python好庫之sh
來自專欄 python取經小分隊
一直以來linux命令也只是用到時去查一下, 但是當看到比較大的bash 腳本時就有點畏縮了,但是在linux下工作調用命令還是必須的,終於找到一種解決方案,通過sh可以像調用函數一樣調用linux下系統命令.
先看一段shell腳本:
對於bash的一些語法斷斷續續看過一點,但是時間一長就給忘記了. 像上面的腳本看懂總是有點累啊,而且不是那麼pythonic. 下面就開始介紹一下可以用python去寫bash的方式.
sh庫簡介
sh將系統的命令動態映射到python函數,通過python的方式去寫shell腳本.
安裝pip install sh
基本使用
(1)獲取網路介面信息:
import shprint sh.ifconfig("eth0")# 或者from sh import ifconfigprint ifconfig("eth0")
輸出:
eth0 Link encap:Ethernet HWaddr 00:16:3e:00:13:d7 inet addr:10.162.223.199 Bcast:10.162.223.255 Mask:255.255.240.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:71475 errors:0 dropped:0 overruns:0 frame:0 TX packets:78854 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:51051493 (51.0 MB) TX bytes:6101887 (6.1 MB)
(2)列印目錄信息:
sh.ls("/home", "-l")
輸出:
total 8drwxr-xr-x 2 root root 4096 Nov 4 10:52 a-rw-r--r-- 1 root root 88 Nov 4 10:54 a.txt
關鍵字參數
當命令里需要參數時,sh調用表現方式會像你期望的一樣.下面是一個下載頁面到本地文件的命令:
curl https://www.baidu.com -o page.html --silent
對應的sh方式為:
sh.curl("https://www.baidu.com", o="page.html", silent=True)
查找命令
可以利用which檢測命令是否存在:
>>> sh.which("python") /usr/bin/python>>> print sh.which("ls") /bin/ls
安裝不存在命令:
if not sh.which("supervisorctl"): sh.apt_get("install", "supervisor", "-y")
烘焙(Baking)
其實就是類似於函數綁定,將參數綁定到函數上.
from sh import lsls = ls.bake("-la")print(ls("/home")) # 這樣默認就加上了選項-la
輸出為:
total 16drwxr-xr-x 3 root root 4096 Nov 4 10:54 .drwxr-xr-x 22 root root 4096 Oct 11 17:34 ..drwxr-xr-x 2 root root 4096 Nov 4 10:52 a-rw-r--r-- 1 root root 88 Nov 4 10:54 a.txt
例子
下面簡單去實現一個例子(安裝nginx並啟動),更直觀的看到sh的便利(環境含有pip):
# -*- coding: utf8 -*-import subprocessdef install_sh(): try: retcode = subprocess.call("pip install sh", shell=True) return retcode except OSError as e: return "Execution failed:", etry: import shexcept ImportError: install_sh() import sh# ps -auxc | grep nginxdef is_nginx_running(): r = sh.grep(sh.ps("-auxc"), "nginx", _ok_code=[1, 2, 3]) return r.exit_code == 0def install_nginx(): if not sh.which("nginx"): print "nginx not exist, will install" sh.apt_get("install", "nginx", "-y") else: print "nginx has installed"def start_nginx(): r = sh.service("nginx", "start", _ok_code=[1, 2, 3]) if r.exit_code == 0: print "start success" else: print "start failed"if __name__ == "__main__": if not is_nginx_running(): install_nginx() start_nginx() else: print "nginx is running"
可以點擊這裡下載
原理
一開始我還以為sh里實現了像ls、curl等命令,當打開源碼才發現是沒有的. 那麼當執行sh.ls時為何沒報錯呢?下面來探索一下:
在python中有一種我們不常用的類型ModuleType. 如下:
>>> import types >>> types.ModuleType<type module>
我們導入的模塊都是module這種類型. 下面演示一下sh的基本實現:
import sysfrom types import ModuleTypeclass SelfWrapper(ModuleType): def __init__(self, self_module): self.self_module = self_module def __getattr__(self, name): return "fetch command:", nameif __name__ == "__main__": passelse: self = sys.modules[__name__] sys.modules[__name__] = SelfWrapper(self)
這裡是將導入的模塊替換為我們自己定義的模塊. 將上面代碼保存為sh_test.py,然後就可以使用:
>>> import sh_test>>> print sh_test.ls(fetch command:, ls)
當我們去訪問模塊不存在的屬性是,會調用__getattr__方法. 這只是簡單的分析了一下sh基本原理, 更多的可以自己去看源碼source
參考
how-to-use-sh-in-python
sh
分析一個python庫--sh
推薦閱讀:
※在Bash中按Ctrl-S為什麼會失去響應?
※什麼是 .bashrc,為什麼要編輯 .bashrc? | Linux 中國
※4 種繞過 Linux/Unix 命令別名的方法
※Linux編程之變數1:bash變數與變數分類-1
※如何評價 Windows 版「bash」(及其相關 *nix 子系統)?