在尝试 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
Run Code Online (Sandbox Code Playgroud)
各列由制表符分隔。现在假设我想提取每行中的第一个字段,所以这里是我尝试实现此目的的两种方法:
测试1:
#!/bin/bash
awk -F'\t' '
{print $1;}
' file.txt
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,输出是:
Carl Gauss
Isaac Newton
Leonhard Euler
Donald Knuth
Alan Turing
Albert Einstein
Run Code Online (Sandbox Code Playgroud)
现在我尝试了另一种据说等效的方法来解决这个问题:
测试2:
#!/bin/bash
awk '
BEGIN {
FS='\t';
}
{print $1;}
' file.txt
Run Code Online (Sandbox Code Playgroud)
在这种情况下我得到的输出是
C
I
L
D
A
A
Run Code Online (Sandbox Code Playgroud)
仅打印行的第一个字母。据我所知,这两种方法应该是等效的,但它们产生不同的输出。我也对以不同方式创建的不同文件进行了尝试file.txt
,但每次都得到相同的结果。
对此有何解释?
Ed *_*ton 17
'
在'
类似 Bourne 的 shell(例如bash
."
, 不是'
。只需更改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
Run Code Online (Sandbox Code Playgroud)
这\t
完全是在调用 awk 之前由 shell 解释的,并且shell 中不带引号的字符串与shell 中在该上下文中已经是文字的字符串\t
相同,因此编写:t
t
awk 'BEGIN{ FS='\t' }'
Run Code Online (Sandbox Code Playgroud)
相当于写:
awk 'BEGIN{ FS='t' }'
Run Code Online (Sandbox Code Playgroud)
这相当于写:
awk 'BEGIN{ FS=t }'
Run Code Online (Sandbox Code Playgroud)
在该脚本中 awk 将其视为t
未初始化的变量,因此(出于字段分割的目的)相当于编写:
awk 'BEGIN{ FS="" }'
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为(将在不同的 awk 变体中执行不同的操作)。
您可能会得到一些答案和/或评论,建议您使用 shebang 调用 awk,而不是仅仅从 shell 中调用它,但不要这样做,请参阅/sf/answers/4270192811/了解原因。