cronがスクリプトを実行する環境をシミュレートするにはどうすればよいですか?


253

私は通常、環境設定がされていないため、cronがスクリプトを実行する方法にいくつかの問題があります。スクリプトをインストールする前にテストできるように、cronと同じ方法でbash(?)を呼び出す方法はありますか?


:私はこの解決策を示唆している unix.stackexchange.com/questions/27289/...
ルディ・

さらにビット@gregseth取ると、私はこのソリューションを与えた: unix.stackexchange.com/questions/27289/...
ロバートBrisita

回答:


385

これをcrontabに(一時的に)追加します。

* * * * * env > ~/cronenv

実行後、次のようにします。

env - `cat ~/cronenv` /bin/sh

これは、ユーザーのデフォルトシェルに関係なく、cronが/ bin / shを実行することを前提としています。


5
注:これをグローバル/ etc / crontabに追加する場合は、ユーザー名も必要になります。たとえば、* * * * * root env>〜/ cronenv
Greg

10
良い、シンプルなアイデア。せっかちな場合は '* * * * *'を使用して次の分を実行し、演奏が終わったらもう一度オフにしてください;-)
Mads Buus

5
@Madsnは、前回のbashシェルの試みに戻るには:終了
spkane

5
この回答の重要性を過小評価することはできません。本に段落を含める価値がある。
Xofo 2016年

1
されるenv - 猫〜/ cronenv` / binに/ sh`もcronジョブとして記述する必要がありますか?例を挙げてください
JavaSa

61

Cronはデフォルトでこの環境のみを提供します:

  • HOME ユーザーのホームディレクトリ
  • LOGNAME ユーザーのログイン
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

さらに必要な場合は、crontabのスケジュール表の前に環境を定義するスクリプトを用意できます。


7
.セキュリティ上の理由からPATH、通常はの一部ではありません。
l0b0 2013年

49

いくつかのアプローチ:

  1. cron envをエクスポートし、それを入手します。

    追加

    * * * * * env > ~/cronenv

    あなたのcrontabに、それを一度実行し、それをオフにしてから実行します

    env - `cat ~/cronenv` /bin/sh

    そして今、あなたはshcronの環境を持つセッションの中にいます

  2. 環境をcronにする

    上記の演習をスキップして. ~/.profile、cronジョブの前で実行することもできます。

    * * * * * . ~/.profile; your_command
  3. 画面を使用

    上記の2つのソリューションは、実行中のXセッションに接続された環境などを提供するという点で失敗しますdbus。たとえば、Ubuntuでは、nmcli(Network Manager)は上記の2つのアプローチで機能しますが、cronでは失敗します。

    * * * * * /usr/bin/screen -dm

    上記の行をcronに追加し、1回実行してからオフに戻します。スクリーンセッションに接続します(screen -r)。あなたがチェックしている場合は、画面のセッションが作成されている(とps)彼らは大文字(例では時々あることに注意してくださいps | grep SCREEN

    さてnmcli、同様のものは失敗します。


22

実行できます:

env - your_command arguments

これはyour_commandを空の環境で実行します。


4
cronは完全に空の環境では動作しませんか?
jldupont 2010

2
gregsethはcronによって環境に含まれる変数を識別しました。コマンドラインでその変数を含めることができます。$ env-PATH = "$ PATH"コマンド引数
DragonFax

4
@DragonFax @dimba私が使っenv - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command argumentsているトリック
l0b0

これは、「悪意のある」または未知の環境でスクリプトをテストするための優れたシンプルな方法です。これで実行するのに十分明示している場合は、cronで実行されます。
Oli


13

6年後の回答:環境の不一致の問題はsystemd、cronの代わりに「タイマー」によって解決される問題の1つです。systemd "サービス"をCLIから実行する場合でも、cron経由で実行する場合でも、まったく同じ環境を受け取り、環境の不一致の問題を回避します。

cronジョブが手動でパスするときに失敗する最も一般的な問題は、$PATHcronによって設定された制限付きのデフォルトです。これは、Ubuntu 16.04の場合です。

"/usr/bin:/bin"

対照的に、Ubuntu 16.04で$PATH設定されsystemdているデフォルトは次のとおりです。

"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

そのため、systemdタイマーが手間をかけずにバイナリを検出する可能性が高くなっています。

systemdタイマーの欠点は、設定に少し時間がかかることです。まず、実行したいものを定義する「サービス」ファイルと、それを実行するスケジュールを定義する「タイマー」ファイルを作成し、最後にタイマーを「有効」にしてそれをアクティブにします。


10

envを実行してstdoutをファイルにリダイレクトするcronジョブを作成します。「env-」と一緒にファイルを使用して、cronジョブと同じ環境を作成します。


すみません、これで混乱しました。「env-スクリプト」では不十分ですか?
ホルヘバルガス

それはあなたに空の環境を与えます。cronを介してスクリプトを実行する場合、環境は空ではありません。
イェンスカールバーグ2010


2

デフォルトでcronは、システムのアイデアが何であれ、ジョブを実行しますsh。これは、実際のBourneシェルであるか、または可能性がdashashksh又はbash(または別のもの)にシンボリックリンクsh(およびPOSIXモードで動作している結果として)。

最善の方法は、スクリプトに必要なものがあることを確認し、何も提供されていないと想定することです。したがって、完全なディレクトリ指定を使用し、$PATH自分などの環境変数を設定する必要があります。


これはまさに私が解決しようとしていることです。誤って何かを想定するスクリプトでは、多くの問題が発生します。フルパスを実行して環境変数とすべてのジャンクを設定すると、恐ろしい巨大でメンテナンス不可能なcron行が作成されます
Jorge Vargas

re * sh申し訳ありませんが、bash = shellで育ったので、代替の(場合によってはより良い)シェルを覚えるのは難しいです。
ホルヘバルガス

1
@Jorge:crontabの行はかなり短くする必要があります。スクリプト(またはラッパースクリプト)内で必要なすべての設定を行う必要があります。次に、例としてcrontabからの典型的な行を示します。0 0 * * 1 /path/to/executable >/dev/null 2>&1次に、「実行可能」内での値を設定し$PATH、完全なディレクトリ仕様を使用して入力ファイルや出力ファイルなどを作成します。例:/path/to/do_something /another/path/input_file /another/path/to/output_file
通知があるまで一時停止します。

1

私が見つけた別の簡単な方法(ただし、エラーが発生する可能性があるため、まだテスト中です)は、コマンドの前にユーザーのプロファイルファイルを読み込むことです。

/etc/cron.d/スクリプトの編集:

* * * * * user1 comand-that-needs-env-vars

に変わります:

* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars

汚いが、それは私のために仕事を成し遂げた。ログインをシミュレートする方法はありますか?実行できるコマンドだけですか?bash --loginうまくいきませんでした。それはそれでも行くより良い方法だと思われます。

編集:これは確実な解決策のようです:http//www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/

* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l

1

受け入れられた答えは、cronが使用する環境でスクリプトを実行する方法を提供します。他の人が指摘したように、cronジョブのデバッグに必要な基準はこれだけではありません。

確かに、cronは、入力などが付加されていない非対話型端末も使用します。

それが役立つ場合は、コマンド/スクリプトをcronで実行するのと同じように簡単に実行できるスクリプトを作成しました。コマンド/スクリプトを最初の引数として呼び出してください。

このスクリプトはGithubでもホストされています(更新される可能性もあります)。

#!/bin/bash
# Run as if it was called from cron, that is to say:
#  * with a modified environment
#  * with a specific shell, which may or may not be bash
#  * without an attached input terminal
#  * in a non-interactive shell

function usage(){
    echo "$0 - Run a script or a command as it would be in a cron job, then display its output"
    echo "Usage:"
    echo "   $0 [command | script]"
}

if [ "$1" == "-h" -o "$1" == "--help" ]; then
    usage
    exit 0
fi

if [ $(whoami) != "root" ]; then
    echo "Only root is supported at the moment"
    exit 1
fi

# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
    echo "Unable to find $cron_env"
    echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
    exit 0
fi

# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
   env_string="${env_string} $envi "
done

cmd_string=""
for arg in "$@"; do
    cmd_string="${cmd_string} \"${arg}\" "
done

# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"


# Let's route the output in a file
# and do not provide any input (so that the command is executed without an attached terminal)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" >"$so" 2>"$se" < /dev/null

echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"

0

回答https://stackoverflow.com/a/2546509/5593430は、cron環境を取得してスクリプトに使用する方法を示しています。ただし、使用するcrontabファイルによって環境が異なる場合があることに注意してください。を介して環境を保存するために、3つの異なるcronエントリを作成しましたenv > log。これらは、Amazon Linux 4.4.35-33.55.amzn1.x86_64での結果です。

1. rootユーザーによるグローバル/ etc / crontab

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PWD=/
LANG=en_US.UTF-8
SHLVL=1
HOME=/
LOGNAME=root
_=/bin/env

2. rootのユーザーcrontab(crontab -e

SHELL=/bin/sh
USER=root
PATH=/usr/bin:/bin
PWD=/root
LANG=en_US.UTF-8
SHLVL=1
HOME=/root
LOGNAME=root
_=/usr/bin/env

3. /etc/cron.hourly/のスクリプト

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
_=/bin/env
PWD=/
LANG=en_US.UTF-8
SHLVL=3
HOME=/
LOGNAME=root

最も重要なこと PATHPWDそしてHOME異なることです。安定した環境に依存するように、これらをcronスクリプトで設定してください。


-8

あるとは思いません。私が知っているcronジョブをテストする唯一の方法は、1〜2分後に実行するように設定してから待つことです。


これが私がシミュレーションを求めている理由です
ホルヘバルガス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.