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 に空として渡される引数をサニタイズすることですが、これは私が実行したことです。しかし、これにより原因が気になりました。

編集

以下のコメントに基づいて、 と は、2 回目の呼び出しでは awk が引数の数を 0 ではなく 1 (引数は空の文字列) と見なすという点で異なるとawk理解しています。awk ''

私がまだ理解していないのは、awk 式としての空の文字列が何を行うかということです。

例えば、次のものは問題なく動作します

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

答え1

ここでは、エラー メッセージ (実際には awk ではなく python からのメッセージ) と awk の使用法メッセージという 2 つの別々の処理が行われています。これらを分離するには、両方のコマンドから 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、Python が書き込みを完了するまで sleep はパイプの終端を閉じないため、エラーは発生しません。関係する正確なタイミングに応じて、結果が異なる場合があります。

さて、awkエラーについて。違いは、awk引数なしでは有効ではないということです。しなければならないプログラムを提供します。不適切に実行されたため、どのように実行すべきかを示す使用方法メッセージを出力して役立てようとします。一方、はawk ''実際には awk に空のスクリプト ('') を実行するように指示しており、これは完全に有効ですが (あまり役に立ちません)、使用方法メッセージは出力されません。

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

答え2

引数 (またはパラメータ) が 0 個のプログラムを呼び出すことは、空の引数 (またはパラメータ) が 1 個のプログラムを呼び出すこととは異なります。

例として 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出力されます。プログラムをまたはとして実行すると、プログラム名と、空のパラメータまたは があるため、 が出力されます。1example ''example SomethingGoesHere2SomethingGoesHere

awk は少なくとも 2 つのパラメータ (awk の名前と他のパラメータ) を必要とするため、引数なしで awk を単独で呼び出すと、上記のような結果になり、ヘルプが印刷されます。

このため、引数を適切に整列させることができます。常に 3 つの引数を必要とするプログラムがあり、2 番目の引数を空白にしたい場合、単純に省略することはできません。シェルは省略された引数があることを認識できないため、2 つの引数をプログラムに渡し、プログラムにエラーが発生します。

関連情報