Python 執行Shell 外部命令
- 2020 年 1 月 7 日
- 筆記
1、os.system() 此方法執行的外部程式,會將結果直接輸出到標準輸出。os.system的返回結果為執行shell 的 $? 值。 因此請執行沒有輸出結果的程式時適合使用此方法。如touch 、rm 一個文件等。
In [1]: import os In [2]: os.system('touch test.txt') Out[2]: 0 In [3]: os.system('rm -rf test.txt') Out[3]: 0
2、os.popen() 此方法結合了os.system和 文件的特性。可以解決os.system那種無法獲取程式執行結果的缺點 os.popen 返回了一個類似與文件句柄的東西。可以對這個返回的結果做一些類似於對文件的操作
In [6]: output = os.popen('cat /etc/passwd') In [7]: for line in output.readlines(): ...: print line.strip() ...: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin
可以help(output) 獲取相關幫助去操作這個output
3、commands 模組 這個模組主要提供了三個方法: (1)、getoutput(cmd) Return output (stdout or stderr) of executing cmd in a shell. 返回一個shell 命令的標準輸出或者時錯誤輸出
In [17]: commands.getoutput('ls /home -l') Out[17]: 'total 4ndrwxr-xr-x 31 admin admin 4096 5xe6x9cx88 3 09:48 admin' In [18]: commands.getoutput('ls /homeaaa -l') Out[18]: 'ls: cannot access /homeaaa: No such file or directory'
(2)、getstatus(file) Return output of "ls -ld <file>" in a string. 獲取一個文件的狀態。 相當於執行了 ls -ld file
In [25]: commands.getstatus('/bin/ls') Out[25]: '-rwxr-xr-x 1 root root 110080 3xe6x9cx88 24 2014 /bin/ls' // 相當於執行了 ls -ld /bin/ls In [26]: os.system('ls -ld /bin/ls') -rwxr-xr-x 1 root root 110080 3月 24 2014 /bin/ls
(3)、getstatusoutput(cmd) Return (status, output) of executing cmd in a shell. 返回shell 的狀態碼和輸出結果
In [20]: commands.getstatusoutput('ls /home -l') Out[20]: (0, 'total 4ndrwxr-xr-x 31 admin admin 4096 5xe6x9cx88 3 09:48 admin') In [21]: commands.getstatusoutput('ls /homeaa -l') Out[21]: (512, 'ls: cannot access /homeaa: No such file or directory')
4、subprocess 相關模組. 從這個模組的幫助中可以看到。它的一個很主要的目的就是要替代掉os.system 、os.spawn*、os.popen*、popen2.* 、commands.* 這些模組的功能
subproces 模組中一個很強大的類Popen,我們的主要學習重點應該在於此 class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): args: 可以是一個字元串 或者是一個序列(list | tuple )。其實字元串也是序列呀。呵呵,我們這裡就講序列認為時list 和 tuple 了吧。若是序列時,則第一個元素為可執行的命令
在unix 系統中, shell=Ture 和 shell=False(默認) 和 args 參數有一定的影響關係。
看一下下面的列子: subprocess.Popen(["cat","/etc/passwd"]) subprocess.Popen("cat /etc/passwd") 我們看看以上這兩種寫法是否OK
In [29]: subprocess.Popen(["cat","/etc/passwd"]) root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync In [30]: subprocess.Popen("cat /etc/passwd") --------------------------------------------------------------------------- OSError Traceback (most recent call last)
第一種寫法OK。第二種寫法不OK。這是什麼原因呢? 主要時 shell=False(默認值) 這個參數搞的鬼。
在UNIX中, shell=False 時 subprocess.Popen() 使用os.execvp()去執行響應的子程式。 當 args 是一個字元串的時候,Popen 認為這個字元串是序列中的第一個元素(可執行的程式)。
調用 os.execvp()的時候 ,到$PATH 中去找這個可執行程式,沒有找到,所以程式出現了異常。 不過這也分命令,若寫成如下的形式: subprocess.Popen("/bin/pwd")
In [32]: subprocess.Popen("/bin/pwd") /home/dexin/python/tcollector
以上這個就無所謂了。 不過就是想讓 subprocess.Popen("cat /etc/passwd") 能夠正確的去執行,應該怎麼辦呢? 設置 shell=True .這樣當再執行類似的程式時,會調用相應的shell 去做 shell -c "cat /etc/passwd"
subprocess.Popen("cat /etc/passwd",shell=True) Out[33]: <subprocess.Popen at 0x7f922a6b2350> In [34]: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
