Sed 非常适合匹配特定的正则表达式并以某些方式操作文本,但在我看来这并不是其中之一。虽然您可以使用 sed 来完成此任务,但结果可能过于复杂和脆弱。
您最初的尝试是:
sed "s#\# 5 * * * 3 bash test.sh#5 * * * 3 bash test.sh#"
这会失败,因为*
字符是正则表达式中的特殊字符,被翻译为“零个或多个前一个原子”(在本例中为空格)。严格来说,您可以通过转义正则表达式中的星号(替换模式中不需要)来使此 sed 脚本正常工作。
但这仅对这种特定模式有帮助。如果您的一位同事决定在下班后 6 分钟而不是 5 分钟运行此脚本,以避免与另一个脚本发生冲突,该怎么办?或者评论字符后面有一个空格?突然你的 sed 替换失败了。
取消注释every评论有问题的脚本的出现,您可以使用:
crontab -l | sed '/# *\([^ ][^ ]* *\)\{5\}[^ ]*test\.sh/s/^# *//' | crontab -
如果您使用的是更现代的 sed,您可以用稍短的 ERE 替换此 BRE:
crontab -l | sed -E '/# *([^ ]+ *){5}[^ ]*test\.sh/s/^# *//' | crontab -
这需要输出crontab -l
,这显然是您完整的 crontab,使用 sed 操作它,然后根据其输出编写一个新的 crontabcrontab -
。 sed 脚本匹配搜索与有效 crontab 匹配的行(以避免仅提及您的脚本的实际注释),然后进行简单的替换以仅删除开头的注释字符。匹配的模式如下所示:
-
# *
- 匹配注释字符后跟零个或多个空格
-
([^ ]+ +){5}
- 五个非空格字符串,后跟空格
-
[^ ]*
- 任意数量的非空格字符,这会导致:
-
test\.sh
- 你的脚本。
但请注意,这不匹配all有效的 crontab 时间,其中可能包括诸如@reboot
, @weekly
, @midnight
等查看man 5 crontab
了解详情。
非 sed 替代品,例如awk
可能是有序的。以下 awk 解决方案对我来说更有意义:
crontab -l | awk -v script="test.sh" '
{ field=6 }
/^# / { field++ }
index($field,script) { sub(/^#/,"") }
1' \
| crontab -
虽然它有点长,但我发现它更容易阅读和理解。