ファイル名に=が含まれていると、awkが停止して待つのはなぜですか。この問題を解決する方法は?

ファイル名に=が含まれていると、awkが停止して待つのはなぜですか。この問題を解決する方法は?
awk 'processing_script_here' my=file.txt

無限に止まって待つ...
ここで何が起こっているのか、そしてどのように機能しますか?

答え1

〜のようにクリスが言う、フォームの引数は、入力ファイル名ではなく変数の割り当て(ステートメントの前に実行された(最新の)変数の割り当てとは異なり、引数が処理されたvariablename=anythingときに実行されます)として扱われます。-v var=valueBEGIN

これは次のような場合に便利です。

awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2

FSそこからファイルごとに異なるものを指定できますRS。また、一般的に次の用途に使用されます。

awk '!file1_processed{a[$0]; next}; {...}' file1 file1_processed=1 file2

より安全なバージョンは次のとおりです。

awk 'NR==FNR{a[$0]; next}; {...}' file1 file2

file1(空であれば何の効果もありません)

=ただし、ファイル名に文字が含まれていると問題が発生します。

=これは、最初の残りの部分が有効な変数名である場合にのみ問題になりますawk

では、有効な変数名の設定はawkからより厳密ですsh

POSIXでは、次のようにする必要があります。

[_a-zA-Z][_a-zA-Z0-9]*

移植可能な文字セットの文字のみを使用してください。ただし、/usr/xpg4/bin/awkSolaris 11は少なくともこの点で互換性がなく、a-zA-Zだけでなく、ロケール内のすべてのアルファベット文字を変数名に使用できます。

x+y=fooしたがって、=baror などの引数は、./foo=barまだ割り当てではない入力ファイル名として扱われます。最初の引数の残りの部分は=有効な変数名ではないからです。実装とロケールStéphane=Chazelas.txtに応じて、「may」や「not」などのパラメータです。awk

そのため、awkを使用するときは、次のものを使用することをお勧めします。

awk '...' ./*.txt

変える

awk '...' *.txt

たとえば、ファイル名に文字がtxt含まれていないことを保証できない場合は、問題を回避できます=

また、以下を-vfoo=bar.txt使用する場合は、同様のパラメーターをオプションと見なすことができます。

awk -f file.awk -vfoo=bar.txt

(1.28.0より前のbusyboxバージョンにも適用可能ですawk '{code}' -vfoo=bar.txtawk対応するエラーレポート)。

繰り返しますが、./*.txtこの問題は次の方法で解決できます(プレフィックスを使用すると、他の意味で理解されている./ファイルを呼び出すときにも役立ちます)。-awk標準入力代わりに)。

これは理由

#! /usr/bin/awk -f

Shebangsは実際には動作しません。これらの問題はvar=value次のように解決できますが、固定明細の値ARGV(./プレフィックスを追加) BEGIN:

#! /usr/bin/awk -f
BEGIN {
  for (i = 1; i < ARGC; i++)
    if (ARGV[i] ~ /^[_[:alpha:]][_[:alnum:]]*=/)
      ARGV[i] = "./" ARGV[i]
}
# rest of awk script

これはオプションには役立ちません。なぜなら、そのオプションはスクリプトawkではなくawkスクリプトによって表示されるからです。

この接頭辞を使用するときに./発生する可能性のある外観上の問題の1つはで終わることです。ただし、不要な場合はFILENAMEいつでもこのプレフィックスを使用して削除できます。substr(FILENAME, 3)

GNU実装はawkオプションを介してこれらすべての問題を解決します-E

その後、-Egawkはスクリプトパスawk-まだstdinを意味します)と入力ファイルパスのリストのみを期待します(-特別な処理もしません)。

これは以下のために設計されています:

#! /usr/bin/gawk -E

引数リストが常に入力ファイルであるshebangs(ARGVステートメント内でリストを自由に編集できることに注意してくださいBEGIN)。

次のように使用することもできます。

gawk -e '...awk code here...' -E /dev/null *.txt

後続のスクリプトに文字が含まれていても、常に入力ファイルとして処理されるように空の-Eスクリプト()を使用します。/dev/null*.txt=

答え2

ほとんどのawkバージョンで実行されるプログラムの後に続くパラメータは次のとおりです。

  1. 1つの文書
  2. テーブルの割り当てx=y

ファイル名はケース#2として解釈されるため、awkはまだstdinが何かを読むのを待っています(ファイル名が渡されたことを検出できないため)。

移植可能にも、この動作はPOSIXで文書化:

次の2種類のパラメータを混在させることができます。

  • ファイル:プログラムに設定されているパターンと一致するように読み取る必要がある入力を含むファイルのパス名。ファイルオペランドが指定されていない場合、またはファイルオペランドが「-」の場合は、標準入力を使用する必要があります。
  • 割り当て:移植可能文字セットの下線またはアルファベット文字で始まるオペランド(IEEE Std 1003.1-2001、セクション6.1移植可能文字セットのデフォルト定義ボリュームの表を参照)、その後に一連の下線、数字が続きます。および「=」文字が続く移植可能な文字セットの文字は、パス名ではなく変数の割り当てを指定する必要があります。

したがって、いくつかの移植可能なオプションがあります(#1はおそらく最も邪魔になりません)。

  1. 「移植可能な文字セットの下線またはアルファベット文字」ではないawk ... ./my=fileため、これを回避するを使用してください。.
  2. 標準入力にファイルを配置するために使用されますawk ... < my=file。ただし、これは複数のファイルでは正しく機能しません。
  3. 一時的にファイルへのハードリンクを作成して使用してください。このようなことを行い、ln my=file my_file正常my_fileに使用できます。コピーは行われず、両方のファイルは同じデータとinodeメタデータでバックアップされます。使用後は、そのアノードの参照数がまだゼロより大きいため、生成されたリンクを削除しても安全です。

答え3

見積もり愚かな文書(追加の強調事項を参照):

コマンドラインの他の引数は通常、指定された順序で処理される入力ファイルとして扱われます。しかし、var = value型のパラメータはvar変数に値を割り当て、ファイルをまったく指定しません。

コマンドが停止して待つのはなぜですか?形であるからawk 'processing_script_here' my=file.txt 指定されたファイルがありません。上記の定義では、 -my=file.txtは変数割り当てとして解釈され、ファイルが定義されていない場合はstdinを読み取ります(これらのコマンドのawkがシステムコールを待っていることもawk明らかです。straceread(0,'...)

この内容はにも記録されています。POSIX awkの仕様、オペランドセクション、仕事その一部)

awk '{print foo}' foo=bar /etc/passwd/ etc / passwdの各行は値を印刷するため、変数の割り当ては明らかです。ただし、パスまたはフルパスをfoo指定すると機能します。./foo=bar

実行straceしてawk '1' foo=bar確認すると、cat foo=barこれはawk固有の問題であることがわかり、execveはファイル名を渡された引数として表示するため、この場合、シェルは環境変数の割り当てとは何の関係もありません。

awk '...script...' foo=barさらに、環境変数の割り当てはコマンドの前に適用する必要があるため、シェルは環境変数を生成しません。バラよりPOSIX シェル構文規則, ポイント 7. さらに、これは次のように確認できます。awk '{print ENVIRON["foo"]}' foo=bar /etc/passwd

関連情報