我怎样在awk中使用"\s|="作为字段分隔符?

4

这是有效的:

awk  -F"[[:space:]]|=" '/^[^#]/{print($2)}'   /etc/fstab 

但这个不行:
awk  -F"\s|=" '/^[^#]/{print($2)}'   /etc/fstab 

我正在使用Ubuntu 16.04自带的awk工具。

2个回答

4
欢迎来到bash转义序列的噩梦和在awk中使用字符串常量作为正则表达式。您定义了一个双引号括起来的字符串,该字符串用作awk中的正则表达式(-F"\s|=")。 awk如何处理正则表达式: 首先,您需要了解有两种方法可以在awk中编写正则表达式:
  • 将其用斜杠括起来/ere/
  • 将其用引号括起来(例如使用FS时)
然而,后者意味着您的字符串将被解析两次:第一次是当awk读取您的程序时,第二次是当它去将左侧操作数上的字符串与右侧模式进行匹配时(请参见GNU awk手册)。
因此,表达式/\s|=/"\\s|="是等价的正则表达式,而表达式/s|=/"\s|="也是等价的。

如何使用bash处理反斜杠(\):

Bash使用\字符来转义字符。未引用的反斜杠(\)保留紧随其后的下一个字符的字面值(有少数例外)。单引号中的反斜杠没有特殊含义,而双引号中的反斜杠仅在后面跟着以下字符之一时才保留其特殊含义:$`"\<newline>

这使我们现在有以下选项:

  • -F"\s|=": awk接收字符串表达式"\s|=",并将其解析为正则表达式/s|=/
  • -F"\\s|=": bash转义第二个\,awk接收字符串表达式"\s|=",并将其解析为正则表达式/s|=/
  • -F"\\\s|=": bash转义第二个\,awk接收字符串表达式"\\s|=",并将其解析为正则表达式/\s|=/
  • -F"\\\\s|=": bash转义第二和第四个\,awk接收字符串表达式"\\s|=",并将其解析为正则表达式/\s|=/

因此,以下所有内容都是等效的:

$ awk -F '\\s|=' '/^[^#]/{print $2}' /etc/fstab
$ awk -F "\\\s|=" '/^[^#]/{print $2}' /etc/fstab
$ awk -F "\\\\s|=" '/^[^#]/{print $2}' /etc/fstab
$ awk 'BEGIN{FS="\\s"}/^[^#]/{print $2}' /etc/fstab
$ awk 'BEGIN{FS="\\s"}/^[^#]/{print $2}' /etc/fstab
$ awk "BEGIN{FS=\"\\\\s|=\"}/^[^#]/{print \$2}" /etc/fstab


有三种引用机制:转义字符、单引号和双引号。
- 非引用的反斜杠(\)是转义字符。它保留跟在其后面的下一个字符的字面值,但换行符例外。如果出现 \newline 对,并且反斜杠本身没有被引用,则 \newline 被视为行继续符(即从输入流中删除并有效地忽略)。 - 用单引号括起来的字符保留引号内每个字符的字面值。单引号内不允许出现单引号,即使前面有反斜杠也不行。 - 用双引号括起来的字符保留引号内所有字符的字面值,但 $、`、\ 和在启用历史扩展时的 ! 除外。$ 和 ` 在双引号内保持特殊含义。只有在反斜杠后跟以下字符之一时,反斜杠才保留其特殊含义:$、`、"、\ 或 \newline。可以通过在其前面加上反斜杠来在双引号内引用双引号。如果启用了历史扩展,并且在双引号中出现未经转义的 !,则将执行历史扩展,除非使用反斜杠对其进行了转义。在 ! 前面的反斜杠不会被删除。
来源:man bash 中的 QUOTING 部分

3
Shell编程准则:除非您需要使用双引号(例如要让变量扩展),否则始终将所有字符串和脚本用单引号括起来,并且在这些情况下始终使用双引号,除非您需要将它们保持未引用状态(例如用于globbing / 文件名扩展)。这种方法的积极副作用是每次都需要最少量的转义。 - Ed Morton

0

看一下它产生的错误:

$ awk -F"\s|=" '/^[^#]/{print($2)}' /etc/fstab
awk: warning: escape sequence `\s' treated as plain `s'

你需要正确转义 \s。例如,以下方式对我来说有效:

$ awk 'BEGIN { FS="\\s|=" } /^[^#]/{print($2)}'  /etc/fstab

2
或者使用-F'\\s|='。也有可能OP没有使用GNU awk,因此\s不会被支持,因为它是GNU扩展。顺便提一下,考虑使用-F'[[:space:]=]' - Ed Morton
@EdMorton OP 使用了双引号字符串 -F"\s|=" - kvantour
我只是在说一个可能的解决方法,就是用单引号引用字符串并添加1个反斜杠,但我怀疑他们根本没有使用gawk,否则结果错误消息将非常清晰明显,并且希望他们在问题中提到它。 - Ed Morton

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