我得到了一个测试文件,其内容是:
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
如果FS
长于单个字符,则将其视为正则表达式。 ofFS
只是*
被视为固定字符串,但FS
of-*-
是正则表达式,-*-
相当于-+
(one or more -
)。所以你需要让自己*
被视为一个普通角色。-\*-
并且-[*]-
都可以做到这一点。然而,字符串 forFS
被解析两次- 一次在分配时,一次在拆分时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 答案中的一个关键点是,要在正则表达式中添加反斜杠,FS
您需要编写双反斜杠\\
。这是因为反斜杠在两个不同级别用作转义字符。
字符串中的单个反斜杠将被视为转义后面的字符,因此我们需要转义反斜杠本身,以便在正则表达式中获得单个反斜杠。进而那反斜杠将转义正则表达式中的以下字符。
FS='ax\*'
正如我在评论中所说,和之间没有区别,FS='ax*'
因为\*
被视为*
,但 awk 会打印一条警告。如果您想将文字放入*
中,FS
则需要使用双反斜杠,例如FS='ax\\*'
will split on 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 变量,\\
双引号内的双引号被解析为单反斜杠,然后将生成的正则表达式应用于输入字符串。