我似乎偶然發現了一些東西,這可能是 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 個參數到程式中,程序就會出錯。