
我們有一個腳本用於將一些目錄同步到 USB 磁碟機。它設定為每天運行一次,但通常需要更長的時間。
為了確保腳本的多個副本不會同時運行,我們檢查進程列表,如果腳本存在,我們立即退出。
#!/bin/bash
#check if we are already running
running=$(ps aux | /usr/bin/grep -i "usb_sync" | /usr/bin/grep -v grep | /usr/bin/grep -c bash)
echo "usb_sync $running" >/opt/local/backup/usb_sync_log
#If we are, the quit
if [ $running -gt 1 ] ; then
exit 0
fi
問題是,當透過 sudo 運行並透過 CLI 手動呼叫時,此檢查工作正常。然而,當它通過 cron 運行時,它無論如何都會啟動。我嘗試了幾種不同的變體,但它們似乎都可以運行。
這是在 FreeNAS 11.2 上。
答案1
文件pid
是防止腳本多次執行的常用方法。它可以這樣使用:
#!/bin/bash
PIDFILE=/home/vagrant/forever.pid
if [ -f $PIDFILE ]
then
PID=$(cat $PIDFILE)
ps -p $PID > /dev/null 2>&1
if [ $? -eq 0 ]
then
echo "Process already running"
exit 1
else
## Process not found assume not running
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
else
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
sleep 25d
rm $PIDFILE
sleep 25d
實際要執行的命令在哪裡。我建議閱讀此內容部落格文章深入解釋處理此問題的各種方法。上面的腳本取自那裡。
應檢查使用者執行 cron 檔案中設定的腳本的存取權限。當前腳本也可能無法識別腳本是否已在執行,因為存取權限不夠。無論如何,使用 pid 檔案似乎是處理此問題的更好且不易出錯的解決方案。
答案2
可以做得更容易。建立一個標誌檔案。在腳本的開頭可能會使用:
## Basic config
SCRIPTNAME=$(basename "$0")
RUNFILE="${SCRIPTNAME}.run"
# 25h in seconds adjust to your needs.
MAX_AGE=90000
# check for running process
if [ -f "$RUNFILE" ]; then
echo "process still running - exit"
if [ $(( $(date +%s) - $(date +%s --reference $RUNFILE) )) -gt ${MAX_AGE} ]; then
rm $RUNFILE;
else
exit
fi
fi
touch $RUNFILE
<your code>
rm ${RUNFILE}
運行檔案的內容可以是正在運行的進程的PID。有進程正在運行會更容易分析。
代替
touch ${RUNFILE}
使用
echo $$ >${RUNFILE}