Python 作為一種指令碼語言,可以非常方便地用於系統(尤其是*nix系統)命令列工具的開發。Python 自身也整合了一些標準庫,專門用於處理命令列相關的問題。
命令列工具的一般結構
1. 標準輸入輸出
*nix 系統中,一切皆為檔案,因此標準輸入、輸出可以完全可以看做是對檔案的操作。標準化輸入可以通過管道(pipe)或重定向(redirect)的方式傳遞:
1 2 3 4 5 |
# script reverse.py #!/usr/bin/env python import sys for l in sys.stdin.readlines(): sys.stdout.write(l[::-1]) |
儲存為 reverse.py
,通過管道 |
傳遞:
1 2 3 4 5 6 7 |
chmod +x reverse.py cat reverse.py | ./reverse.py nohtyp vne/nib/rsu/!# sys tropmi :)(senildaer.nidts.sys ni l rof )]1-::[l(etirw.tuodts.sys |
通過重定向 傳遞:
1 2 |
./reverse.py reverse.py # 輸出結果同上 |
2. 命令列引數
一般在命令列後追加的引數可以通過 sys.argv
獲取, sys.argv
是一個列表,其中第一個元素為當前指令碼的檔名:
1 2 3 4 |
# script argv.py #!/usr/bin/env python import sys print(sys.argv) # 下面返回的是 Jupyter 執行的結果 |
1 |
['/Users/rainy/Projects/GitHub/pytips/venv3/lib/python3.5/site-packages/ipykernel/__main__.py', '-f', '/Users/rainy/Library/Jupyter/runtime/kernel-0533e681-bd7c-4c4d-9094-a78fde7fc2ed.json'] |
執行上面的指令碼:
1 2 3 4 5 6 |
chmod +x argv.py ./argv.py hello world python argv.py hello world # 返回的結果是相同的 # ['./test.py', 'hello', 'world'] |
對於比較複雜的命令列引數,例如通過 --option
傳遞的選項引數,如果是對 sys.argv
逐項進行解析會很麻煩,Python 提供標準庫 argparse
(舊的庫為 optparse
,已經停止維護)專門解析命令列引數:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# script convert.py #!/usr/bin/env python import argparse as apa def loadConfig(config): print("Load config from: {}".format(config)) def setTheme(theme): print("Set theme: {}".format(theme)) def main(): parser = apa.ArgumentParser(prog="convert") # 設定命令資訊,用於輸出幫助資訊 parser.add_argument("-c", "--config", required=False, default="config.ini") parser.add_argument("-t", "--theme", required=False, default="default.theme") parser.add_argument("-f") # Accept Jupyter runtime option args = parser.parse_args() loadConfig(args.config) setTheme(args.theme) if __name__ == "__main__": main() |
1 2 |
Load config from: config.ini Set theme: default.theme |
利用 argparse
可以很方便地解析選項引數,同時可以定義指定引數的相關屬性(是否必須、預設值等),同時還可以自動生成幫助文件。執行上面的指令碼:
1 2 3 4 5 6 7 |
./convert.py -h usage: convert [-h] [-c CONFIG] [-t THEME] optional arguments: -h, --help show this help message and exit -c CONFIG, --config CONFIG -t THEME, --theme THEME |
3. 執行系統命令
當 Python 能夠準確地解讀輸入資訊或引數之後,就可以通過 Python 去做任何事情了。這裡主要介紹通過 Python 呼叫系統命令,也就是替代 Shell
指令碼完成系統管理的功能。我以前的習慣是將命令列指令通過 os.system(command)
執行,但是更好的做法應該是用 subprocess
標準庫,它的存在就是為了替代舊的 os.system; os.spawn*
。
subprocess
模組提供簡便的直接呼叫系統指令的call()
方法,以及較為複雜可以讓使用者更加深入地與系統命令進行互動的Popen
物件。
1 2 3 4 5 |
# script list_files.py #!/usr/bin/env python import subprocess as sb res = sb.check_output("ls -lh ./*.ipynb", shell=True) # 為了安全起見,預設不通過系統 Shell 執行,因此需要設定 shell=True print(res.decode()) # 預設返回值為 bytes 型別,需要進行解碼操作 |
1 2 3 4 5 6 7 |
-rw-r--r-- 1 rainy staff 3.4K 3 8 17:36 ./2016-03-06-The-Zen-of-Python.ipynb -rw-r--r-- 1 rainy staff 6.7K 3 8 17:45 ./2016-03-07-iterator-and-generator.ipynb -rw-r--r-- 1 rainy staff 6.0K 3 10 12:35 ./2016-03-08-Functional-Programming-in-Python.ipynb -rw-r--r-- 1 rainy staff 5.9K 3 9 16:28 ./2016-03-09-List-Comprehension.ipynb -rw-r--r-- 1 rainy staff 10K 3 10 14:14 ./2016-03-10-Scope-and-Closure.ipynb -rw-r--r-- 1 rainy staff 8.0K 3 11 16:30 ./2016-03-11-Arguments-and-Unpacking.ipynb -rw-r--r-- 1 rainy staff 8.5K 3 14 19:31 ./2016-03-14-Command-Line-tools-in-Python.ipynb |
如果只是簡單地執行系統命令還不能滿足你的需求,可以使用 subprocess.Popen
與生成的子程式進行更多互動:
1 2 3 4 5 6 |
import subprocess as sb p = sb.Popen(['grep', 'communicate'], stdin=sb.PIPE, stdout=sb.PIPE) res, err = p.communicate(sb.check_output('cat ./*', shell=True)) if not err: print(res.decode()) |
1 2 3 4 |
" "p = sb.Popen(['grep', 'communicate'], stdout=sb.PIPE)\n",n", " "# res = p.communicate(sb.check_output('cat ./*'))"n", "p = sb.Popen(['grep', 'communicate'], stdin=sb.PIPE, stdout=sb.PIPE)n", "res, err = p.communicate(sb.check_output('cat ./*', shell=True))n", |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!