Awk реагирует по-разному в зависимости от того, как указан пустой аргумент

Awk реагирует по-разному в зависимости от того, как указан пустой аргумент

Кажется, я наткнулся на что-то, что, вероятно, является ошибкой в ​​awk, но это также может быть ошибкой в ​​моем понимании bash/awk.

Я пытался отладить проблемы, при которых вывод программы Python передавался в awk, и получал следующее исключение независимо от того, что делала команда awk.

close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Как оказалось, awk получал пустой первый аргумент, за которым следовал -f awkfilename.awk. Так что ошибку можно воспроизвести с помощью следующей командной строки:

python -c 'print "hello"'  | awk '' 

Но если я запускаю awk без каких-либо аргументов (что я бы счел эквивалентом вышесказанного), я получаю справку awk, за которой следует то же исключение

 python -c 'print "hh"'  | awk 

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:      GNU long options:
    -f progfile     --file=progfile
    -F fs           --field-separator=fs
    -v var=val      --assign=var=val
    -m[fr] val
    -W compat       --compat
    -W copyleft     --copyleft
    -W copyright        --copyright
    -W dump-variables[=file]    --dump-variables[=file]
    -W exec=file        --exec=file
    -W gen-po       --gen-po
    -W help         --help
    -W lint[=fatal]     --lint[=fatal]
    -W lint-old     --lint-old
    -W non-decimal-data --non-decimal-data
    -W profile[=file]   --profile[=file]
    -W posix        --posix
    -W re-interval      --re-interval
    -W source=program-text  --source=program-text
    -W traditional      --traditional
    -W usage        --usage
    -W use-lc-numeric   --use-lc-numeric
    -W version      --version

To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
    gawk '{ sum += $1 }; END { print sum }' file
    gawk -F: '{ print $1 }' /etc/passwd
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Примечание:сообщение после «Исходное исключение:» на самом деле пустое, это не то, что я пропустил.

Подробности о моей системе

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2

$ awk --version
GNU Awk 3.1.6

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04.3 LTS

$ uname -a
Linux <hostname> 2.6.32-37-generic #81-Ubuntu SMP Fri Dec 2 20:32:42 UTC 2011 x86_64     GNU/Linux

Я был бы рад, если бы кто-то мог предложить какое-то понимание. Конечно, немедленное решение — это очистить аргумент, который передается как пустой в awk, что я и сделал, но это заставило меня заинтересоваться причиной.

Редактирует

На основании комментариев ниже я понял это, awkи awk ''отличие в том, что второй вызов означает, что awk видит количество аргументов, равное 1 (при этом аргумент является пустой строкой) вместо 0.

Чего я до сих пор не понимаю, так это что делает пустая строка в выражении awk.

Например, следующее работает нормально

$ echo "" > /tmp/empty.awk
$ python -c 'print "hello"' | awk -f /tmp/empty.awk
$ echo $?
$ 0

решение1

Здесь происходят две отдельные вещи: сообщения об ошибках (которые на самом деле от python, а не от awk) и сообщение об использовании awk. Чтобы изолировать их, просто перенаправьте stderr из обеих команд:

$ python -c 'print "hello"' 2>pyerr | awk 2>awkerr
$ cat pyerr 
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:
$ cat awkerr 
usage: awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]

AIUI python получает ошибку, потому что программа, в которую передается ее вывод, завершается (и закрывает канал) до того, как python что-то в нее записывает. Вот пример использования sleep 0в качестве программы, которая вообще ничего не делает и, следовательно, завершается очень быстро:

$ python -c 'print "hello"' | sleep 0
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Но если я использую sleep 1, ошибки не возникает, поскольку sleep не закрывает свой конец канала, пока python не закончит писать в него. Ваши результаты могут отличаться в зависимости от точного времени выполнения.

Теперь об awkошибке. Разница в том, что awkбез аргумента это недопустимо, потому что выдолженпредоставить программу; поскольку вы запустили ее неправильно, она пытается быть полезной, печатая сообщение об использовании, чтобы рассказать вам, как ее следует запускать. С другой стороны, awk ''фактически говорит awk запустить пустой скрипт (''), что совершенно допустимо (хотя и не очень полезно), поэтому сообщение об использовании не печатается:

$ awk
usage: awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
$ awk ''

решение2

Вызов программы с нулевыми аргументами (или параметрами) отличается от вызова программы с одним пустым аргументом (или параметром).

Приведем пример кода на языке C:

#include <stdio.h>
int main(int argc, char** argv)
{
    printf("%d\n", argc); // print the number of arguments we've received
    return 0; // exit successfully
}

Запуск этой программы как exampleвыведет 1-, потому что имя программы всегда передается автоматически и нет никаких дополнительных аргументов. Запуск программы как example ''или example SomethingGoesHereвыведет 2, потому что есть имя программы и либо пустой параметр, либо SomethingGoesHere.

Поскольку awk ожидает как минимум 2 параметра (свое имя и что-то еще), вызов awk без каких-либо аргументов приведет к тому, что вы видите выше — выводу справки.

Именно по этой причине вы можете правильно выровнять аргументы. Если у вас есть программа, которая всегда требует 3 аргумента, но вы хотите, чтобы второй был пустым, вы не можете просто опустить его — оболочка не будет знать, что был опущен аргумент, поэтому она передаст 2 аргумента программе, и программа выдаст ошибку.

Связанный контент