我有一個計劃每天運行的 cron 作業,除了更改計劃之外,還有其他方法可以立即測試該命令以查看它是否按預期運行嗎?
編輯:(從評論中)我知道該命令在shell(我的shell)中輸入時工作正常,但我想知道cron 運行它時它是否正常工作,它可能會受到ENV 或shell 特定內容的影響(〜擴展)或所有權和許可的東西或......
答案1
您可以使用以下命令強制 crontab 運行:
run-parts /etc/cron.daily
答案2
您可以模擬 cron 使用者環境,如中所述“立即手動執行 cron 作業”。這將允許您測試作業以 cron 使用者身分執行時的工作情況。
摘自連結:
步驟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
答案3
據我所知,沒有辦法直接做到這一點,因為 cron 有一個特殊的目的 - 在特定時間運行計劃命令。因此,最好的方法是手動建立一個(臨時)crontab 條目或編寫一個刪除並重置環境的腳本。
“刪除並重置環境”的說明:
可以啟動包裝器腳本(這會刪除環境),該腳本將在啟動腳本之前env -i
取得已儲存的環境(確保匯出所有變量,可能會先進行設定)。set -a
保存的環境將是 cron 作業的預設環境,透過作為 cronjob運行env
(或取決於 cron 作業使用的 shell)來記錄,並保存其輸出。declare -p
答案4
在需要自己偵錯 cron 作業後,我編寫了以下腳本。在執行命令之前,它會盡力模擬與 cron 完全相同的條件(包括修改的環境,但它也與非互動式 shell、沒有附加終端等有關)。
使用您的命令/腳本作為參數來呼叫它,您可以立即輕鬆地偵錯您的 cron 作業。它還託管(並可能更新)在 GitHub 上:run-as-cron.sh
:
#!/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 redirect the output into files
# and provide /dev/null as input
# (so that the command is executed without an open terminal
# on any standard file descriptor)
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"