使用 sed 编辑 crontab

Posted

技术标签:

【中文标题】使用 sed 编辑 crontab【英文标题】:Use sed to edit crontab 【发布时间】:2016-07-19 17:37:56 【问题描述】:

我正在编写一个 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 命令最终会进入脚本。

【问题讨论】:

您使用# 作为替代分隔符的任何特殊原因?似乎是一个不必要的并发症。 【参考方案1】:

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 -

虽然有点长,但我发现它更容易阅读和理解。

【讨论】:

这里没有竞争条件的危险吗?如果您运行“crontab -l | sed ... | crontab -”,shell 会同时运行这两个“crontab”进程。在“crontab -l”打开它进行阅读之前,“crontab -”是否可能会截断用户的 crontab? 有趣的问题。所以...管道命令确实同时运行。但是命令crontab - 仅在它关闭 时覆盖现有选项卡。在这个答案的构造中,导致它关闭的是前一个管道元素的输入结束。如果简单地开始我们的crontab - 会删除现有选项卡,就会存在危险,但事实并非如此。如果 crontab -l 命令在有机会转储 crontab 之前被某些东西杀死,也会出现问题,但这表明存在其他严重问题。见:unix.stackexchange.com/q/37508/13377【参考方案2】:

是否使用 sed 或其他工具不会有太大的不同。 我也会使用 sed。

但要正确修改 cron 正在使用的内容,请注意使用 crontab 命令。 不要尝试只编辑数据文件(例如,某些系统上的 /etc/crontab)。 Cron 不会接受更改!!!。

你可以使用管道:

crontab -l | sed -e "s#\# 5 \* \* \* 3 bash test.sh#5 * * * 3 bash test.sh#"| crontab 

执行更改。

尽管如此,将启用/禁用功能添加到正在运行的脚本中不仅更简单吗?

【讨论】:

如何将启用/禁用功能移动到脚本中?你能详细说明一下吗? 在脚本的开头添加一个检查。例如。如果某个 well-known 文件不存在则中止(如果运行脚本的可能性比不运行的可能性低,则最好),或者在相反的情况下,如果存在此类文件则中止。 当然,您还应该注意从 sed 模式中转义 *。否则,它们将被用于正则表达式语法。

以上是关于使用 sed 编辑 crontab的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 SED 快速编辑文件

使用 sed 编辑 crontab

Sed

Shell脚本------sed编辑器

sedgawk介绍与正则表达式-----------(sed编辑器简单使用)

shell的三剑客sed