class - subprocess (call program)

最後更新: 2024-01-04

目錄

 

介紹

subprocess 是用來取代 os.system 的 Class 來

Available In version: 2.4 and later

舊式寫法是

import os
cmd = 'ls -al'
os.system(cmd)

新寫法

import subprocess

cmd=['ls','-l']    # 如果有參數, 那就要用 list
myresult = subprocess.call(cmd)

print myresult     # 0

 


call()

 

Usage:

subprocess.call([program, args],stdin=None, stderr=None, stdout=None,
shell=False, cwd=None, env=None, universal_newlines=False)

# Wait for command to complete, return the returncode attribute

cmd='exit 1'
myresult = subprocess.call(cmd,shell=True)   # return 1

* 每次 call 都是獨立的 (cd 到另一個目錄是不影響下次 call)

* env: inheriting the current process

Example:

import subprocess

cmd=['ls','-l']    # 如果有參數, 那就要用 list !!
myresult = subprocess.call(cmd)
print myresult

Output:

total 4                                             # shell output, 不關 print 事 !!
-rwx------ 1 root root 121 Sep 23 09:13 test.py     # shell output
0                                                   # py var myresult output

* won't work: subprocess.call(['ls', '|', 'wc', '-l'])    <- 用到 pipeline 時必須要有 shell

* won't work: subprocess.call('ls -l')                     <- subprocess is looking for an executable file called 'ls -l'

 


check_call(), check_output()

 

# 如果 return code 不是 "0" 時, 會 raise "CalledProcessError"

# CalledProcessError object 內有 "returncode" attribute

check_call vs check_output

  • check_call() returns as soon as process exits
  • check_output() waits until all output is read

test.py

import subprocess

subprocess.check_call("exit 1")

所以有

<1> check_call()

ls_output = subprocess.check_call(['ls', '-l'])

<2> check_output()

If the return code was non-zero it raises a CalledProcessError.

>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'

>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

 


Shell

 

當使用 call() 沒有 shell 時, 有些 shell features 就用唔到

such as shell pipes, filename wildcards, environment variable expansion,

and expansion of ~ to a user’s home directory.

i.e.

subprocess.call('ls | wc -l', shell=True)

subprocess.call('sleep 10', shell=True)

subprocess.call('dd if=/dev/zero of=test.bin bs=1M count=1024', shell=True)

P.S.

call() default 不會 call a system shell

 


Working Directory

 

# You set the location of the directory which you want as the working directory of the program you are launching.

# doesn't work: subprocess.call('./ls')

subprocess.call('./ls', cwd='/bin')

 


Popen()

 

Basic Usage

# Popen 比 call 好, 因為它不會等 program 完才下一行

i.e. 要等 "ls -l" 完

import subprocess

subprocess.call(['ls','-l'])

相當於

import subprocess

proc = Popen('ls -l')
proc.wait()
print proc.returncode

returncode

使用 returncode 時必須加上 wait(), 否則 returncode 只會 None

p.wait()
print p.returncode

PIPE (get)

 * 當用到 pipe 時, 那 script 就會等 process 完結

Popen.stdin / Popen.stdout / Popen.stderr

If the stdin/stdout/stderr argument was PIPE,

this attribute is a file object that provides input/output to the child process.

#!/usr/bin/env python

import subprocess

process = subprocess.Popen('ls',
              stdout=subprocess.PIPE,
              stderr=subprocess.PIPE)

print process.stdout.read()

subprocess.PIPE

stdout=subprocess.PIPE, stderr=subprocess.PIPE

Special value that can be used as the stdin, stdout or stderr argument to Popen

Indicates that a pipe to the standard stream should be opened

    that you can then read with the .communicate() function.

Popen.communicate(input=None)

import subprocess

process = subprocess.Popen('ls', 
              stdout=subprocess.PIPE, 
              stderr=subprocess.PIPE)

stdout, stderr = process.communicate()

print stdout

Interact with process:

 * Send data to stdin (stdin=PIPE)

 * Read data from stdout and stderr, until end-of-file is reached.

 * Wait for process to terminate.

communicate() returns a tuple (stdoutdata, stderrdata).

 * The data read is buffered in memory, so do not use this method if the data size is large.

Example: shell pipe line

output=`dmesg | grep hda`

相當於

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

 

Other Feature

 

Killing and dieing

proc.terminate()

proc.kill()

Other

Popen.pid

Popen.send_signal(signal)  

Popen.poll()                       # 未行完是 None, 行完時會是 returncode

Popen.wait()                      # 不斷等, 最後 return returncode

 

 


subprocess.run()

 

The run() function was added in Python 3.5