awkで変更するフィールド区切り文字が '\ t'の場合、-Fフラグを使用すると機能しますが、FS変数を使用してフィールド区切り文字を明示的に変更すると機能しないのはなぜですか?

awkで変更するフィールド区切り文字が '\ t'の場合、-Fフラグを使用すると機能しますが、FS変数を使用してフィールド区切り文字を明示的に変更すると機能しないのはなぜですか?

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

  1. Bourneなどのシェル'ではこれを行うことはできません。'bash
  2. 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
                 

これは\tawkを呼び出す前にシェルによって完全に解釈され、シェルで引用されていない文字列は\tそのコンテキストのシェルですでにリテラルであるのと同じですtt

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なぜ。

関連情報