Python和shell script是目前編寫腳本類應用的不二之選,在糾結使用Python還是shell script時,希望本文能夠提供一些思路。
Python和shell script對比
Python最突出的優(yōu)勢在于語言相對簡單,熟悉的人多,支持json解析等高級語言特性。
shell的優(yōu)勢在于特定場景下代碼更簡練,ps,grep,awk,sed,tar等命令一行能夠搞定的場景,如果用python原生代碼來實現(xiàn)相對會比較復雜,而且往往還需要安裝第三方Python庫。
在部署方式上兩者區(qū)別都不大,python和shell大部分情況下使用“原生庫”即可搞定。
Python的原生庫subprocess支持調(diào)用shell script命令,選擇Python + subprocess庫的方案可以結合兩者的優(yōu)勢,這是我為什么推薦用Python代替shell腳本的原因
subprocess注意事項
兼容性
subprocess庫有多個版本,需兼容不同的版本。核心代碼如下:
def check_output(cmd):
"""
execute shell commandline, return output
:param cmd: commandline string
:return:
output string: empty string if output nothing. For shell command, the output has a "\n" in the end generally.
None: failed to execute the commandline, do not use None to judge whether the execution result is ok.
"""
if hasattr(subprocess, 'check_output'):
try:
p = subprocess.check_output(cmd, shell=True)
if isinstance(p, bytes):
return p.decode()
else:
return p
except subprocess.CalledProcessError as e:
print(e)
return None
else:
# python version < 2.7
try:
output = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True).communicate()[0]
return output
except subprocess.CalledProcessError as e:
print(e)
return None
grep命令的返回值
grep查找失敗時,subprocess在python3中會直接拋出異常,這與shell的習慣不同。以如下代碼舉例:
if grep abc check_process.sh ;
then
echo good
fi
這是shell中的典型寫法,判斷check_process.sh文件中是否存在abc字符串,使用subprocess實現(xiàn)的話,代碼一般如下:
if __name__ == "__main__":
r = check_output("grep abc check_process.sh")
if "abc" in r:
print "good"
當grep查找失敗時,返回值是1。在python3中會拋出異常,返回None,而不是空字符串,此時在命令尾部增加 “|| true”即可,請注意在這種情況下,即使命令執(zhí)行失敗也不會返回None,比如check_process.sh不存在時也會返回空字符串。
r = check_output("grep abc check_process.sh || true")
非預期輸出
命令的輸出會與腳本輸出混雜在一起,比如grep的結果會直接輸出到stdout。我們當然可以通過重定向到/dev/null的方式來處理,但是總會有漏網(wǎng)之魚。如果腳本最終要輸出格式化的數(shù)據(jù),建議輸出到文件中,而不是stdout。
最佳實踐推薦
- Python中調(diào)用subprocess集成shell腳本
- 使用單元測試
- 使用getopt庫處理入?yún)?/li>
- 支持格式化輸出,比如json。結果輸出到文件,而不僅僅是stdout。
- 關注腳本的退出code, sys.exit()返回值應體現(xiàn)出腳本執(zhí)行結果。
如果對你有幫助,請順手點個贊