執(zhí)行程序,獲取返回碼或輸出信息。
命令行參數(shù)可以用 shlex.split 分解成列表。
>>> from subprocess import *
>>> from shlex import split
>>> s = check_output(split("ls -l"))
>>> print s
total 0
drwx------+ 4 yuhen staff 136 1 11 07:40 Desktop
drwx------+ 10 yuhen staff 340 1 4 01:53 Documents
drwx------+ 4 yuhen staff 136 1 11 08:35 Downloads
drwx------@ 56 yuhen staff 1904 1 11 08:28 Library
drwx------+ 3 yuhen staff 102 9 22 15:20 Movies
drwx------+ 5 yuhen staff 170 1 9 19:37 Music
drwx------+ 5 yuhen staff 170 1 3 21:14 Pictures
drwxr-xr-x+ 4 yuhen staff 136 9 15 16:21 Public
如果需要獲取 ExitCode,又不想看到輸出信息??梢詫?stdout 重定位到 /dev/null。
>>> null = open(os.devnull, "w")
>>> call(split("ls -l"), stdout = null, stderr = null)
0
官方建議用 subprocess 代替 os.system、os.spawn、os.popen、popen2.、commands.這個傳統(tǒng)用法?;谝院笙?Python 3 遷移的需要,還是放棄所有打上 obsolete 標記的庫。
>>> from subprocess import Popen, PIPE
>>> Popen('find . -name "*.py" | xargs ls -l', shell=True).wait()
-rwxr-xr-x 1 yuhen staff 286 5 29 19:24 ./main.py
-rw-r--r-- 1 yuhen staff 76 6 7 17:49 ./test.py
可以用 PIPE 改變輸入輸出對象。
>>> p = Popen('find . -name "*.py" | xargs ls -l', shell=True, stdout=PIPE)
>>> p.pid
71474
>>> print p.stdout.read()
-rwxr-xr-x 1 yuhen staff 286 5 29 19:24 ./main.py
-rw-r--r-- 1 yuhen staff 76 6 7 17:49 ./test.py
>>> p.wait()
0
除使用簡便函數(shù)外,還可以創(chuàng)建 Popen 對象以獲取更細節(jié)的控制。subprocess 不能控制終端和 TTY 交互程序,建議使用第三方庫 Fabric 或 pexpect。進程信息可以用 psutil 獲取。
信號是軟中斷,提供了一種異步事件通知機制。Python 默認已經(jīng)安裝了一些信號處理器,比如 SIGPIPE 被忽略,SIGINT 引發(fā) KeyboardInterrupt 異常,捕獲 SIGTERM 調(diào)用退出函數(shù)。
常用信號
注意: 信號 SIGKILL、SIGSTOP 不能被捕獲。
signal
僅能在主線程調(diào)用 signal() 注冊信號處理器函數(shù),它會移除當前處理動作??捎?getsignal() 獲取,在需要時重新注冊。有兩個特殊的處理器:SIG_IGN 忽略信號,SIG_DFL 默認處理。
試著用 SIGINT 代替 KeyboardInterrupt 異常來處理用戶中斷。
from signal import *
from time import time, sleep
def sig_handler(signum, frame):
print "exit"
exit(0)
def main():
signal(SIGINT, sig_handler)
while True:
sleep(1)
print time()
if __name__ == "__main__":
main()
輸出:
$ ./main.py
1357987332.33
1357987333.33
1357987334.33
^Cexit
中斷信號被攔截,我們可以自主決定是否終止進程。在 GDB 里,用 SIGINT 來處理調(diào)試中斷。也有一些軟件用 SIGUSR1、SIGUSR2 作為外部通知事件,比如重啟什么的。信號處理會被帶入 fork()創(chuàng)建的子進程。
pause
函數(shù) pause() 會使進程休眠,直到進程接收到信號。信號要么被處理,要么終止進程。
def sig_handler(signum, frame):
print "sig:", signum
def main():
signal(SIGUSR1, sig_handler)
while True:
print time()
pause()
如果收到 SIGUSR1 信號,則進程蘇醒后顯示時間,然后再次休眠。如是其他信號,進程終止。
alarm
在 n 秒后發(fā)送一個 SIGALRM 告警信號。或用 0 秒取消所有尚未到期的告警。
signal(SIGALRM, sig_alarm) # 捕獲信號
alarm(2) # 2 秒后發(fā)送告警信號。僅一次。
timer
用來設置在 seconds 秒后發(fā)出信號,并在此以后每隔 interval 秒重復發(fā)出信號。參數(shù) which 決定了發(fā)出何種信號。
signal(SIGALRM, sig_alarm)
setitimer(ITIMER_REAL, 2, 5) # 2 秒后首次發(fā)出信號,隨后每隔 5 秒發(fā)一次。
將 seconds 設置為 0,將清除定時器。