awk - 理解 FS 是如何工作的

awk - understanding how FS works

我知道默认的 FS= " ",那为什么我在以下 awk 命令中看到变化。请帮助我理解。

>echo "   ABC DEF   XYZ  \n   abc       def,ghi   xyz   \n" | awk '{printf("nf: %s 1:%s line: %s\n", NF, , [=10=])}'
nf: 3 1:ABC line:    ABC DEF   XYZ  
nf: 3 1:abc line:    abc       def,ghi   xyz   
nf: 0 1: line: 
                                                                                                                                                               
>echo "   ABC DEF   XYZ  \n   abc       def,ghi   xyz   \n" | awk -F" " '{printf("nf: %s 1:%s line: %s\n", NF, , [=10=])}'
nf: 3 1:ABC line:    ABC DEF   XYZ  
nf: 3 1:abc line:    abc       def,ghi   xyz   
nf: 0 1: line: 
                                                                                                                                                               
>echo "   ABC DEF   XYZ  \n   abc       def,ghi   xyz   \n" | awk -F"[ ]" '{printf("nf: %s 1:%s line: %s\n", NF, , [=10=])}'
nf: 10 1: line:    ABC DEF   XYZ  
nf: 17 1: line:    abc       def,ghi   xyz   
nf: 0 1: line: 
                                                                                                                                                               
>echo "   ABC DEF   XYZ  \n   abc       def,ghi   xyz   \n" | awk -F"[ ]*" '{printf("nf: %s 1:%s line: %s\n", NF, , [=10=])}'
nf: 5 1: line:    ABC DEF   XYZ  
nf: 5 1: line:    abc       def,ghi   xyz   
nf: 0 1: line: 
                                         

我想了解为什么在第一个和第二个示例中没有空标记,但在第三个和第四个示例中存在。

更新:为了进一步解释我的疑问,awk 与默认 FS 和自定义 FS 的行为不一致。请参阅以下示例。

>printf "ab  cd\nef gh\n" | awk -F" " '{ printf("nf: %d\t", NF); for (i=1;i<=NF;i++) printf("%02d:%s\t", i, $i); print ""}'
nf: 2   01:ab   02:cd   
nf: 2   01:ef   02:gh

>printf "ab::cd\nef:gh\n" | awk -F":" '{ printf("nf: %d\t", NF); for (i=1;i<=NF;i++) printf("%02d:%s\t", i, $i); print ""}'
nf: 3   01:ab   02:     03:cd   
nf: 2   01:ef   02:gh

默认情况下 awk 使用单个 space 作为默认值 FS。这是一个特例,也是唯一的特例。两个或多个 space 不被解释为多个字段,而是被解释为单个分隔符。使用 任何其他字符 会导致该字符的每次出现都被解释为分隔符。所以使用 ':' 会将 ":::my" 解释为四个字段。 (emptyemptyempty"my")参见:GNU Awk User's Guide - 4.5.1 Whitespace Normally Separates Fields.

当您使用 正则表达式 时,每个出现的 FS 字符(即使是 space)都被视为单独的字段分隔符。参见 GNU Awk User's Guide - 4.5.2 Using Regular Expressions to Separate Fields

要将每个字符作为一个单独的字段进行检查,您只需将 FS 设置为 empty-string(空),在命令行中使用 -F"" 或设置 FS = "".

在您使用正则表达式 -F"[ ]" 的示例中,每个 space 都被视为一个单独的字段分隔符。 FS 是正则表达式而不是默认大小写。这是一个正则表达式,其中单个字符恰好是 space.

随着 * (zero-or-more) 次的重复出现,FS 有点模棱两可。它可以不匹配任何内容 (null),也可以匹配一行中尽可能多的 space。 (这就是为什么它匹配第一个字符然后匹配多个 spaces)我不建议以这种方式弄乱 spaces 和 FS

awk 理解 扩展正则表达式 (ERE) 语法,因此您可以对 [=67 使用 '+' 重复说明符=] 个字符。

GNU Awk User's Guide 放在手边。它是 gawk 以及 awk 其他风格的一个很好的参考。在指南中如果某些东西是gawk独有的,它会在指南中用'#'标记来告诉你。它通常解释(有时在脚注中)gawk 行为与 POSIX、awkmawk 等有何不同。