为什么在 awk 中要更改的字段分隔符为 '\t' 时,使用 -F 标志可以工作,而使用 FS 变量显式更改字段分隔符却不起作用?

为什么在 awk 中要更改的字段分隔符为 '\t' 时,使用 -F 标志可以工作,而使用 FS 变量显式更改字段分隔符却不起作用?

在尝试 Unix 工具时awk,我遇到了这个我无法解释的微妙之处。假设这是我正在使用的文件file.txt

Carl Gauss      1       Germany
Isaac Newton    2       England
Leonhard Euler  3       Switzerland
Donald Knuth    4       America
Alan Turing     5       England
Albert Einstein 6       Germany

各列由制表符分隔。现在假设我想提取每行中的第一个字段,所以这里是我尝试实现此目的的两种方法:

测试1:

#!/bin/bash

awk -F'\t' '
{print $1;}
' file.txt

正如预期的那样,输出是:

Carl Gauss
Isaac Newton
Leonhard Euler
Donald Knuth
Alan Turing
Albert Einstein

现在我尝试了另一种据说等效的方法来解决这个问题:

测试2:

#!/bin/bash

awk '
BEGIN {
        FS='\t';
}
{print $1;}
' file.txt

在这种情况下我得到的输出是

C
I
L
D
A
A

仅打印行的第一个字母。据我所知,这两种方法应该是等效的,但它们产生不同的输出。我file.txt也对以不同方式创建的不同文件进行了尝试,但每次都得到相同的结果。

对此有何解释?

答案1

  1. 您不能''类似 Bourne 的 shell(例如bash.
  2. awk 脚本内的字符串分隔符是", 不是'

只需更改FS='\t'FS="\t".

您当前的代码在 后脱离 awk 脚本FS=,然后在 shell 脚本中独立运行\t,然后在其后重新输入 awk 脚本:

'BEGIN{     FS='\t              ' }             '
^shell ends    ^awk ends        ^shell ends     ^awk ends
 awk begins     shell begins     awk begins      shell begins
                 

\t完全是由您的 shell 在调用 awk 之前解释的,并且在 shell 中的不带引号的字符串中与在该上下文中的 shell 中已经是文字\t相同,t因此编写:t

awk 'BEGIN{ FS='\t' }'

相当于写:

awk 'BEGIN{ FS='t' }'

这相当于写:

awk 'BEGIN{ FS=t }'

在该脚本中 awk 将其t视为未初始化的变量,因此(出于字段分割的目的)相当于编写:

awk 'BEGIN{ FS="" }'

这是未定义的行为(将在不同的 awk 变体中执行不同的操作)。

您可能会得到一些答案和/或评论,建议您使用 shebang 调用 awk,而不是仅仅从 shell 中调用它,但不要这样做,请参阅https://stackoverflow.com/a/61002754/1745001为什么。

相关内容