Unixツールを使ってみるとアッ、説明できない微妙さに出会いました。これが私が使用するファイルだとしましょう。file.txt
Carl Gauss 1 Germany
Isaac Newton 2 England
Leonhard Euler 3 Switzerland
Donald Knuth 4 America
Alan Turing 5 England
Albert Einstein 6 Germany
列はタブで区切られます。それでは、各行の最初のフィールドを抽出しようとしているとします。これを達成するための2つの方法は次のとおりです。
テスト1:
#!/bin/bash
awk -F'\t' '
{print $1;}
' file.txt
予想通り、出力は次のようになります。
Carl Gauss
Isaac Newton
Leonhard Euler
Donald Knuth
Alan Turing
Albert Einstein
今、私はこの問題を解決するために同等の別の方法を試しました。
テスト2:
#!/bin/bash
awk '
BEGIN {
FS='\t';
}
{print $1;}
' file.txt
この場合、私が得た結果は次のとおりです。
C
I
L
D
A
A
行の最初の文字だけが印刷されます。私が知る限り、これら2つの方法は同じでなければなりませんが、異なる結果を生成します。また、別の方法で生成された別のファイルで試してみましたが、file.txt
毎回同じ結果を得ました。
これの説明は何ですか?
答え1
- Bourneなどのシェル
'
ではこれを行うことはできません。'
bash
- awkスクリプト内の文字列区切り文字は
"
、isではありません'
。
FS='\t'
に変更してくださいFS="\t"
。
現在のコードはawkスクリプトから切り離され、次にFS=
シェルスクリプトで独立して実行され、\t
後でawkスクリプトに再入力されます。
'BEGIN{ FS='\t ' } '
^shell ends ^awk ends ^shell ends ^awk ends
awk begins shell begins awk begins shell begins
これは\t
awkを呼び出す前にシェルによって完全に解釈され、シェルで引用されていない文字列は\t
そのコンテキストのシェルですでにリテラルであるのと同じですt
。t
awk 'BEGIN{ FS='\t' }'
書き込みと同じ:
awk 'BEGIN{ FS='t' }'
これは、次のように書くのと同じです。
awk 'BEGIN{ FS=t }'
そのスクリプトでは、awkはt
それを初期化されていない変数として扱うので(フィールドを分割するために)、次のように書くのと同じです。
awk 'BEGIN{ FS="" }'
これは未定義の動作です(他のawkバリアントで別の操作を実行します)。
シェルでawkを呼び出す代わりに、shebangを使用してawkを呼び出すように回答や説明を取得できますが、そうしないでください。https://stackoverflow.com/a/61002754/1745001なぜ。