我一直使用单引号进行字段分隔,例如:awk -F';' ...
对我来说相当新的是使用反斜杠的方式,例如:awk -F\; ...
两者之间是否存在技术差异,或者只是偏好问题?
答案1
这完全与你的 shell 有关,而不是与awk
.
在类似 Bourne 的 shell 中,\
、'...'
和"..."
都是引用运算符。
引用消除了字符在 shell 语法中可能具有的特殊含义。\
引用单个字符(除了它删除的换行符),'...'
并且"..."
可以引用多个字符("..."
不包含换行符)引用每个字符)。
;
是 shell 语法中的特殊字符。它用于分隔命令。如果您想将其逐字传递给命令,则需要引用它。 \;
,';'
会做。
";"
也将执行 as;
不是那些在双引号内仍然特殊的字符之一,但是您需要"\\"
将一个文字反斜杠传递给命令,因为\
是那些在双引号内仍然特殊的字符之一"..."
(尽管只有在跟随时它才特殊)由其他特殊字符组成,"..."
就像它本身一样"
)。
同样,这在很大程度上取决于外壳。rc
例如,在shell 中,\
和"
并不特殊,更不用说引用字符了,-F\;
在那里不起作用,因为命令将被解析为以分隔的awk -F\
和命令。...
;
看如何像普通字符一样使用特殊字符?更多细节。
让事情变得更加复杂的是,请注意论证-F
本身还经过一层或两层反斜杠处理通过 awk。
awk
首先处理它接收到的参数以扩展其中的 ANSI C 转义序列。如果使用awk -F '\t'
orawk -F \\t
或awk -F "\\t"
or awk -F "\t"
,则awk
接收包含 的参数\t
,并将其扩展为制表符。 awkFS
变量将包含 TAB 字符,而不是\t
。
使用awk -F '\\'
,awk
接收\\
参数并设置FS
为\
字符。严格来说,awk -F '\'
will 是未指定的,因为转义序列尚未完成,但实际上,除了 busybox 之外awk
,我知道的所有awk
实现都将其视为与 相同awk -F '\\'
。
在 中awk
,当FS
包含单个字符时,该字符是字段分隔符。awk -F .
按点字符分割记录。
但是,当FS
包含多个字符时,它会被解释为正则表达式。awk -F ..
不会溢出在两个点的序列上,而是溢出在任何两个字符的序列上,就像.
匹配任何单个字符的正则表达式运算符一样。要分成两个点,您需要awk -F '[.][.]'
或awk -F '\\.\\.'
。
对于awk -F '\\\\'
,shell 将文字\\\\
传递给awk
,awk
将这两个中的每一个扩展为\\
,\
因此FS
变为\\
,它被视为正则表达式。\
在正则表达式语法中也比较特殊,用于去除字符的特殊含义作为正则表达式运算符这次。再次强调,这是在反斜杠字符上进行拆分,尽管这一次是作为正则表达式。
因此,在实践中,要拆分\
,所有这些(在类似 Bourne 的 shell 中)都可以工作:
awk -F '\' # FS becomes a single \ except in busybox where it's empty
awk -F "\\" # instead so it's a one-character split on backslash
awk -F \\ # and a one-field-by-character split in busybox
awk -F '\\' # FS becomes a single \ in every awk implementation
awk -F \\\\ # so one-character split on backslash
awk -F "\\\\"
awk -F '\\\' # FS is \ on busybox and \\ in other implementations
awk -F \\\\\\ # so one-character split on backslash in busybox and
awk -F "\\\\\\" # \\ regex split in other implementations, to the same effect
awk -F '\\\\' # FS is \\ in all implementations so
awk -F \\\\\\\\ # \\ regex split
awk -F "\\\\\\\"
我建议使用单引号,因为它们是最直接且最不令人惊讶的引号。所以在这里,要在反斜杠上进行可移植的分割:awk -F '\\'
.
您还可以执行以下操作:
awk -v FS='\\' ...
或者
awk 'BEGIN{FS="\\"} ...'
或者
awk ... 'FS=\\'
或者:
FS='\' awk 'BEGIN{FS = ENVIRON["FS"]} ...'
(避免 执行额外的反斜杠扩展awk
,因此只需要一个反斜杠)。
答案2
单引号内的所有字符均按字面意思处理(即一对单引号之间没有特殊字符)。如果没有单引号,如果要使用文字字符,则需要反斜杠转义具有特殊含义的字符。
这些是shell的引用规则,与awk无关。