(私はすでに読んだ 新しいcronスクリプトをテストするにはどうすればよいですか? 。)
特定の問題があります(cronジョブが実行されていない、または適切に実行されていないようです)が、一般的な問題です。cron化されたスクリプトをデバッグしたいのですが。 * * * * * crontab行を設定できることは承知していますが、これは完全に満足できる解決策ではありません。 cronジョブが実行されているかのように、コマンドラインからcronジョブを実行できるようにしたいと思います(同じユーザー、同じ環境変数など)。これを行う方法はありますか?スクリプトの変更をテストするために60秒待つ必要はありません。
これが私がやったことであり、この状況でうまくいくようです。少なくとも、エラーは表示されますが、ユーザーがコマンドラインから実行するとエラーは表示されません。
ステップ1:この行をユーザーのcrontabに一時的に配置します。
* * * * * /usr/bin/env > /home/username/tmp/cron-env
ファイルが書き込まれたら、それを取り出しました。
ステップ2:以下を含む小さなrun-as-cron bashスクリプトを作成しました。
#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"
それで、問題のユーザーとして、私はすることができました
run-as-cron /the/problematic/script --with arguments --and parameters
このソリューションは、Sudoなどを利用してより柔軟に拡張できることは明らかです。
これが他の人を助けることを願っています。
私はピストスの回答に基づいた解決策を提示しますが、欠陥はありません。
次の行をcrontabに追加します。 crontab -e
を使用
* * * * * /usr/bin/env > /home/username/cron-env
Cronジョブが実行されるのと同じ環境でコマンドを実行するシェルスクリプトを作成します。
#!/bin/sh
. "$1"
exec /usr/bin/env -i "$Shell" -c ". $1; $2"
使用する:
run-as-cron <cron-environment> <command>
例えば.
run-as-cron /home/username/cron-env 'echo $PATH'
2番目の引数は、引数が必要な場合は引用符で囲む必要があることに注意してください。スクリプトの最初の行は、POSIXシェルをインタープリターとしてロードします。 2行目は、cron環境ファイルのソースです。これは、環境変数Shell
に格納されている正しいシェルをロードするために必要です。次に、(新しいシェルへの環境変数のリークを防ぐために)空の環境をロードし、cronjobsに使用されるのと同じシェルを起動して、cron環境変数をロードします。最後にコマンドが実行されます。
Crontabは仕事をしないので、その内容を操作します。
crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done
それがすること:
私が見たほとんどのデフォルトのcronデーモンのデフォルトでは、現時点でここで実行するようにcronに指示する方法はありません。 anacronを使用している場合は、フォアグラウンドで別のインスタンスを実行することもできます。
スクリプトが適切に実行されていない場合、それは考慮されていません
Crontab(5)から:
いくつかの環境変数は、cron(8)デーモンによって自動的に設定されます。シェルは/ bin/shに設定され、LOGNAMEとHOMEはcrontabの所有者の/ etc/passwd行から設定されます。 PATHは "/ usr/bin:/ bin"に設定されています。 HOME、Shell、PATHは、crontabの設定によって上書きされる場合があります。 LOGNAMEは、ジョブの実行元のユーザーであり、変更することはできません。
一般的にPATHが最大の問題なので、次のことを行う必要があります。
シェルなしの別のユーザー(www-dataなど)としてスクリプトを実行する必要がある場合は、Sudoを使用します。
Sudo -u www-data /path/to/crontab-script.sh
もちろん、その前に最初にテストすることは、スクリプトが実際にコマンドラインから実行することを想定していることです。コマンドラインから実行できない場合は、cronでは動作しません。
マルコのスクリプトは、なぜか私にはうまくいきませんでした。デバッグする時間がなかったので、Pythonスクリプトを書いて、同じことをしました。もっと長くなりましたが、最初に機能し、2つ目は、 「/ tmp/cron-env」を環境を保存した場所に変更します。
#!/usr/bin/env python
from __future__ import division, print_function
import sys
import os
def main():
if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
print("Usage: {} CMD\n"
"Run a command as cron would. Note that CMD must be quoted to be only one argument."
.format(sys.argv[0]))
sys.exit(1)
_me, cmd = sys.argv
env = dict(line.strip().split('=', 1) for line in open('/tmp/cron-env'))
sh = env['Shell']
os.execvpe(sh, [sh, '-c', cmd], env)
if __name__ == '__main__':
main()
シェルスクリプトの場合、これでほとんどの方法が得られます。
Sudo su # (assuming it's run as root, if not switch to the user you want it to run as)
cd # Switch to home folder
sh <full-path/my-Shell-script>
すべてではないにしても、いくつかの問題が明らかに強調されます。
Marcoの解決策は私にはうまくいきませんでしたが、Noamのpythonスクリプトは機能しました。Marcoのスクリプトを少し修正して、私にそれを機能させました。
#!/bin/sh
. "$1"
exec /usr/bin/env -i "$Shell" -c "set -a;. $1; $2"
追加されたset -a
スクリプト$ 1で定義された変数をエクスポートし、コマンド$ 2で使用できるようにしました
pS Noamのpythonは、環境を子プロセスに「エクスポート」したため、機能しました。
まあ、ユーザーはcrontabエントリに入力したユーザー(またはcrontabを交互に入力したユーザー)と同じなので、簡単です。 crontab
(5)を実行すると、環境変数セットのリストが表示されます。いくつかあります。
例えばのようなほとんどのcrontabではvixie-cronでは、このようにcrontab自体に変数を配置してから、/ usr/bin/envを使用して、機能しているかどうかを確認できます。このように、run-as-cronスクリプトの問題点を見つけたら、crontabでスクリプトを機能させることができます。
Shell=/bin/bash
LANG=en
FASEL=BLA
* * * * * /usr/bin/env > /home/username/cron-env
次の分を開始するようにジョブをプログラムできます:)
マルコの答えにうんざりしました。コードを以下に示しますが、このスクリプトは維持します here 。
このcrontabを考えると:
# m h dom mon dow command
X=Y
1 2 3 4 5 6 echo "Hello, world"
1 2 3 4 5 6 echo "Goodby, cruel world"
1 2 3 4 5 6 echo "Please spare me the drama"
使用セッションの例:
$ cronTest
This is the crontab for without comment lines or blank lines:
1 X=Y
2 echo "Hello, world"
3 echo "Goodby, cruel world"
4 echo "Please spare me the drama"
Which line would you like to run as now?
55
55 is not valid, please enter an integer from 1 to 4
2
Evaluating 1: X=Y
Evaluating 2: echo "Hello, world"
Hello, world
これは cronTest2
は、cronと同じ方法で環境変数を設定するために適切に呼び出す必要があります。
#!/bin/bash
# Prompt user for a user crontab entry to execute
function deleteTempFile {
rm -f $TEMP_FILE
}
function debug {
if [ "$DEBUG" ]; then >&2 printf "$1\n"; fi
}
function isValidLineNumber {
# $1 - number of lines
# $2 - requested line number
if [[ -n "${2//[0-9]+/}" ]] && (( $2 <= $1 )); then echo true; else echo false; fi
}
function isVariableAssignment {
[[ "$( echo "$1" | grep "=" )" ]]
}
function makeTempCrontab {
local -r ASTERISK=\\*
local -r NUMBER='[[:digit:]]{1,2}'
local -r NUMBERS="$NUMBER(,$NUMBER)+"
local -r CRON="^(($ASTERISK|$NUMBER|$NUMBERS)[[:space:]]+)"
local -r CRON5_REGEX="$CRON{5}"
local -r CRON6_REGEX="$CRON{6}"
rm -f "$TEMP_FILE"
local -r ALL_LINES="$( crontab -l )"
# Ignore empty lines and lines starting with # (comment lines)
local -r LINES="$(
echo "$ALL_LINES" | \
grep -v '^[[:space:]]*#' | \
grep -v '^[[:space:]]*$'
)"
if [[ -z "$LINES" ]]; then
echo "Your crontab is empty, nothing to do"
exit 1
fi
IFS=$'\n'
for LINE in $LINES; do
LINE="$( echo "$LINE" | sed 's/\s\+$//e' )" # remove trailing space
if [ "$( echo "$LINE" | grep "^$" )" ]; then
debug "" # ignore empty line
Elif [ "$( echo "$LINE" | egrep "$CRON6_REGEX" )" ]; then
debug "6 field date/time specifier: $LINE"
# strip out when to run debug, leaving just the command to execute
echo "$LINE" | cut -f 7- -d ' ' >> "$TEMP_FILE"
Elif [ "$( echo "$LINE" | egrep "$CRON5_REGEX" )" ]; then
debug "5 field date/time specifier: $LINE"
# strip out when to run debug, leaving just the command to execute
echo "$LINE" | cut -f 6- -d ' ' >> "$TEMP_FILE"
Elif [ "$( echo "$LINE" | grep '^@' )" ]; then
debug "@declaration: $LINE"
# strip out @declaration, leaving just the command to execute
echo "$LINE" | cut -f 2- -d ' ' >> "$TEMP_FILE"
Elif [ "$( echo "$LINE" | grep '=' )" ]; then
debug "Variable assignment: $LINE"
echo "$LINE" >> "$TEMP_FILE"
else
debug "Ignored: $LINE"
fi
done
unset IFS
}
function runUpToLine {
# Scans up to given line number in $TEMP_FILE
# Evaluates variable assignment
# Executes specified line
# Ignores remainder of file
# Function definitions are not supported
#
# $1 - line number to run
readarray CONTENTS < "$TEMP_FILE"
for (( i=0; i<=$1; i++ )); do
# >&2 echo "\$i=$i, \$1=$1, isVariableAssignment: $( isVariableAssignment $CONTENTS[$i] ), CONTENTS[$i]=${CONTENTS[$i]}"
if isVariableAssignment ${CONTENTS[$i]} || (( $i == $1 )); then
printf "\nEvaluating $(( i+1 )): ${CONTENTS[$i]}"
eval "${CONTENTS[$i]}"
fi
done
}
function selectLine {
>&2 echo "This is the crontab for $USER without comment lines or blank lines:"
cat -n "$TEMP_FILE" >&2
>&2 echo "Which line would you like to run as $USER now?"
local -r NUM_LINES=$( cat "$TEMP_FILE" | wc -l )
read LINE_NUMBER
# >&2 echo "NUM_LINES=$NUM_LINES, LINE_NUMBER=$LINE_NUMBER; valid: $( isValidLineNumber $NUM_LINES $LINE_NUMBER )"
while [[ $( isValidLineNumber $NUM_LINES $LINE_NUMBER ) == false ]]; do
>&2 echo "$LINE_NUMBER is not valid, please enter an integer from 1 to $NUM_LINES"
read LINE_NUMBER
# >&2 echo "NUM_LINES=$NUM_LINES, LINE_NUMBER=$LINE_NUMBER; valid: $( isValidLineNumber $NUM_LINES $LINE_NUMBER )"
done
(( LINE_NUMBER-- ))
echo ${LINE_NUMBER}
}
function doIt {
export USER=$1
local -r TEMP_FILE="$( mktemp crontabTest.XXX )"
trap deleteTempFile EXIT
makeTempCrontab
local -r LINE_NUMBER="$( selectLine )"
runUpToLine $LINE_NUMBER
}
doIt "$1"
cronTest
実行cronTest2
適切な環境変数を設定:
#!/bin/bash
# Execute a user crontab entry with the proper environment
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
env -i bash --noprofile --norc -c "$DIR/cronTest2 $USER"
@DjangoJannyの答えに触発されて、これが私が慣れているものですcrontab
の5行目でジョブを起動:
eval "$(crontab -l | sed -n '5p' | tr -s ' ' | cut -d' ' -f 6-)"
説明:
私はcronジョブを手動で実行する方法を見つけたことがありませんが、 this write-upは、cronjobと同じ環境を設定し、スクリプトを手動で実行することをお勧めします。