使用 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的主要内容,如果未能解决你的问题,请参考以下文章