なぜawkはFS="*"を理解できますが、FS="-*-"は理解できないのですか?

なぜawkはFS="*"を理解できますが、FS="-*-"は理解できないのですか?

内容は次のテストファイルを受け取りました。

a -*- b

使用しましたがawk 'BEGIN {FS="*"} {print $2}' test印刷されます。

- b

正しい!しかし、 を使用すると、次のようなawk 'BEGIN {FS="-*-"} {print $2}' test結果が得られます。

*

私はFS正規表現がサポートされていることを知っているので、以前にそれを追加し、\まだこれを実行して*awk 'BEGIN {FS="-\*-"} {print $2}' test のようになりました。

*

幸い、私は半年前にブログを始めました。awk 'BEGIN {FS="-[*]-"} {print $2}' testこの場合に使用する必要があると言われています。したがって、私は以下を得る:

 b

また正解!

*しかし、なぜFSがそれを理解できるのか、理解できないのか-*--\*-そしてついに理解できるのか、本当に混乱しています-[*]-

メカニズムは何ですか?

答え1

1文字より長い場合はFS正規表現として扱われます。 ofはFS単に*固定文字列として扱われますが、FSofは(one or more)と同等の-*-正規表現です。したがって、自分を普通の人物として見ることを許可する必要があります。そして両方ともこれを行うことができます。ただし、文字列は解析されます。-*--+-*-\*--[*]-FS二重- 割り当て時に一度、分割時に一度FS。そのため、エスケープ文字\もエスケープする必要があります。\

$ awk -F '-\\*-' '{print $2,FS}' test.txt
 b -\*-
$ awk -F '-\*-' '{print $2,FS}' test.txt
awk: warning: escape sequence `\*' treated as plain `*'
* -*-

答え2

muruの答えの重要な点の1つは、正規表現にバックスラッシュを追加するには二重バックFSスラッシュを作成する必要があることです\\。これは、バックスラッシュが2つの異なるレベルでエスケープ文字として使用されるためです。

文字列の単一のバックスラッシュは次の文字をエスケープすることで処理されるため、正規表現で単一のバックスラッシュを取得するにはバックスラッシュ自体をエスケープする必要があります。それからそれバックスラッシュは正規表現で次の文字をエスケープします。

FS='ax\*'コメントで述べたように、asとasの間に違いはありませんが、awkFS='ax*'は警告を出力します。テキストを入力するには、will Split onのように二重バックスラッシュを使用する必要があります。\***FSFS='ax\\*'ax*

おそらく、いくつかの例でこれをより明確に理解することができます。

#!/usr/bin/env bash

s='123abcd
123axbcd
123axxbcd
123ax*bcd
123ax**bcd'

printf "%s\n\n" "$s"

awk -F 'ax*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo


awk -F 'ax\*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax\*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo


awk -F 'ax\\*' 'BEGIN{printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

awk 'BEGIN{FS="ax\\*"; printf "FS=[%s]\n", FS};{printf "[%s] [%s]\n", $1, $2}' <<< "$s"
echo

出力

123abcd
123axbcd
123axxbcd
123ax*bcd
123ax**bcd

FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

awk: warning: escape sequence `\*' treated as plain `*'
FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

awk: warning: escape sequence `\*' treated as plain `*'
FS=[ax*]
[123] [bcd]
[123] [bcd]
[123] [bcd]
[123] [*bcd]
[123] [**bcd]

FS=[ax\*]
[123abcd] []
[123axbcd] []
[123axxbcd] []
[123] [bcd]
[123] [*bcd]

FS=[ax\*]
[123abcd] []
[123axbcd] []
[123axxbcd] []
[123] [bcd]
[123] [*bcd]

答え3

区切り文字の内側で"バックスラッシュをエスケープする必要があります。

$ echo 'a -*- b' | awk 'BEGIN {FS="-\\*-"} {print $2}'
 b

正規表現はFS変数に渡されるため、\\二重引用符内の二重引用符は単一のバックスラッシュで解析され、結果の正規表現は入力文字列に適用されます。

関連情報