我正在编写一个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 -

虽然时间稍微长一点,但我发现它更容易阅读和理解。

09-04 01:18
查看更多