python subprocess
运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。
call(*popenargs, **kwargs): 执行命令,返回状态码
>>> import subprocess >>> ret = subprocess.call(["ls", "-l"]) total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> ret = subprocess.call("ls -l") #默认shell=False Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 524, in call return Popen(*popenargs, **kwargs).wait() File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib64/python2.7/subprocess.py", line 1308, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory >>> ret = subprocess.call("ls -l", shell=True) #shell=True不会报错 total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> print(ret) 0
check_call(*popenargs, **kwargs): 执行命令,如果执行状态码是 0 ,则返回0,否则抛异常
>>> ret = subprocess.call(["cd", "A"]) /usr/bin/cd: line 2: cd: A: No such file or directory >>> ret = subprocess.check_call(["cd", "A"]) /usr/bin/cd: line 2: cd: A: No such file or directory Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 542, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['cd', 'A']' returned non-zero exit status 1
check_output(*popenargs, **kwargs):执行命令,如果状态码是 0 ,则返回执行结果,否则抛异常
>>> ret = subprocess.check_output(["ls", "-l"]) >>> print(ret) total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> ret = subprocess.check_output(["lsa", "-l"]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 568, in check_output process = Popen(stdout=PIPE, *popenargs, **kwargs) File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib64/python2.7/subprocess.py", line 1308, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory
subprocess.Popen(...) 用于执行复杂的系统命令
参数:
- args:shell命令,可以是字符串或者序列类型(如:list,元组)
- bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
- stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
- preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
- close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。
所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。 - shell:同上
- cwd:用于设置子进程的当前目录
- env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
- universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
- startupinfo与createionflags只在windows下有效将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) >>> obj.stdin.write("print('hello')\n") >>> obj.stdin.write("print('hello word')") >>> obj.stdin.close() >>> cmd_out = obj.stdout.read() >>> obj.stdout.close() >>> cmd_error = obj.stderr.read() >>> obj.stderr.close() >>> print(cmd_out) hello hello word >>> print(cmd_error)
或者
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) >>> obj.stdin.write("print('hello word')") >>> out_error_list = obj.communicate() >>> print(out_error_list) ('hello word\n', '')
管道(shell中的|)
[root@Python ~]# ls -l | wc -l 18 >>> p1=subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) >>> p2=subprocess.Popen(["wc","-l"], stdin=p1.stdout,stdout=subprocess.PIPE) >>> out=p2.communicate() >>> print(out) (b'18\n', None)
上面实例其执行过程:
child1.stdout-->subprocess.PIPE
child2.stdin<--subprocess.PIPE
child2.stdout-->subprocess.PIPE
需要注意的是:communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成