这对我来说有点困惑。
当我单独尝试以下 cronjobs 时:
* * * * * /bin/bash -c "readlink /proc/$$/exe >> /root/printenv"
* * * * * /bin/bash -c "readlink /proc/$PPID/exe >> /root/printenv"
* * * * * /bin/bash -c "readlink /proc/self/exe >> /root/printenv"
* * * * * /bin/bash -c "ps -h -o comm -p $$ >> /root/printenv"
* * * * * /bin/bash -c "echo $SHELL" >> /root/printenv
我分别得到以下结果:
/bin/dash
/usr/sbin/cron
/bin/readlink
sh
/bin/sh
当像这样从 cron 调用时,我似乎无法/bin/bash
在任何情况下报告它。
在直接 cronjob 中,* * * * * /bin/bash -c "command"
我如何证明“ command
”正在被/bin/bash
(如果是)解释?
答案供以后参考:
将双引号更改为单引号返回了正确的 shell:
* * * * * /bin/bash -c 'readlink /proc/$$/exe >> /root/printenv'
回到:
/bin/bash
感谢以下答案的所有贡献者。
答案1
在这种情况下,我的默认 shell 是bash
,我刚刚运行了一个测试:
sh -c 'echo $0'
结果:sh
sh -c "echo $0"
结果:-bash
bash -c 'echo $0'
结果:bash
bash -c "echo $0"
结果:-bash
看起来您需要使用单引号,'
后跟-c
开关
答案2
您所有命令的问题是您使用了错误的引号。 crontab 中的每个命令都是一段 shell 代码,由 shell 处理。 crontab 命令处理 shell 是通过SHELL
crontab 文件中变量的设置来定义的,默认为/bin/sh
.
当/bin/sh
(或任何兼容的 shell)执行脚本时/bin/bash -c "readlink /proc/$$/exe >> /root/printenv"
,解析命令行后的步骤之一是执行任何变量或命令替换。这里有一个变量替换:$$
位于双引号字符串内的 the 。 so$$
替换为进程的进程ID /bin/sh
。假设这个进程 ID 是 1234。由 cron 调用的 shell 执行/bin/bash
带有参数-c
和 的命令readlink /proc/1234/exe >> /root/printenv
。输出表明这/bin/sh
是一个到 的符号链接/bin/bash
。
如果使用单引号而不是双引号,则 cron 调用的 shell 不会执行任何变量替换,而是使用/bin/bash
参数-c
和执行命令readlink /proc/$$/exe >> /root/printenv
。然后 Bash 解析该命令,$$
用它自己的进程 ID替换,并readlink
使用参数执行1234
。
请注意,根据 shell 的不同,该命令的输出可能不是 shell 二进制文件,也可能是/bin/readlink
.原因是 bash(以及其他几个 shell)中有一个优化:当 shell 要做的最后一件事是运行外部命令时,它不会在子进程中运行该命令,而是会替换 shell 的进程图像。 (在 Unix 下执行程序总是通过将过程映像替换为另一个映像;程式通常 复制自己就在这样做之前,但这不是义务。)由于 bash 检测到运行readlink
是它必须做的最后一件事,因此它readlink
在同一进程中运行 1234,因此readlink /proc/1234/exe
报告/bin/readlink
。如果您只运行命令,Bash 就会执行此优化
bash -c 'readlink /proc/$$/exe`
但如果存在重定向,则不会。有些 shell(例如 dash)不执行此优化。有些 shell(例如 ksh)更聪明一些,会优化ksh -c 'readlink /proc/$$/exe >>/root/printenv
,但不会优化ksh -c 'readlink /proc/$$/exe; true
。(练习:为什么不可能优化那个?)