Linux Crontab自動化排程,執行Python/R程式
誰需要這篇文章
你可能會寫程式,但伺服器管理不是你的專業,甚至對Linux零經驗,不知道Ubuntu和Linux有什麼關係,也不知道Cron和Crontab哪裡不一樣。可是人生總有意外,可能是管Server的人離職了,維護廠商不續約了,或是你和IT的大大吵架了,他丟了一組帳號密碼給你,叫你自己搞定Linux上的自動化排程。
或是你和我一樣,是搞資料科學的數據分析師,經常需要自動化執行某些程式,可能是常態性的資料計算,也可能是要爬取網路上的資料。面對這種高頻率操作的情況,如果每次都要請IT幫忙,確實苦了自己,也難為別人,而且數據分析使用的Pyton、Anaconda、Jupyter確實也不是IT會熟悉的工具。與其大眼瞪小眼,相看兩不厭,倒不如靠自己,自立自強。只要不把Server弄壞,把資料庫刪除,一切都好談。
網路上雖然有許多Linux的教學文章,Stack Overflow上也有許多熱心網友的問與答,但我認為大部份資訊過於片面,必須拼拼湊湊多篇文章,才能練成Crontab即戰力。這是我曾經遭遇的難關,也是我寫這篇文章的主要目的。另外,這篇文章假設的情境是你有一台功能正常的Server,而且Server上已經裝好了Python或R,你所需要的只是把排程掛到Server上。
出發前再次溫馨提醒,我是搞資料科學的數據分析師,以下資料不保證完全正確,很多概念我也是一知半解,但我會盡量附上我查到的內容及關鍵字。內容如有錯誤,還請不吝指教。
一、連線到Server
要操作Server,首先當然必須透過遠端連線(Remote)控制這台機器,而不是傻傻的走進機房,放包新的綠色乖乖就可以搞定。
要連線到Server,你必須取得兩樣東西,一個是IP與帳號密碼,一個是遠端連線軟體。IP可能的型式會是「192.168.0.1:1225」,冒號後面的數字不能省略。遠端連線軟體(VNC)我推薦UltraVNC,你可以下載它的免安裝中文版。如果你們公司對於軟體安裝的控管比較嚴格,那免安裝軟體會是一個不錯的選擇。
二、先測試你的Code能不能跑
成功連線到Server後,你應該會看到像是Window或Mac一樣的圖形化介面,四處點點看看,你應該可以快速理解大致的操作方式。接下來要做的事情是開啟Terminal,也就是輸入指令的地方,像是Windows中的cmd。
首先,請先確認你的Code可以正常運作,否則和Crontab奮戰老半天,結果發現是自己的程式有問題,你絕對會想掐死自己一百次。建議你可以寫一段小小的程式,只要成功執行時就會匯出一個txt或csv檔,方便檢查。
執行方式是在Terminal中輸入以下指令:
python [程式路徑]
python /home/aron/test.py
如果程式可以順利執行,也成功的匯出檔案,那我們可以進到下一步。
三、檢查帳號及舊排程
Linux新手通常會對帳號權限的概念較陌生。和Windows一樣,Linux中也可以新增多個帳號,每個帳號的權限不同,而且Linux可以直接在Terminal中切換帳號,不必反覆登出再再入。可以參考鳥哥的Linux私房菜 — Linux 帳號管理與 ACL 權限設定。
如果你的Server名字叫pyserver,在Terminal中,aron@pyserver代表你是用aron這個帳號進行操作,hack@pyserver則則代表你是用hack這個帳號進行操作,不同帳號能操作的crontab排程會不一樣。如果你的前人已經在Server上掛了一些排程,為了方便管理,你想讓所有排程都掛在同一個帳號底下,建議你檢查現有排程,指令如下:
crontab -l
如果你發現目前帳號的排程是空的,想切換至另一個帳號,可以輸入以下指令:
su -p [account]
Ex: su -p hack
Enter之後必須再輸入密碼,才能夠確實切換到另一個帳號。
四、掛排程
編輯Crontab
接下我們要正式新增Crontab排程。首先,輸入以下指令進入Crontab的編輯模式。進入編輯模式後,可以按鍵盤上的Insert鍵,切換Insert或Replace模式。
crontab -e
排程格式
Crontab的排程格式如下:
[分 時 日 月 週][程式類型][程式路徑]
舉例來說,以下路徑會在每天晚上的23:00執行project.py這個python腳本。請注意,該空格的地方要有空格,否則可能會造成排程失敗。
0 23 * * * python /home/aron/project.py
另外,也可以將格式調整如下,代表每5分鐘會執行一次。
*/5 * * * * python /home/aron/project.py
當然也可以替換成R語言的檔案。
*/5 * * * * Rscript /home/aron/project.R
你可以使用#在Crontab中寫註解寫註解。為避免編碼錯誤,路徑與檔案名稱盡量避免使用中文。
存檔
編輯完成後,按Esc退出Insert/Replace,並輸入以下指令結束編輯並存檔。
:wq
完成存檔後,你可以觀察一下排程是否有順利執行。如果成功,那恭喜你功德圓滿,你可以直接關掉這個網頁;如果失敗,沒關係,我也是在這裡卡關的,請繼續往下閱讀。
六、檢查Log
除錯的第一步,先檢查log檔,確認Crontab是否有嘗試要執行排程。Stack Exchange上列出了很多種檢查log的方法,老實說,我也不是很懂每一個的差異在哪裡,但我是透過以下指令成功檢查的。
grep CRON /var/log/syslog
檢視log檔必須要有足夠的權限,如果你使用的Linux帳號權限不足,會出現Permission Denied之類的訊息。
另外,我的log中也出現以下訊息「No MTA installed, discarding output」,這部份可以參考Stack Exchange上的討論,但應該不用理它。
如果你新增的排程沒有出現在log中,那可能是格式有錯,或是根本設錯時間,請檢查你的排程格式是否有錯。假如看起來一切正常,我們繼續往下debug。
七、檢查Python/R的安裝路徑
上面提到的排程格式如下:
0 23 * * * python /home/aron/project.py
我猜測,出錯的原因可能是Crontab沒辦法直接使用python這個指令來執行python檔。所以應該將指令調整為:
0 23 * * * [python的安裝路徑] /home/aron/project.py
問題來了,我們要怎麼知道python安裝在哪裡?先讓我們休息一下,先來談談Python Interactive Shell。
Interactive Shell
Interactive Shell是讓你可以在Terminal或cmd中寫Python的模式,使用的方法是在Terminal或cmd中輸入python,就這麼簡單,進入後會看到以下畫面。
你可以在Interactive Shell中輸入以下程式,取得Python的安裝路徑:
import sys
sys.path
雖然看起來有很多個路徑,但最像的只有一個,也就是上圖中的/opt/anaconda3/lib/pathon3.8。
你的Python路徑可能和我不同,像是/home/anaconda3/lib/python3.8之類的,往下的步驟務必用你自己的路徑執行。到這裡,你可以輸入quit(),或直接按Ctrl+D結束Interactive Shell。
事情還沒有結束,請把上面取得的路徑再輸入到Terminal中,如果你可以再次進入Interactive Shell,代表這確實是我們需要的路徑,但你很可能會得到「is a directory」。
不要灰心,我們已經非常接近真相了,至少我們知道Python安裝的大致路徑。你可以把上面的/opt/anaconda3/lib/pathon3.8改成/opt/anaconda3/bin/python,然後再丟回Terminal測試,如果可以進入Interactive Shell,Bingo,這就是我們需要的Python安裝路徑。
調整排程格式
接下來只剩最後一步,把Crontab排程修改成正確路徑如下:
0 23 * * * /opt/anaconda3/bin/python /home/aron/project.py
執行到這裡,理論上Crontab應該可以正常運作了,如果真的還是失敗,可能需要重新啟動Crontab,或採取其他作法,但請審慎評估風險,或參考〈Why is my crontab not working, and how can I troubleshoot it?〉 。
PythonAnywhere的排程
如果你和我一樣是PythonAnywhere的使用者,在PythonAnywhere上的Task也可以執行自動化排程,用法與Crontab類似,主要差別在於PythonAnywhere上可以執行多種版本的Python,因此,在新增Task的時候,也必須指定Python版本,範例加下:
python3.7 /home/aron/project.py