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