当从 cron 调用时如何证明解释器是 /bin/bash?

当从 cron 调用时如何证明解释器是 /bin/bash?

这对我来说有点困惑。

当我单独尝试以下 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 是通过SHELLcrontab 文件中变量的设置来定义的,默认为/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。(练习:为什么不可能优化那个?)

相关内容