我该如何在AWK中使用":"作为字段分隔符?

366
给定以下命令:
echo "1: " | awk '/1/ -F ":" {print $1}'

为什么AWK会输出:
1:

?


awk '/1/ -F ":" {print $1}' 无论输入行中是否实际存在 "1",它都将始终打印出 $1 或空行。 - RARE Kpop Manifesto
9个回答

570

-F是命令行参数,而不是AWK语法。尝试使用:

echo '1: ' | awk -F  ':' '/1/ {print $1}'

54
无知的问题在这里:/1/ 部分是告诉 awk 仅处理包含数字 1 的行(或更准确地说,记录),对吗? - rantsh
13
Awk语法的格式是(模式){动作}。如果模式(通常是一个条件语句)为_true_,则执行动作。如果模式不可用,则默认为_true_。在这里,模式/1/,它表示在当前记录$0中是否匹配正则表达式1 - kvantour
1
顺便提一下,如果你的分隔符是逗号,你需要在awk命令中添加“-v OFS =“,以保持输出。 - Altair7852
你如何在 .awk 脚本中指示这一点? - Joan Serrano
@JoanSerrano 看一下下面 Dennis 的答案,它正好做到了这一点。 - vmallet

81

如果您想以编程方式完成该操作,可以使用FS变量:

echo "1: " | awk 'BEGIN { FS=":" } /1/ { print $1 }'

请注意,如果你在主循环而不是 BEGIN 循环中更改它,则它将对下一行读入产生影响,因为当前行已经被分割。


71

您有多种方式来设置分隔符:

awk -F: '{print $1}'

awk -v FS=: '{print $1}'

awk '{print $1}' FS=:

awk 'BEGIN{FS=":"} {print $1}'

它们都是等效的,并将在给定样本输入"1:2:3"时返回1

$ awk -F: '{print $1}' <<< "1:2:3"
1
$ awk -v FS=: '{print $1}' <<< "1:2:3"
1
$ awk '{print $1}' FS=: <<< "1:2:3"
1
$ awk 'BEGIN{FS=":"} {print $1}' <<< "1:2:3"
1

哪种方式更好?我认为最终的例子使用 BEGIN 语句会更正确(与整个 awk 语法保持一致)。 - user4104817
1
@randomware 所有的都可以。如果我使用文件来存储整个内容,我倾向于使用 BEGIN,而对于一行命令,-F 很方便。 - fedorqui
1
必须说第三种情况与所有其他情况之间存在着微妙的差别。例如:awk 'BEGIN{print split("foo:bar",a)}' FS=":" fileawk 'BEGIN{FS=":"; print split("foo:bar",a)}' file - kvantour
@kvantour 很好的观点。我刚在为什么在表达式之前或之后设置字段分隔符会有不同考虑?上询问了一下。 - fedorqui
1
谢谢!我最喜欢清晰的例子来学习。 - Merlin
@kvantour:虽然你的说法非常正确,但我个人总是在split()中明确设置分隔符,特别是在函数内部,而不是让它完全取决于当前的FS(除非我正在拆分一个空字符串以清除数组,在这种情况下,这根本不重要)。 - RARE Kpop Manifesto

12

您也可以使用正则表达式作为字段分隔符。以下代码将使用正则表达式将数字“10”设置为分隔符并打印“bar”。

echo "foo 10 bar" | awk -F'[0-9][0-9]' '{print $2}'

11

-F是传递给awk本身的参数:

$echo "1: " | awk -F":" '/1/ {print $1}'
1

4
不需要引用冒号。 - ceving

5

或者你可以使用:

echo "1: " | awk  '/1/{print $1-":"}' 

这是一个非常有趣的公式。


1
/1/ 是什么意思? - user4104817
找出一个模式。在这种情况下是“1”。 - José Dias
为什么这是一个非常有趣的方程式? - Peter Mortensen
我认为这个技巧只能在“:”前面的值是数字时才有效。echo "ab1: " | awk '/1/{print $1-":"}' 失败,输出“0”。 - RARE Kpop Manifesto

4
不需要写这么多,只需在AWK命令中使用-F选项输入所需的字段分隔符和要打印的列号,即可根据您提供的字段分隔符打印所需列。
echo "1: " | awk -F: '{print $1}'
1

echo "1#2" | awk -F# '{print $1}'
1

4

AWK是一种文本解释器,它会按行处理整个文档,对于每一行又会逐个字段处理。因此$1、$2...$n代表每行的字段($1代表第一个字段,$2代表第二个字段以此类推)。

您可以使用命令行下的“-F”开关或在两个括号中使用“FS=…”来定义字段分隔符。

现在考虑Jürgen的答案

echo "1: " | awk -F  ":" '/1/ {print $1}'

在这个场景中,冒号 ":" 用于设置字段的边界,因此我们有两个字段 $1,它是 "1",$2 是一个空格。接下来是正则表达式 "/1/",它指示过滤器仅在解释器遇到包含此表达式(即 1)的行时输出第一个字段。

"echo" 命令的输出是包含 "1" 的一行,因此过滤器将起作用...

当处理以下示例时:

echo "1: " | awk '/1/ -F ":" {print $1}'

语法混乱,解释器选择忽略F ":"这一部分,并切换到默认的字段拆分器——空格,因此将“1:”作为第一个字段输出,并且不会有第二个字段!

Jürgen的回答包含了良好的语法...


如果不是 awk 忽略它 - awk 将其视为一个正则表达式的布尔结果(1/0),然后进行数字减法运算,再与一个单冒号(:)字符串连接,这意味着总模式为真,因为它是一个非空字符串,因此 $1 默认按空格分隔并打印。 - RARE Kpop Manifesto

-1
echo "1: " | "456:abc:515:xyz "
awk -F: NF=/1/            
      1    |  456

更新:意识到我之前的回答有些啰嗦了


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接