web-dev-qa-db-ja.com

シバンはシェルをcronに設定しません

以下を含むスクリプトがあります。

#!/bin/bash
printenv

コマンドラインから実行すると:

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

毎回Shell=/bin/bashを出力します。ただし、cronから実行すると、常にShell=/bin/shが出力されます。どうしてこれなの?どうすればcronにシバンを適用させることができますか?

私はすでにcronPATHをチェックしました。/binが含まれています。

7
Benubird

Shebangは機能しており、cronはそれとは何の関係もありません。ファイルが実行されるとき、そのファイルの内容が#!で始まる場合、カーネルは#!行で指定されたファイルを実行し、元のファイルを引数として渡します。

あなたの問題は、シェルスクリプトのShellがスクリプトを実行しているシェルを反映していると信じているように見えることです。これはそうではありません。実際、ほとんどのコンテキストで、Shellはユーザーが好むインタラクティブシェルを意味し、ターミナルエミュレータなどのアプリケーションが実行するシェルを決定することを目的としています。 cronでは、Shellは、crontabエントリ(時刻表示の後の行の部分)を実行するために使用するプログラムをcronに指示する変数です。

シェルは、開始時に設定されていない限り、Shell変数を設定しません。

Shell/bin/shであるという事実はおそらく無関係です。スクリプトには#!/bin/bash行があるため、bashによって実行されます。自分を納得させたい場合は、スクリプトにps $$を追加して、psにスクリプトを実行しているシェルに関する情報を表示させます。

Bashリファレンスマニュアル 言います:

シェル-シェルへのフルパス名は、この環境変数に保持されます。シェルの起動時に設定されていない場合、Bashは現在のユーザーのログインシェルのフルパス名を割り当てます。

man 5 crontab 言います:

いくつかの環境変数は、cron(8)デーモンによって自動的に設定されます。シェルは/ 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が表示されます

シバンは動作します。文書化された動作があります:)

1

ただし、cronから実行すると、常にShell =/bin/shが出力されます。どうしてこれなの?

これは、cronがShell/bin/shに設定したためです。これは、cronがcrontabエントリを実行するために使用するデフォルトのプログラムであるためです。 man 5 crontabから:

いくつかの環境変数は、cron(8)デーモンによって自動的に設定されます。シェルは/ bin/shに設定されています...

そして、Evgeny Vereshchaginの回答ですでに示されているように、その変数は、すでに設定されている場合、後でBashによって変更されることはありません。

どうすればcronにシバンを適用させることができますか?

次の例からわかるように、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プロセスを開いたことを示しています。

0
Jaime Hablutzel