web-dev-qa-db-ja.com

シェルによる解釈を防ぐために、ブラケット "] ["に二重エスケープ "\\"が必要なのはなぜですか?

「bash」シェルを使用して、ファイルのレコードを以下の「awk」コマンドの下で実行します。ファイルのレコードは、以下のサンプルレコードのように、ブラケット、コロン、括弧などの異なる文字

...(field#13[field#14:]]:filed#18[filed#19)[...

しかし、単一のエスケープ「\」で「] [」をエスケープすると、awkコマンドが失敗し、期待される結果を得るためだけに「\\」ブラケットを二重エスケープする必要があります。 「シェルそれは同じです)?

awk -F"[\\[\\]:)(]" '{print $18}' inFile
filed#18

また、これに注意してください、私はすべての場合、以下のように二重エスケープ「\\」でそれらをエスケープできることを知っていますが、ブラケットのためにこれが必須である理由を知りたいですか?

awk -F"[\\[\\]\\:\\)\\(]" '{print $18}' inFile
filed#18

signleエスケープを使用しても警告が表示されます(ブラケットを除く)が、それでもコマンドの実行と結果の受信はありがとう

awk -F '[\\[\\]\:\)\(]' '{print $18}' inFile
awk: warning: escape sequence `\:' treated as plain `:'
awk: warning: escape sequence `\)' treated as plain `)'
awk: warning: escape sequence `\(' treated as plain `('
filed#18
4
αғsнιη

ここでは、複数のレベルの引用/エスケープが行われています。最初に、FS正規表現(-F "[\\[\\]\:\)\(]")を二重引用符で囲みます。それが警告を与えているものです:

$ awk -F"[\\[\\]:)(]" '{print $2}' file 
awk: warning: escape sequence `\[' treated as plain `['
awk: warning: escape sequence `\]' treated as plain `]'
awk: fatal: :, [., or [=: /[[]:)(]/

単一引用符は機能しますが:

$ awk -F'[\\[\\]:)(]' '{print $2}' file 
field#13

これは、二重引用符で囲まれたものが最初にシェルによって展開されるためです。そのため、シェルは最初に\\[\[に展開してから、awkに渡します。 set -xでこれが起こっているのを見ることができます:

$ set -x
$ awk -F"[\\[\\]:)(]" '{print $2}' file 
+ awk '-F[\[\]:)(]' '{print $2}' file

上記のように、シェルは最初のエスケープを食べました。したがって、ここでは"を使用しないでください。

次の問題は、awk自体がエスケープを2回解釈することです。 -F\t\rなどの特別なエスケープを受け入れることができるため、最初に\[を単一のエスケープ文字として読み取ろうとします。 \[[と同じであるため(\nは改行なので、nとは異なり、\nとは異なります)、警告メッセージを表示し、\[[として処理したことを説明します。

したがって、\自体をエスケープするには最初のエスケープが必要で、[をエスケープするには2番目のエスケープが必要です。つまり、\\[では、最初の\が2番目の\をエスケープしているため、awkが最終的に受け取るのは\[です。

このようなことを考えれば理解しやすいかもしれません:

$ echo -e 'a\tb'
a   b                  ## prints a tab character
$ echo -e 'a\\tb'
a\tb                   ## prints a literal \t
$ echo -e "a\\tb"      
a   b                  ## prints a tab because of the double quotes
$ echo -e "a\\\tb"     
a\tb                   ## 3ple escaping! Prints a literal `\t` again.

上記の最後の例が最もわかりやすいです。エコーされる文字列は二重引用符で囲まれているため、最初に(1つの\を食べる)シェルによって展開され、次にecho -e(別の\を食べる)によって展開され、最終的にリテラル\tとして出力されます。

2
terdon