crontab 条目中有 7 个项目意味着什么?

Enl*_*ico 0 cron

一些同事建议我添加一个 cron 作业来做一些事情,但执行crontab -e并添加以下行:

 0 1 * * * . /path/to/some/file.bash
Run Code Online (Sandbox Code Playgroud)

为了确保这件事正常工作,我将其更改为

 0 1 * * * . /path/to/some/file.bash && date >> /some/log
Run Code Online (Sandbox Code Playgroud)

这样我就可以检查/some/log每天确实没有更多线路。

但这并没有发生。

为了调试的目的,我刚刚将这三行添加到crontab -e

 * * * * * echo "uffa" >> /home/me/without-user
 * * * * * me echo "uffa" >> /home/me/with-user
 * * * * * . echo "uffa" >> /home/me/with-any-user
Run Code Online (Sandbox Code Playgroud)

我的用户名在哪里me,这导致所有三个文件都被创建,但只有第一个文件每分钟增长一行,正如您在 8 分钟后所做的检查中看到的那样:

 0 1 * * * . /path/to/some/file.bash
Run Code Online (Sandbox Code Playgroud)

发生了什么?第二行和第三行是否使用了错误的语法,因为该行上多了一个条目?如果是这样,那么为什么还要创建该文件?


我刚刚验证了运行像这样的无意义命令jflkdasjflaksd > someFile确实会创建一个空someFile,这告诉我这两行

 * * * * * me echo "uffa" >> /home/me/with-user
 * * * * * . echo "uffa" >> /home/me/with-any-user
Run Code Online (Sandbox Code Playgroud)

只是错误的,并且由于 shell 命令行处理的工作方式,文件甚至在错误发生之前就已创建。

然而,这些都是对其他人有用的线路。怎么了?

ilk*_*chu 5

好的,首先,有两种略有不同的crontab格式。一个用于每用户 crontab,另一个用于系统 crontab(/etc/crontab以及 中的文件/etc/cron.d/)。

个人 crontab 有五个字段用于时间和日期,其余部分用于命令。系统 crontab 有五个字段用于时间和日期,第六个字段用于用户运行命令,其余行用于命令。如果您愿意的话,总计 6 和 7,尽管命令的最后一个“字段”的定义与其他字段有点不同。

个人 crontab 没有用户名字段,因为 crontab 隐含了所有者是谁,并且普通用户无论如何都不允许以其他人的身份运行程序。

(正如评论中所指出的,root用户的个人 crontab 也只是像任何其他用户一样的个人 crontab。它没有用户名字段,尽管root在其他方面有点特殊。所以不仅是/etc/crontab一个与你以 root 身份获得的一个crontab -e,它也有不同的格式。)


然后是.. 它告诉 shell 读取作为参数命名的脚本,并在当前 shell 中运行它(某些 shell 称为source的别名.)。此后任何函数定义和变量分配都将可见,这与将脚本作为单独的程序运行时不同。

线路

0 1 * * * . /path/to/some/file.bash
Run Code Online (Sandbox Code Playgroud)

告诉 shell(cron 启动的).../file.bash在同一个 shell 中运行。我不确定为什么他们建议这样做,而不是直接运行不带点的命令。不必初始化新的 shell 可能会有轻微的优化,但缺点是脚本必须在 cron 启动的 shell 中运行。如果 cron 启动一个普通的 sh,那么这是行不通的,但脚本是针对 zsh 的,或者是针对 Python 的。

如果该行位于全局 crontab 中,则意味着/path/to/some/file.bash以 user 身份运行.。这可能不是它的意思。

为了简单起见,我建议这样做(在使脚本可执行并添加适当的 hashbang 行(如果尚未完成)之后):

0 1 * * * /path/to/some/file.bash
Run Code Online (Sandbox Code Playgroud)

然后,如果不起作用. /some/script && date >> logfile,首先要查看脚本是否因错误退出。您&&在那里使用了运算符,它告诉 shell 仅在左侧命令成功退出时才运行右侧命令。你可以. /some/script; date >> logfile无条件地运行它。或者,您. /some/script; printf "run at %s, exit status %d\n" "$(date)" "$?" >> logfile也可以尝试保存退出状态。


至于这些:

* * * * * echo "uffa" >> /home/me/without-user
* * * * * me echo "uffa" >> /home/me/with-user
* * * * * . echo "uffa" >> /home/me/with-any-user
Run Code Online (Sandbox Code Playgroud)

在个人 crontab 中,第一个告诉 shell 运行echo,第二个告诉 shell 运行名为 的命令me,第三个告诉 shell 运行名为 的脚本echo。所有这些都包含重定向,并且重定向是在命令启动之前由 shell 处理的,因此在所有情况下都会创建您的文件。(它们必须如此,因为 shell 在尝试之前无法知道该命令是否可运行,如果成功,控制权将传递给该命令,因此 shell 无法再对重定向执行任何操作。)

后面两个可能会给出错误消息,如果您的 cron 设置正确,您应该会在电子邮件中收到这些消息。


然而,这些都是对其他人有用的线路。怎么了?

如上所述,. /path/to/some/script尝试在 shell 中运行给定的脚本,对于二进制命令来说它将失败,因此. echo ...不太可能工作。0 1 * * * username echo ...可以在全局 crontab 中工作,但可能不能在个人 crontab 中工作。0 1 * * * . whatever不太可能在全球范围内工作,因为.可能不是有效的用户名。