Кажется, я наткнулся на что-то, что, вероятно, является ошибкой в 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 аргумента программе, и программа выдаст ошибку.