我似乎偶然发现了一些东西,可能是 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 个参数,但您希望第二个参数为空,则您不能简单地省略它 - shell 不知道有一个参数被省略,因此它会将 2 个参数传递给程序,程序将出现错误。