在awk中使用"sub()"函数会导致重复的替换行为

  • 本文关键字:quot 换行 替换 awk sub 函数 awk
  • 更新时间 :
  • 英文 :


假设我有这个/etc/crontab文件示例:

0 0 1 * * ntpdate -s pool.ntp.org && hwclock -w

我想要实现的是用另一个ntpdate cronjob(如下面的(替换这一行

0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w

如果原始的ntpdate行不存在,那么第二行只是附加在crontab文件的末尾。

因此,我尝试了awk:

awk -v cronjob='0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w' '/ntpdate/ { sub(/^.*$/,cronjob,$0);found=1; }; { print $0 }; END {if(!found) print cronjob}' /etc/crontab

这导致了以下(当然是错误的(重复替换:

0 0 0 * * ntpdate -s pool.ntp.org 0 0 1 * * ntpdate -s pool.ntp.org && hwclock -w0 0 1 * * ntpdate -s pool.ntp.org && hwclock -w hwclock -w

我的awk脚本有什么问题?我一定误解了什么,但我不知道在哪里。

感谢您的帮助。非常感谢。

显然,&是替换字符串中的元字符;意思是"无论你匹配什么"。这就是为什么你会得到重复。

下一个问题是"如何避免它"。答案似乎是两对反斜杠:

awk -v cronjob='0 0 0 * * ntpdate -s pool.ntp.org \&\& hwclock -w' 
    '/ntpdate/ { sub(/^.*$/,cronjob,$0); found=1; } { print $0 }
     END {if(!found) print cronjob}'

我原以为一个反斜杠就足够了,但在我的测试中(在Mac OS X 10.10.4上同时使用BSD awk和GNU awk(,我似乎需要一个双反斜杠。我的期望和奈特里的经历有关——但我不确定为什么我需要额外的反斜杠,而他没有。在此期间,选择对您有效的选项:尝试单反斜杠,如果有效,那就太好了,如果无效,那就尝试双反斜杠。

当我在Ubuntu 14.04 LTS虚拟机上尝试此操作时,我发现awk确实是mawk 1.3.3 Nov 1996,并且单个反斜杠就足够了。哎哟我的怀疑是,BSD awk和GNU awk在这方面比mawk更接近POSIX标准,哪怕只是因为它们更新了十年左右(对我来说,BSD的awkawk --version产生awk version 20070501,而gawk --version产生GNU Awk 3.1.7,版权终止日期为2009年(。

使用单个&gawk报告:

gawk -v cronjob='0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w' 
     '/ntpdate/ { sub(/^.*$/,cronjob,$0);found=1; } { print $0 }
      END {if(!found) print cronjob}' /dev/null
gawk: warning: escape sequence `&' treated as plain `&'
0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w

注意警告。它出现在Ubuntu和Mac OS X上。这就是"加法"模式;/dev/null不包含该行的匹配项。如果你把它保存在文件x1中,然后用除了文件名之外的相同命令行编辑x1,我得到了最初的重复行为:

0 0 0 * * ntpdate -s pool.ntp.org 0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w hwclock -w

或者

正如pii_ke在评论中所建议的,一种更简单的技术可能是:

awk -v cronjob='0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w' 
    '/ntpdate/ { next } { print $0 } END {print cronjob}' 

这将删除原来的行,并简单地在输出的末尾添加新的行。这对awk的所有三种变体都起到了合理的作用。

YMMV-您的里程数可能有所不同;你被警告了。如果你不简单地回避这个问题,这些可怕的细微差异会让你发疯。

最新更新