Unix - awk неожиданное поведение - PullRequest
1 голос
/ 27 декабря 2011

У меня есть следующий код в bash-файле с именем 'findError.sh':

#!/bin/bash
filename="$1"
formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count

Затем я запускаю его в командной строке следующим образом: sh findError.sh test.dat

Но это дает мне другой счет, чем выполнение команды, которая была отражена ??Как это возможно?

т.е. команда $, возвращаемая в ответ:

awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l

Но счет $, возвращаемый в ответ:

3

Однакоесли я просто запусту эту строку ниже в командной строке (не через скрипт) - результат будет 0:

awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l

Пример входного файла (test.dat):

sid|storeNo|latitude|longitude
2|1|-28.03720000
9|2
10
jgn352|1|-28.03ERROR720000
9|2|fdERRORkjhn422-405
0000543210|gfERRORdjk39

Примечания: Использование SunOS с версией bash 4.0.17

Ответы [ 2 ]

4 голосов
/ 27 декабря 2011

Вы слишком осторожны со своими кавычками вокруг разделителя формата.

Когда вы набираете:

awk -F"|" ...

Программа (awk) видит -F| в качестве первогоаргумент;оболочка удаляет двойные кавычки.

Когда у вас есть:

formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator ...`

Вы сохранили двойные кавычки в $formatindicator, и поэтому awk видит -F"|" в качестве разделителя, ииспользует двойную кавычку в качестве разделителя.

Использование:

formatindicator="|"
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F"$formatindicator" ...`

Разница в том, что оболочка удаляет кавычки -F"$formatindicator", но не делает этого, когда $formatindicator содержитдвойные кавычки.

(Примечание: отредактировано для сохранения обратных кавычек вместо обозначения $(...), которое является (а) предпочтительным и (b) использовалось в первой версии этого ответа. $(...)нотация не была распознана SunOS /bin/sh, которая, как мне кажется, использовалась для выполнения сценария. И bash, и ksh распознают нотацию $(...), но базовая оболочка Bourne, /bin/sh, в Solaris10 (SunOS 5.10) и более ранние (я не брал руки на Solaris 11) не распознает $(...).)

Я отмечаю, что любой из perl, awk или grep может бытьиспользуется для самостоятельного поиска количества строк ошибок, поэтому триплет awkк perl по трубопроводу к wc не очень эффективно.

awk -F"|" '$1 ~ /ERROR/ { count++ } END { print count }' $filename

grep -c ERROR $filename                # simple
grep -c '^[^|]*ERROR[^|]*|' $filename  # accurate

perl -anF"|" -e '$count++ if $F[0] =~ m/ERROR/; END { print "$count\n"; }' $filename

Это Perl, поэтому TMTOWTDI ;сделайте свой выбор ...


Боковое обсуждение

В комментариях нас беспокоит то, как интерпретируются различные части сценария.

formatindicator="|"
formatarg="\$1"

count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `

Давайте упростим это до (используя часть моего основного ответа):

count=`awk -F"$formatindicator" '{print $formatarg}' $filename`

Намерение состоит в том, чтобы указать разделитель в командной строке (что происходит успешно) с помощью опции -F.Я ожидаю, что проблема в том, «почему $formatarg раскрывается внутри одинарных кавычек?».И ответ «Есть ли это?».Думаю, нет.Итак, что происходит, awk видит сценарий {print $formatarg}.Поскольку formatarg не присваивается какое-либо значение, оно эквивалентно 0, поэтому сценарий выводит $0, то есть всю строку ввода.Perl очень рад повторить строку, если она соответствует ERROR в любом месте строки, и wc не заботится о том, что находится в строках, поэтому результат примерно соответствует ожидаемому.Единственное время, в котором может быть несоответствие, - это когда строка из $filename содержит ОШИБКУ, отличную от первого поля, разделенного каналом.Это будет считаться сценарием, где это не должно быть.

1 голос
/ 27 декабря 2011

Проблема заключается в использовании внешних переменных в awk.Если вы хотите использовать внешние переменные в awk, тогда определите переменную в однострочнике awk, используя опцию -v и variable name, и присвойте ей external variable.Итак

Строка -

count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `

должна быть -

count=`awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `

Обновление:

Как указано в комментариях$formatarg содержит значение $1.Вам нужно просто сохранить 1 и передать его как -

count=`awk -v fi=$formatindicator -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l

[jaypal:~/Temp] echo $formatindicator
|
[jaypal:~/Temp] echo $formatarg
1
[jaypal:~/Temp] awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' data.file
sid
2
9
10
jgn352
9
0000543210

Сценарий:

#!/bin/bash
filename="$1"
formatindicator="|"
echo "$formatindicator"
formatarg="1"
echo "$formatarg"
count=`awk -v fa="$formatarg" -v fi="$formatindicator" 'BEGIN{FS=fi}{print $fa}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...