Python中 configparser 模塊用於讀取和編輯配置文件,更多的是用於讀取配置文件。配置文件的格式以下,能夠包含多個section(例如:db,email),每一個section又能夠有多個鍵值對(例如:database=bps);其中 '=' 也可使用 ':' 取代~python
[default] log_path=/tmp/csv.log [db] host=192.168.1.20 database=bps user=bps password=123456 [email] smtp_server=1.2.3.4 smtp_port=587 mailfrom=kitty@163.com mailfrom_pass=123456
生成如上示例的配置文件:shell
import configparser config = configparser.ConfigParser() config['default'] = {'log_path': '/tmp/csv.log'} config['db'] = {'host': '192.168.1.20', 'database': 'bps', 'user': 'bps', 'password': '123456'} config['email'] = {'smtp_server': '1.2.3.4', 'smtp_port': '587', 'usmailfromer': 'kitty@163.com', 'mailfrom_pass': '123456'} # 寫入到配置文件,執行 config.ini 配置文件的路徑爲當前路徑~ with open(file='config.ini',mode='w') as f: config.write(f)
執行後,在當前目錄下,能夠看到已生成的 config.ini 文件:
緩存
文件內容以下:
ide
更多的時候,咱們是手動編輯配置文件,在程序運行時讀取配置信息。函數
config = configparser.ConfigParser() print(config.sections()) # [] # 讀取配置文件 config.ini config.read('config.ini') # 打印 config.ini 文件中的全部 section,以列表的形式返回 print(config.sections()) # ['default', 'db', 'email'] # 判斷指定的 section 是否存在 print('email' in config) # True print('log_path' in config) # False # 或 print(config.has_section('email')) # True print(config.has_section('log_path')) # False # 打印 config.ini 文件中 指定 section 下的全部 option,以列表的形式返回 print(config.options('email')) # ['smtp_server', 'smtp_port', 'usmailfromer', 'mailfrom_pass'] # 判斷 指引的 option 是否存在 print('log_path' in config['default']) # True # 或 print(config.has_option('email', 'abc')) # False # 打印 config.ini 文件中 指定 section 下的全部 鍵值對 print(config.items('db')) # [('host', '192.168.1.20'), ('database', 'bps'), ('user', 'bps'), ('password', '123456')] # 獲取 config.ini 文件中 指定 section 下的指定 option 的值,以字符串的形式返回 print(config.get('email', 'smtp_server')) # 1.2.3.4 # 或 print(config['email']['smtp_server']) # 1.2.3.4
遍歷指定 section 下的全部key工具
for key in config['db']: print(key) 結果輸出: host database user password
除了讀寫操做,還能夠對已有的配置文件進行編輯。code
config = configparser.ConfigParser() # 讀取配置文件 config.read('config.ini') # 增長一個section if not config.has_section('sftp'): config.add_section('sftp') # 刪除一個section config.remove_section('email') # 添加一個 option if not config.has_option('sftp', 'sftp_server'): config.set('sftp', 'sftp_server', '4.3.2.1') # 刪除一個 option config.remove_option('db', 'database') # 修改一個 option if config.has_option('db', 'user'): config.set('db', 'user', 'baby')
注意:以上這些操做只發生在內存中,若要使文件改變,還須要寫入到文件中server
with open(file='config.ini', mode='w') as f: config.write(f)
再次查看文件,文件內容已經發生修改:
對象
subprocess 模塊用於執行外部命令。在python中,可使用標準庫中的 subprocess模塊 來fork一個子進程,而後使用子進程執行外部命令。主程序能夠經過 subprocess模塊 提供的一些管理標準流(standard stream) 和 管道(pipe) 的工具來獲取外部命令的執行結果,以及子進程的執行狀態碼~blog
os.system() 會打開一個子shell(子進程)來執行系統命令,命令的執行結果會輸出到stdout,也就是直接打印到終端,方法會返回狀態碼,以下所示:
import os return_code = os.system('ls -l /tmp') print(return_code) # 輸出結果: lrwxr-xr-x@ 1 root wheel 11 Sep 25 20:16 /tmp -> private/tmp 0
os.popen() 的執行會將外部命令的執行結果輸出到管道,方法返回一個鏈接管道的文件對象。若是外部命令執行成功,則不會返回狀態碼,若執行失敗,錯誤信息會輸出到stdout(即直接打印到終端),並返回一個空字符串。操做該文件對象的方式與普通的讀寫文件操做一致,以下示例:
import os f = os.popen('cat /Users/James/abc') print(f.readlines()) # 輸出結果: ['hello\n', 'kitty\n']
和 subprocess模塊 同樣,以上兩種方式也能夠用來執行外部命令,可是這兩個方法過於簡單,不能完成複雜的操做,例如管理命令的輸入輸出,獲取命令的運行狀態等~,subprocess 模塊能夠知足這些需求,因此如官方建議,使用subprocess模塊來生成新進程並獲取結果是更好的選擇。
在 subprocess 模塊中,有不少個函數,這些函數都有各自的方式建立子進程,執行外部命令~
run方法 會直接輸出命令的執行結果,並返回 CompletedProcess 對象
code = subprocess.run(["df","-h"]) # 輸出命令的執行結果 print(code) # CompletedProcess(args=['df', '-h'], returncode=0) # 獲取命令的狀態碼 print(code.returncode) # 0
call方法 會直接輸出命令的執行結果,並返回 狀態碼
res = subprocess.call(["ls","-l"]) # 輸出命令的執行結果 # 獲取命令的狀態碼 print(res) # 0
check_call 方法內部其實調用了call方法,當狀態碼爲0時,同call方法一致,若狀態碼不爲0,則拋出 CalledProcessError 異常
res = subprocess.check_call(["ls","-l"]) print(res) # 0
check_output方法 接收的參數只能是一個沒有參數的外部命令,返回執行的結果,內部實現方式是調用了 run 方法
res = subprocess.check_output("pwd") print(res) # 即返回當前路徑
getstatusoutput方法 接受字符串形式的命令,返回 一個元組形式的結果,第一個元素是命令執行狀態,第二個爲執行結果
res = subprocess.getstatusoutput('ls -l /tmp') print(res) # (0, 'lrwxr-xr-x@ 1 root wheel 11 Sep 25 20:16 /tmp -> private/tmp')
若執行錯誤,則一樣會返回錯誤信息
res = subprocess.getstatusoutput('abc') print(res) # 結果輸出: (127, '/bin/sh: abc: command not found')
getoutput方法 接受字符串形式的命令,返回執行結果,不會返回狀態碼
res = subprocess.getoutput('ls -l /tmp/') print(res) # 結果輸出: total 8 ...... ...... -rw-r--r-- 1 baby wheel 446 Dec 21 14:14 csv.log drwxr-xr-x 2 root wheel 64 Dec 19 15:03 powerlog
以上這些方法都是直接或者間接的調用了subprocess.Popen 方法,建議在使用過程當中直接使用 subprocess.Popen 方法~
res = subprocess.Popen("cat /etc/passwd", shell=True) # 結果輸出(即 /etc/passwd 文件的內容): ## # User Database ... ## nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false root:*:0:0:System Administrator:/var/root:/bin/sh daemon:*:1:1:System Services:/var/root:/usr/bin/false ...... ......
subprocess.Popen 方法建立的子進程執行外部命令後,會將返回結果 輸出到 stdin/stdout/stderr 中,這樣會直接打印到終端。也能夠將返回信息寫入到一個緩存區(或稱之爲管道),主進程從緩存區中讀取子進程的返回信息~
res = subprocess.Popen("cat /tmp/csv.log", shell=True, stdout=subprocess.PIPE) print(res.stdout.read()) # 結果輸出: b'abc\n'
將正確輸出和錯誤輸出都寫入到緩存區中
res = subprocess.Popen("lm /tmp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(res.stdout.read()) # b'' print(res.stderr.read()) # b'/bin/sh: lm: command not found\n'
也能夠利用 subprocess.PIPE 將多個子進程的輸入和輸出鏈接在一塊兒,構成管道(pipe),即 s1 的輸出結果做爲 s2 的輸入信息:
s1 = subprocess.Popen(["cat", "/etc/passwd"], stdout=subprocess.PIPE) s2 = subprocess.Popen(["grep", "0:0"], stdin=s1.stdout, stdout=subprocess.PIPE) out = s2.communicate() print(out) # 輸出結果: (b'root:*:0:0:System Administrator:/var/root:/bin/sh\n', None)
其中的 communicate() 方法下面會介紹~
注意::運行 subprocess.Popen() 後,主進程不會等待子進程執行完畢,而是會繼續往下執行~
poll 方法用於判斷子進程是否執行完畢,若沒有執行完畢返回 None,如果執行完成,返回 執行狀態碼~
res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(res.poll()) # None time.sleep(6) print(res.poll()) # 0
wait方法 會等待命令執行完成(即主進程阻塞),而且返回 執行狀態碼~
res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 等待子進程執行完畢,並返回狀態碼 print(res.wait()) # 0
terminate方法能終止正在運行中的子進程
res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) res.terminate() # 子進程被終止後,沒有返回信息 print(res.stdout.read()) # b''
pid 爲 subprocess.Popen 對象的一個變量,保存了子進程的進程號
res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(res.pid) # 36777
執行 communicate 方法後,主進程會等待(主進程阻塞)子進程運行完畢,並從 subprocess.PIPE 中會獲取子進程的返回信息,返回一個tuple(標準輸出和錯誤輸出)
res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(res.communicate()) # 主進程執行到這一步,再也不繼續往下執行,會等待子進程運行完畢~ # 錯誤輸出 res = subprocess.Popen("lm -l", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(res.communicate()) # 結果輸出: (b'end\n', b'') (b'', b'/bin/sh: lm: command not found\n')
.................^_^