为什么 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

如果FS长于单个字符,则将其视为正则表达式。 ofFS只是*被视为固定字符串,但FSof-*-是正则表达式,-*-相当于-+(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 变量,\\双引号内的双引号被解析为单反斜杠,然后将生成的正则表达式应用于输入字符串。

相关内容