当它从命令行 bash 工作时,无法从 crontab 运行 bash 脚本

Posted

技术标签:

【中文标题】当它从命令行 bash 工作时,无法从 crontab 运行 bash 脚本【英文标题】:Cannot run bash script from crontab when it works from command line bash 【发布时间】:2014-12-19 07:10:08 【问题描述】:

我有一个奇怪的问题,即能够从命令行运行 bash 脚本,但不能从 root 的 crontab 条目运行。我正在运行 Ubuntu 12.04。

* * * * 1-5 root /home/xxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/jmeter-cron-randomise.sh >> /home/xxxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/cron.log

如果我使用 bash 从 cmd 行运行脚本,它可以正常工作,但 sh 失败并出现以下错误:

> jmeter-cron-randomise.sh: 7: jmeter-cron-randomise.sh: arithmetic
> expression: expecting primary: "  % 1 "

用谷歌搜索了这个问题,似乎标准 shell 没有与 bash 相同的数学运算符,如 %(模数)。我不确定为什么脚本中的 cron 作业失败了?我假设这是因为它没有使用 bash shell?它肯定是被 cron 守护进程触发的(可以在 /var/log/syslog 中看到它)。非常感谢任何帮助。

【问题讨论】:

你的 shebang 线上有什么? 您的cron 是否使用/bin/sh 运行命令?看起来它可能确实如此,因为如果您使用sh 而不是bash(如:sh /home/…/jmeter-cron-randomise.sh)运行脚本,则会出现错误。在 Ubuntu 上,/bin/sh 通常是 dash,而不是 bash。要修复,请在您的 crontab 条目中使用 bash /home/…/jmeter-cron-dandomise.sh >> … 看起来它正在运行 sh。如何强制它在 shebang 线之外运行 bash? kal:运行bash /path/of/script.sh。这个bash应该是which bash的输出,也就是二进制的全路径。 @kal head -n 1 /home/xxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/jmeter-cron-randomise.sh | cat -vE 的完整输出是什么?这将以视觉上明确的方式显示第一行,以帮助确定是否例如字节顺序标记使您的 shebang 无效。 【参考方案1】:

您可能需要告诉 cron 要使用的 shell 是 bash shell,因为它默认为 sh。您可以通过将此行放入您的 crontab 中来对所有 crontab 条目执行此操作:

SHELL=/bin/bash

请注意,这将导致 crontab 中的所有脚本都在 bash 下运行,这可能不是您想要的。如果您想将 crontab 行本身更改为仅运行 bash,请将其更改为:

* * * * 1-5 root /bin/bash /home/xxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/jmeter-cron-randomise.sh >> /home/xxxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/cron.log 2>&1

请注意,我还导致将 stderr 写入 cron.log 文件 (2>&1),这可能不是您想要的,但这是很常见的做法。这可以帮助您进一步诊断脚本中的错误。

【讨论】:

这几乎是正确的:它可以是/bin/bash,也可以是/usr/bin/bash 或其他。有趣的是,真正的完整路径可以通过which bash获取。 谢谢。通过 crontab -e 恢复为 root 用户使用 crontab 条目并面对原始问题我现在可以看到有用的失败消息 ------ 运行 jmeter-cron-randomiser 脚本 min = 1 random = 1933 rmin = 0 /bin/sh: 1: root: 未找到 /bin/sh: 1: root: 未找到 /bin/sh: 1: root: 未找到 感谢@viritude。通过编辑 /etc/crontab 解决了总体问题。 @fedorqui - 虽然这是正确的,但路径是已知的。 kal 在他对这个问题的第一条评论中提到它是 /bin/bash。【参考方案2】:

如果这对任何人都有帮助:对我来说,这似乎是因为我以“DOS”line endings(CR-LF)而不是“unix”行尾(LF)结束。这可以使用od 或您最喜欢的十六进制转储工具进行检查,例如:

od -c <script_file>

... 并寻找 \r\n 而不仅仅是 \n。

似乎(并且this article 支持它)CR 字符阻止“shebang”工作,因为它被解释为 shell 可执行文件的文件名的一部分。

(出现行尾本身是因为文件来自 git 存储库并通过 Windows 机器传输)。

【讨论】:

【参考方案3】:

我在尝试以 root 身份安排数据库备份时也遇到了这个问题,这让我大吃一惊!我正在开发一个 CentOS 7 机器。 每当我检查/var/spool/mail/root 时,我都会看到一个日志: sh: root: command not found,但该命令将在终端中完美运行。

这对我有用:

    我在以 root 身份登录时使用 crontab -e 创建了 crontab 条目。

    以上面的命令为例:

    * * * * 1-5 root /home/xxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/jmeter-cron-randomise.sh &gt;&gt; /home/xxxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/cron.log

我删除了 root 用户条目,例如: * * * * 1-5 /home/xxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/jmeter-cron-randomise.sh &gt;&gt; /home/xxxxxxx/jmeter/VerificationService-0.0.1-SNAPSHOT/cron.log

这解决了我的问题。

【讨论】:

以上是关于当它从命令行 bash 工作时,无法从 crontab 运行 bash 脚本的主要内容,如果未能解决你的问题,请参考以下文章

当它从一个 collectionView 移动到另一个时,如何实现单元格动画?

Python脚本在几秒钟后自动关闭,当它从IP摄像机对RTSP实时源进行对象检测时?

一些 GNUPlot 终端从命令行工作,但从 Perl 调用时不能(管道)

Bash 脚本无法识别命令行参数? [复制]

bash:以空格作为参数传递路径?

进入sqlplus命令行后无法暂停关闭bash文件