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

时间:2015-07-04 01:41:01

标签: 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脚本出了什么问题?我一定误解了什么,但我无法弄清楚在哪里。

感谢任何帮助。谢谢。

1 个答案:

答案 0 :(得分:3)

简洁地说,&是替换字符串中的元字符;它意味着“无论你匹配什么”#。这就是你为什么要重复的原因。

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

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),似乎我需要一个双反斜杠。我的期望与Naitreeexperience有关 - 但我不确定为什么我需要额外的反斜杠而他没有。在此期间,请选择适合您的选项:尝试使用单个反斜杠,如果有效,那么很好,如果没有,请尝试使用双反斜杠。

当我在Ubuntu 14.04 LTS VM上尝试这个时,我发现awk确实是mawk 1.3.3 Nov 1996,并且单个反斜杠就足够了。哎哟!我怀疑BSD awk和GNU awk在这方面比mawk更接近POSIX标准,只是因为他们已经十年左右更新了(对我来说, awk --version获取awk awk version 20070501gawk --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上。  那就是“添加”#39;模式; /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_kecomment中建议的那样,一种更简单的技术可能是:

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

这会删除原始行,只需在输出结尾添加新行。这与awk的所有三种变体都很合理。

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