我有建立一個Linux環境做一些網路爬蟲的資料收集, 用的是在crontab建立定時排程, 執行python指令收集資料。已經收集好一段時間, 過程中也遇到一些狀況, 學習及調整, 今天把這些學到的內容和最新的做法, 做個筆記, 以免日後忘記了。
crontab的基本操作和設定就不在此說, 例如時間的定義- 在
crontab中存取檔案或叫用程式, 最好都加上完整路徑, 因為crontab執行時用的身份和前景使用者不同, 若沒指明路徑, 可能會無法正確找到檔案來執行 - stdout及stderr:
crontab執行的結果分為正常輸出和錯誤輸出, 在設定時也會用對應的代號來標示- stdout, 正常輸出, 用代號1表示
- stderr, 錯誤輸出, 用代號2表示
- 若要丟棄輸出結果, 可以指定給
1>/dev/null來表示, 這裡預設對象是正常輸出的代號1, 所以也可以簡單寫成>/dev/null - 若要把錯誤輸出一同寫到正常輸出的地方(檔案), 可以用
2>&1表示
- 在
crontab中, 可以用&&串接多個指令, 會由左至右依序執行, 但串接多個指令, 再加上以上寫到的標示完整檔案路徑, 以及輸出結果的標示, 會使指令很長, 不便於檢視, 另外也無法使用\做換行標示 - 在
crontab開頭可以宣告變數, 例如:PATH=/path/to/file, 在執行指令中就可以用$PATH來代表這個設定的變數值,crontab中的變數宣告, 不可指定動態變數值, 例如: 日期、時間 - 針對以上2點限制, 可以改成以
.sh指令檔來執行, 如下:- 把要執行的指令改寫到
.sh檔中 - 可以在
.sh開頭用source再引入另一個.sh檔 .sh中可以宣告動態變數值- 可以用
\來表示換行, 以便於編排成易於閱讀的樣式。\後面不要有多餘空白, 換行後的開頭也不要有多餘字元, 以免解析整串指令錯誤
- 把要執行的指令改寫到
#!/bin/bash
source /path/to/base.sh
LOG_FILE=data_$($PA/date +\%4Y-\%m-\%d).log
cd $REPO && $PA/git pull -q >/dev/null 2>>$LOG/$LOG_FILE \
&& $PA/git lfs lock $REPO/data.db >>$LOG/$LOG_FILE 2>&1
- 給予
.sh檔有執行權限
chmod +x /path/to/*.sh
- 最後再於
crontab中改成以.sh檔案執行, 整個清爽很多
更新: 2024-06-14
我會每日定時把當日排程執行的Log以e-mail發給自己, 方便自己可以收e-mail就知道執行結果, 而且無須連線到crontab執行的環境中。另外, 我是把log檔內容當成e-mail的內文來發送, 而不是當成附件。不過, 排程不是每日都有安排, 當沒執行時, 就不會產生log檔, 這時若還是發-email, 就會收到一封例外的e-mail, 如下:
/bin/sh: 列 1: /path/to/log/git_2024-06-12.log: 沒有此一檔案或目錄
因此上網查也問問ChatGPT, 在排程執行時如何同時檢查檔案是否存在的做法, 就如下, 加上 [ -e /path/to/log/file.log ] 的判斷, 另外, 加上如果沒有log檔案時簡單以echo指定內文發e-mail。這裡也要注意, 中刮號[ ]和其內容設定的前後都要隔一個空格, 不要貼著內容, 否則會被當成格式不正確。
0 19 * * * [ -e $LOG/git_$($PA/date +\%4Y-\%m-\%d).log ] && mail -s "crontab result" $MAILTO < $LOG/git_$($PA/date +\%4Y-\%m-\%d).log || echo "file not exists !" | mail -s "crontab result" $MAILTO
參考資料:
https://www.cnblogs.com/tinywan/p/6025468.html
https://unix.stackexchange.com/questions/711595/how-to-run-a-crontab-job-only-if-a-file-exists