在尝试 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
- 您不能
'
在'
类似 Bourne 的 shell(例如bash
. - 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为什么。