Shebang没有在cron中设置SHELL

Shebang没有在cron中设置SHELL

我有一个脚本包含:

#!/bin/bash
printenv

当我从命令行运行它时:

env testscript.sh
bash testscript.sh
sh testscript.sh

每次,它都会输出SHELL=/bin/bash.然而,当它从 cron 运行时,它总是输出SHELL=/bin/sh.为什么是这样?我怎样才能让 cron 应用 shebang?

我已经检查了 cron 路径;它确实包含/bin。

答案1

shebang 正在工作,而 cron 与此无关。当执行一个文件时,如果该文件的内容以 开头#!,内核将执行该#!行指定的文件并将原始文件作为参数传递给它。

您的问题是您似乎相信SHELLshell 脚本中反映了正在执行脚本的 shell。不是这种情况。事实上,在大多数情况下,SHELL意味着用户的偏好交互的shell,它的作用是让终端仿真器等应用程序决定执行哪个 shell。在 cron 中,SHELL是一个变量,告诉 cron 使用什么程序来运行 crontab 条目(时间指示之后的行部分)。

Shell 不会设置该SHELL变量,除非在启动时未设置该变量。

事实SHELL/bin/sh可能是无关紧要的。您的脚本有#!/bin/bash一行,因此它由 bash 执行。如果您想说服自己,请ps $$在脚本中添加以ps显示有关执行脚本的 shell 的信息。

答案2

Bash 参考手册说:

SHELL - shell 的完整路径名保存在此环境变量中。如果 shell 启动时未设置,Bash 会为其分配当前用户登录 shell 的完整路径名。

man 5 crontab说:

几个环境变量由 cron(8) 守护进程自动设置。 SHELL 设置为 /bin/sh,LOGNAME 和 HOME 从 crontab 所有者的 /etc/passwd 行设置。 PATH 设置为“/usr/bin:/bin”。 HOME、SHELL 和 PATH 可能会被 crontab 中的设置覆盖

因此该SHELL变量是在 Bash 启动时设置的。

尝试SHELL=/bin/awesome/shell bash testcript.sh。你应该看到SHELL=/bin/awesome/shell

舍邦有效。你的行为有记录:)

答案3

然而,当它从 cron 运行时,它总是输出 SHELL=/bin/sh。为什么是这样?

这是因为 cron 设置SHELL/bin/sh,因为这是 cron 用于运行 crontab 条目的默认程序。从man 5 crontab

几个环境变量由 cron(8) 守护进程自动设置。 SHELL 设置为 /bin/sh...

正如 Evgeny Vereshchagin 的答案已经指出的那样,如果该变量已经设置,则稍后 Bash 不会对其进行修改。

我怎样才能让 cron 应用 shebang?

Cron 已经在应用它了为您自己的脚本,正如您从以下示例中看到的那样。

假设您有以下内容display_process_tree.sh

#!/bin/bash
pid=$$
depth=0
while
    [ "$pid" -gt 0 ] &&
    read -r ppid name < <(ps -o ppid= -o comm= -p "$pid")
do
    eval $(echo printf '" %0.s"' {0..$depth})
    if [[ -r /proc/$pid/exe ]]; then    
    echo -n "$name - "
    readlink -f /proc/$pid/exe
    else
    echo $name
    fi
    pid=$ppid
    depth=$((depth+1))
done

还有一个像这样的 crontab:

* * * * * /path/to/display_process_tree.sh > /tmp/display_process_tree.log

现在,如果您等待输出到达/tmp/display_process_tree.log,您将发现如下所示的进程树:

 display_process - /bin/bash
  sh - /bin/dash
   cron
    cron
     systemd

这表明 cron 实际上使用/bin/sh(链接到我的系统中)为您的脚本/bin/dash打开一个新进程。/bin/bash

答案4

将 shebang 更改为

#!/bin/env bash

或者执行crontab -e让脚本使用您自己的环境变量运行,因为 cron 自己的环境变量是不同的。


作为旁注,根据这篇文章在askubuntu上cron,您需要在脚本顶部 给出一个 PATH:

PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# rest of script follows

但是,鉴于您所说的 PATH 似乎有正确的搜索目录,您可以排除这一点。

相关内容