awk的默认分隔符只有空格吗?
gawk
) - 一些Linux发行版中的默认awk
mawk
) - 一些Linux发行版中的默认awk
(例如,早期版本的Ubuntu crysman报告称19.04版本现在附带GNU Awk-请参见他下面的评论。)awk
awk -W version
将告诉您默认awk
的哪个实现。awk --version
(GNU Awk除了awk -W version
外还理解)。RS
是输入记录分隔符,它描述了输入如何被分成记录:
\n
;也就是说,默认情况下输入被分成行。awk
的命令行上,可以将RS
指定为-v RS=<sep>
。RS
限制为字面上的单个字符,但GNU Awk和Mawk支持多字符值,这些值可能是扩展正则表达式(BWK Awk不支持)。FS
是输入字段分隔符,它描述了每个记录如何被分割成字段;它可以是一个扩展正则表达式。
awk
的命令行上,可以将FS
指定为-F <sep>
(或-v FS=<sep>
)。0x20
),但该空格不是字面上解释为(唯一的)分隔符,而具有特殊含义;请参见下文。默认情况下:
POSIX规范使用抽象的<blank>
表示空格和制表符, 这对于所有语言环境都是正确的,但在特定的语言环境下,可能会包括其他字符 - 我不知道是否存在这样的语言环境。
请注意,使用默认的输入记录分隔符 (RS
),\n
,换行符通常不会成为字段分隔符,因为在这种情况下,没有记录本身包含\n
。
然而,作为字段分隔符的换行符确实会发挥作用:
RS
设置为导致记录本身包含\n
实例的值时(例如当RS
设置为空字符串时;见下文)。split()
函数将字符串拆分为数组元素时没有明确的字段分隔符参数。
RS
生效的情况下,输入记录不会包含\n
实例,但是如果在来自不同来源的多行字符串上调用split()
函数(例如通过-v
选项传递的变量或伪文件名),split()
函数总是将\n
视为字段分隔符。重要的非默认考虑因素:
将空字符串赋值给RS
有特殊含义:它以段落模式读取输入,这意味着输入被非空行的连续运行分成记录,忽略前导和尾随的空行。
当你将除了字面空格之外的任何东西赋值给FS
时,FS
的解释会发生根本性的变化:
FS
设置为[ ]
- 即使它实际上相当于一个空格 - 也会导致每个记录中的每个单独空格实例被视为字段分隔符。+
;例如,[\t]+
将识别制表符的连续运行作为单个分隔符。FS
设置为空字符串意味着每个记录的每个字符都是自己的字段。根据 POSIX标准, 如果RS
设置为空字符串(段落模式),则换行符(\n
)也会被视为字段分隔符,无论FS
的值如何。
[1] 不幸的是,GNU Awk至少在版本4.1.3中遵守了一个已过时的POSIX标准,当你使用强制POSIX兼容选项-P
(--posix
)时,关于字段分隔符:当该选项生效并且RS
设置为非空值时,换行符(\n
实例)不被认为是字段分隔符。GNU Awk手册详细说明了过时的行为(但忽略了当RS
设置为空字符串时不适用的事实)。POSIX标准在2008年进行了更改(请参见评论),以将新行视为字段分隔符,当FS
具有其默认值时 - 正如GNU Awk一直没有使用-P
(--posix
)所做的那样。
以下是2个验证上述行为的命令:
-P
并将RS
设置为空字符串,则\n
仍然被视为字段分隔符:gawk -P -F' ' -v RS='' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
-P
并且RS
不为空,则\n
不会被视为字段分隔符-这是过时的行为:gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
FS
值,但它代表着空格、制表符和换行符。我已经更新了我的答案以作澄清。 - mklement0❱ which -a "awk" /usr/bin/awk ❱ file /usr/bin/awk /usr/bin/awk: symbolic link to /etc/alternatives/awk ❱ file /etc/alternatives/awk /etc/alternatives/awk: symbolic link to /usr/bin/gawk
- crysman问题 默认的分隔符是否只是空格用于awk?
模糊不清,但我会尝试回答您可能会问的两个问题。
FS
变量的默认值(它保存了告诉awk如何将记录分隔成字段的字段分隔符)是一个单独的空格字符。
awk 用于将记录分隔成字段的东西是“字段分隔符”,它是一个正则表达式,具有一些附加功能,仅在字段分隔符为单个空白字符时才适用。这些额外的功能是:
[ ]
而不仅仅是独立的字面空格字符,就像在正则表达式中一样。除了在读取输入时将字段分隔符用于将记录拆分为字段,它们还在某些其他上下文中使用,例如 split()
的第三个参数,因此重要的是您知道哪些上下文需要字符串、正则表达式或字段分隔符,man 页面清楚地指定了每个上下文。
除其他事项外,以上内容还解释了这一点:
$ echo ' a b c ' | awk '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F' ' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F'[ ]' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
5: <> <a> <b>
所以,如果您不明白为什么前两个产生相同的输出但最后一个不同,请询问。
0x20
),而“blank”是一种可能特定于语言环境的抽象:“在POSIX语言环境中,只包括<space>和<tab>。在语言环境定义文件中,<space>和<tab>会自动包含在这个类别中。”(我在POSIX规范中看不到涵盖“blank”和换行符的总称。) - mklement0FS
变量的值作为字段分隔符将记录分成字段。如果FS
是单个字符,则字段由该字符分隔。如果FS
是空字符串,则每个单独的字符都成为单独的字段。否则,FS
应该是完整的正则表达式。特殊情况下,如果FS
是单个空格,则字段由连续的空格、制表符和/或换行符分隔。”mawk
;例如,在Ubuntu上)- 它们也适用于BWK Awk,如在类似BSD的平台上,包括macOS。 - mklement0BWK awk
还能处理RS
中的正则表达式:jot -s''-c-33 126 | gtr -d'\n' | nawk'$-_ = NR"=NR:{ "($-_)" }:NF=" NF' RS='(:|[0-9]|\42)+' 1=NR:{!}:NF=1 2=NR:{#$%&'()*+,-./}:NF=1 3=NR:{;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\
abcdefghijklmnopqrstuvwxyz{|}~}:NF=1` - RARE Kpop Manifesto'[ ]+' 对我有效。
运行 awk -W version
获取 awk 版本。我的版本是 GNU Awk 4.0.2
。
# cat a.txt
tcp 0 0 10.192.25.199:65002 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:26895 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:18422 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8888 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50010 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50075 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8093 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8670 0.0.0.0:* LISTEN
# cat a.txt | awk -F '[ ]+|:' '{print $5}'
65002
26895
111
18422
22
8888
50010
50075
8093
8670
如果你只是想测试默认分隔符,你可以运行以下命令:
# cat a.txt | awk -F '[ ]+' '{print $4}'
10.192.25.199:65002
127.0.0.1:26895
0.0.0.0:111
0.0.0.0:18422
0.0.0.0:22
10.192.25.199:8888
0.0.0.0:50010
0.0.0.0:50075
10.192.25.199:8093
0.0.0.0:8670
[ \t]+
,即一个或多个空格和制表符。 - ThorFS='[ \t\n]+'
。但是只有在RS不包括换行符时才会产生影响。 - ThorRS
,如果您构造一个包含换行符的字符串并执行split(string,arr)
,默认的FS
也会产生影响。 - Ed Morton