为什么以下示例中未打印前导空格?
$ echo " foo bar" | awk '{ $2 = "baz"; print $0 }'
foo baz
答案 0 :(得分:4)
每当你“触摸”记录中的字段时(在这种情况下通过分配给第二个字段),awk会重新格式化整个记录。因此$1
为“foo”,每个字段由输出字段分隔符OFS
分隔,默认情况下为单个空格。
为了保持线条完整,您可以将代码更改为以下内容:
$ echo " foo bar" | awk '{ sub(/bar/, "baz"); print $0 }'
baz bar
作为一个整体而不是单个字段在线上操作意味着不会重新格式化。
......虽然在那时,你也可以使用sed:
$ echo " foo bar" | sed 's/bar/baz/'
baz bar
答案 1 :(得分:4)
无论何时修改记录的字段,awk都会重新编译记录,使用OFS的值分隔字段并从记录中删除前导和尾随空白。为了保持空白区域的完整性,您必须修改整个记录,而不是修改它的任何一个字段。
例如,用GNU awk做你想做的事情:
$ echo " foo bar" | awk '{ $0=gensub(/(^\s*\S+\s+).*/,"\\1baz",""); print $0 }'
foo baz
不要认为只能做sub(/bar/,"baz")
,因为当记录中出现“bar”而不是第二个字段时会失败:
$ echo " rhubarb bar" | awk '{ sub(/bar/, "baz"); print $0 }'
rhubazb bar
$ echo " rhubarb bar" | awk '{ $0=gensub(/(^\s*\S+\s+).*/,"\\1baz",""); print $0 }'
rhubarb baz
通常,要替换字段由默认FS分隔的记录的第N个字段,请执行以下操作:
$0=gensub(/((^\s*\S+\s+){N-1})\S+/,"\\1baz","")
并且对于在字符类中无法否定的FS值,这次使用GNU awk为第4个arg分割():
awk -F'<whatever>' '{split($0,f,FS,s); f[2]="baz"; r=s[0]; for (i=i;i<=NF;i++) r=r f[i] s[i]; $0=r; print $0}'
答案 2 :(得分:2)
awk在空格上分割线条。
对于该行,awk设置$1="foo"
和$2="bar"
。
当你没有修改关于某行的任何内容时,只需将输出行打印出来。
当您修改该行时(通过指定其中一个字段),awk重新组合字段以形成输出行(它使用OFS
的值重新组合字段)。
所以awk会占用你的两个字段(现在$1="foo"
和$2="baz"
)并且(有效地)这样做:
printf "%s%s%s\n", $1, OFS, $2