打印具有特定输出字段分隔符的特定列

Por*_*ine 3 awk

cat A.tsv
1,a,d
2,b,e
3,c,f
Run Code Online (Sandbox Code Playgroud)
cat A.tsv
1,a,d
2,b,e
3,c,f
Run Code Online (Sandbox Code Playgroud)
  • 我预计以下 4 个命令会给出与上述相同的结果:
$ awk -F ',' -v OFS="," '{print $2, $3}' A.tsv 
a,d
b,e
c,f
Run Code Online (Sandbox Code Playgroud)
$ awk 'FS=","; OFS=","; {print $2, $3}' A.tsv 
1,a,d
1,a,d
,
2,b,e
2,b,e
b,e
3,c,f
3,c,f
c,f
Run Code Online (Sandbox Code Playgroud)
$ awk -F ',' 'OFS=","; {print $2, $3}' A.tsv 
1,a,d
a,d
2,b,e
b,e
3,c,f
c,f
Run Code Online (Sandbox Code Playgroud)
$ awk -v OFS="," 'FS=","; {print $2, $3}' A.tsv 
1,a,d
,
2,b,e
b,e
3,c,f
c,f
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么最后 4 个命令的结果与第一个不同吗?

请参阅:shell 脚本中 awk -FS 和 awk -f 之间的区别 - 爱编程的大狗

ste*_*ver 12

awk 程序由pattern {action}成对组成,{action}如果pattern评估为 TRUE则执行。如果pattern省略,则默认为 TRUE,而如果{action}省略,则默认操作为{print}

awk 'FS=","; OFS=","; {print $2, $3}' A.tsv
Run Code Online (Sandbox Code Playgroud)

你有:

  1. 图案FS=",",其受让人,为的值FS,并作为副作用评估TRUE,触发默认动作{print}

  2. 模式OFS=","同样分配,OFS,评估为 TRUE 并再次触发默认{print}操作

  3. {print $2,$3}没有模式的动作,因此假定默认为 TRUE 并触发动作。但是直到第一条记录已经被处理后才FS设置为,,所以$2$3都是空的(因为 awk 使用默认空格FS来解析第一条记录,将整个记录分配给$1)。在后续记录上,它打印预期的逗号分隔值。

您可能打算在记录处理开始之前分配FS=","OFS=","操作 - 这是BEGIN块的功能:

awk 'BEGIN{FS=","; OFS=","} {print $2, $3}' A.tsv
Run Code Online (Sandbox Code Playgroud)

或者

awk -F ',' 'BEGIN{OFS=FS} {print $2, $3}' A.tsv
Run Code Online (Sandbox Code Playgroud)

或者,您可以在文件名参数之前将变量赋值作为参数传递(如果您正在处理多个文件并希望为每个文件设置不同的字段分隔符,这有时很有用)

awk '{print $2, $3}' FS="," OFS="," A.tsv
Run Code Online (Sandbox Code Playgroud)

  • 我知道所有 AWK 文档都说“模式”,但这都是错误的。awk 由 `<condition> { <action> }` 语句组成,而不是 `<pattern> { <action> }` 语句。后者在第一个 awk 版本中具有一定意义,该版本实际上仅进行模式匹配,但对于 1980 年代以来的任何 awk 版本而言,它都具有可悲的误导性和过时性。`foo == 17` 是什么模式?不是,是有条件。“TRUE”以什么方式成为模式?不是,是有条件。当我们在 C 中编写 `if (X) <action>` 时,我们不会说 X 是一个模式,它是一个条件。等等... (2认同)