我正在编写一个sed命令,该命令应该取消对crontab中某个条目的注释。有更好的办法吗?首先想到的是sed。
例子:
crontab -l
# 5 * * * 3 bash test.sh
sed命令应取消对此项的注释。这就是我现在拥有的。
sed "s#\# 5 * * * 3 bash test.sh#5 * * * 3 bash test.sh#"
显然这个sed命令不能完成任务。
ps:sed命令最终将进入脚本。
最佳答案
Sed对于匹配特定的正则表达式和以某种方式处理文本非常有用,但在我看来这并不是其中之一。虽然您可以使用sed执行此任务,但结果可能过于复杂和脆弱。
您最初的尝试是:
sed "s#\# 5 * * * 3 bash test.sh#5 * * * 3 bash test.sh#"
这会失败,因为
*
字符是正则表达式中的一个特殊字符,并被转换为“前一个原子的零个或多个”(在本例中是一个空格)。严格地说,您可以通过转义regex中的星号(在替换模式中不需要)来让这个sed脚本工作。但这只对这种特定的模式有帮助。如果你的一个同事决定在一小时后6分钟而不是5分钟运行这个脚本,以避免与另一个脚本发生冲突,该怎么办?或者在注释字符后面有一个空格?突然你的sed替换失败了。
若要取消注释所述脚本的每个已注释事件,可以使用:
crontab -l | sed '/# *\([^ ][^ ]* *\)\{5\}[^ ]*test\.sh/s/^# *//' | crontab -
如果您使用的是more modern sed,则可以将此BRE替换为稍短的here:
crontab -l | sed -E '/# *([^ ]+ *){5}[^ ]*test\.sh/s/^# *//' | crontab -
这需要
crontab -l
的输出,很明显这是完整的crontab,使用sed对其进行操作,然后使用crontab -
根据其输出编写一个新的crontab。sed脚本匹配搜索与有效crontab相匹配的行(以避免只提到脚本的实际注释),然后执行简单的替换以仅删除开头的注释字符。匹配的模式如下:# *
-匹配注释字符,后跟零个或多个空格([^ ]+ +){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 -
虽然时间稍微长一点,但我发现它更容易阅读和理解。