假设我有这个/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
脚本出了什么问题?我一定误解了什么,但我无法弄清楚在哪里。
感谢任何帮助。谢谢。
答案 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
),似乎我需要一个双反斜杠。我的期望与Naitree的experience有关 - 但我不确定为什么我需要额外的反斜杠而他没有。在此期间,请选择适合您的选项:尝试使用单个反斜杠,如果有效,那么很好,如果没有,请尝试使用双反斜杠。
当我在Ubuntu 14.04 LTS VM上尝试这个时,我发现awk
确实是mawk 1.3.3 Nov 1996
,并且单个反斜杠就足够了。哎哟!我怀疑BSD awk
和GNU awk
在这方面比mawk
更接近POSIX标准,只是因为他们已经十年左右更新了(对我来说, awk --version
获取awk
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上。
那就是“添加”#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_ke在comment中建议的那样,一种更简单的技术可能是:
awk -v cronjob='0 0 0 * * ntpdate -s pool.ntp.org && hwclock -w' \
'/ntpdate/ { next } { print $0 } END {print cronjob}'
这会删除原始行,只需在输出结尾添加新行。这与awk
的所有三种变体都很合理。
YMMV - 您的里程可能会有所不同;你被警告了如果你不能简单地回避问题,这些可怕的微妙差异可能会让你感到疯狂。