使用多个分隔符时第一个字段为空

Empty first field when using multiple delimiters

提问人:miken32 提问时间:3/15/2018 最后编辑:miken32 更新时间:3/16/2018 访问量:113

问:

我正在尝试解析程序的输出,如下所示:

  Status       : OK (97 ms)

这些都是空格,没有制表符。我不知道该间距是否会在不同版本中保持一致,因此我想将空格冒号视为分隔符。

我很清楚字段分隔符可以声明为任意复杂的正则表达式,所以我希望这会起作用:

echo "  Status       : OK (97 ms)" | awk -F'[ :]+' '/Status/{print $2}'

但事实并非如此;相反,它打印“Status”,并且是一个空字符串。$1

将其与内置分隔符的输出进行比较,其中前导分隔符似乎被忽略,并且是“状态”:$1

echo "  Status       : OK (97 ms)" | awk '/Status/{print $1}'

打印起来很容易,但它让我想知道我做错了什么,或者误解了什么?$3

我正在使用 GNU Awk 3.1.7

awk 分隔符

评论


答:

1赞 John1024 3/15/2018 #1

因为,在样本输入中,字段分隔符在 之前,第一个字段为空,第二个字段为 。观察:StatusStatus

$ echo "  Status       : OK (97 ms)" | awk -F'[ :]+' '/Status/{print $2}'
Status
$ echo "Status       : OK (97 ms)" | awk -F'[ :]+' '/Status/{print $2}'
OK

一种选择是制作或进入字段分隔符,在这种情况下,无论是否有前导空格,第二个字段都将包含::($2

$ echo "  Status       : OK (97 ms)" | awk -F'[:(]+' '/Status/{print $2}'
 OK 
$ echo "Status       : OK (97 ms)" | awk -F'[:(]+' '/Status/{print $2}'
 OK 

另一种选择是保留字段分隔符,但在打印前消除前导空格:

$ echo "  Status       : OK (97 ms)" | awk -F'[ :]+' '{sub(/^ +/,"")} /Status/{print $2}'
OK
$ echo "Status       : OK (97 ms)" | awk -F'[ :]+' '{sub(/^ +/,"")} /Status/{print $2}'
OK

Awk 和前导或尾随场分隔符

对于默认字段分隔符,将忽略前导空格和尾随空格。如果使用自定义字段分隔符,则不会忽略前导和尾随分隔符。这记录在 POSIX 标准中:

  1. 如果 FS 为 null 字符串,则未指定行为。

  2. 如果 FS 是单个字符:

    一个。如果 FS 是 ,则跳过前导和尾随以及字符;字段应由一个或多个字符的集合分隔。<space><blank><newline><blank><newline>

    b.否则,如果 FS 是任何其他字符 c,则应分隔字段 通过每次出现 c。

  3. 否则,FS 的字符串值应被视为 扩展正则表达式。序列匹配的每次出现 扩展的正则表达式应分隔字段。

评论

0赞 miken32 3/16/2018
这是有道理的,但与标准分隔符的行为不符——请参阅我上面的编辑......
1赞 John1024 3/16/2018
@miken32 这是真的:根据 POSIX 规范,默认值被特殊对待。我在答案中添加了 POSIX 的一句话来记录这一点。FS
1赞 karakfa 3/15/2018 #2

根据您对字段分隔符的定义,这就是字段解析的内容。为了更好地可视化它,让我们用逗号替换字段分隔符

$ awk '{gsub(/[ :]+/,",")}1' file

,Status,OK,(97,ms)

现在很明显,“状态”是字段 2。