Python中subprocess学习

subprocess的目的就是启动一个新的进程并且与之通信。

subprocess模块中只定义了一个类: Popen。可以使用Popen来创建进程,并与进程进行复杂的交互。它的构造函数如下:

subprocess.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,元组),用于指定进程的可执行文件及其参数。如果是序列类型,第一个元素通常是可执行文件的路径。我们也可以显式的使用executeable参数来指定可执行文件的路径。

参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承

如果参数shell设为true,程序将通过shell来执行。

参数env是字典类型,用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承

subprocess.PIPE

  在创建Popen对象时,subprocess.PIPE可以初始化stdin, stdout或stderr参数。表示与子进程通信的标准流。

subprocess.STDOUT

  创建Popen对象时,用于初始化stderr参数,表示将错误通过标准输出流输出。

Popen的方法:

Popen.poll()

  用于检查子进程是否已经结束。设置并返回returncode属性。

Popen.wait()

  等待子进程结束。设置并返回returncode属性。

Popen.communicate(input=None)

  与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。

Popen.send_signal(signal)

  向子进程发送信号。

Popen.terminate()

  停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程

Popen.kill()

  杀死子进程

Popen.stdin,Popen.stdout ,Popen.stderr ,官方文档上这么说:

stdinstdout and stderr specify the executed programs’ standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None.

Popen.pid

  获取子进程进程ID。

Popen.returncode

  获取进程的返回值。如果进程还没有结束,返回None。

---------------------------------------------------------------

简单的用法:

[python]   view plain  copy
  1. p=subprocess.Popen("dir", shell=True)  
  2. p.wait()  

shell参数根据你要执行的命令的情况来决定,上面是dir命令,就一定要shell=True了,p.wait()可以得到命令的返回值。

如果上面写成a=p.wait(),a就是returncode。那么输出a的话,有可能就是0【表示执行成功】。

---------------------------------------------------------------------------

进程通讯

如果想得到进程的输出,管道是个很方便的方法,这样:

[python]   view plain  copy
  1. p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)  
  2. (stdoutput,erroutput) = p.<span>commu</span>nicate()  

p.communicate会一直等到进程退出,并将标准输出和标准错误输出返回,这样就可以得到子进程的输出了。

再看一个communicate的例子。

上面的例子通过communicate给stdin发送数据,然后使用一个tuple接收命令的执行结果。

------------------------------------------------------------------------

上面,标准输出和标准错误输出是分开的,也可以合并起来,只需要将stderr参数设置为subprocess.STDOUT就可以了,这样子:

[python]   view plain  copy
  1. p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)  
  2. (stdoutput,erroutput) = p.<span>commu</span>nicate()  

如果你想一行行处理子进程的输出,也没有问题:

[python]   view plain  copy
  1. p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)  
  2. while True:  
  3.     buff = p.stdout.readline()  
  4.     if buff == '' and p.poll() != None:  
  5.         break  

------------------------------------------------------

死锁

但是如果你使用了管道,而又不去处理管道的输出,那么小心点,如果子进程输出数据过多,死锁就会发生了,比如下面的用法:

[python]   view plain  copy
  1. p=subprocess.Popen("longprint", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)  
  2. p.wait()  

longprint是一个假想的有大量输出的进程,那么在我的xp, Python2.5的环境下,当输出达到4096时,死锁就发生了。当然,如果我们用p.stdout.readline或者p.communicate去清理输出,那么无论输出多少,死锁都是不会发生的。或者我们不使用管道,比如不做重定向,或者重定向到文件,也都是可以避免死锁的。

----------------------------------

subprocess还可以连接起来多个命令来执行。

在shell中我们知道,想要连接多个命令可以使用管道。

在subprocess中,可以使用上一个命令执行的输出结果作为下一次执行的输入。例子如下:

例子中,p2使用了第一次执行命令的结果p1的stdout作为输入数据,然后执行tail命令。

- -------------------

下面是一个更大的例子。用来ping一系列的ip地址,并输出是否这些地址的主机是alive的。代码参考了Pythonunix Linux 系统管理指南。

[python]   view plain  copy
  1. #!/usr/bin/env python  
  2.   
  3. from threading import Thread  
  4. import subprocess  
  5. from Queue import Queue  
  6.   
  7. num_threads=3  
  8. ips=['127.0.0.1','116.56.148.187']  
  9. q=Queue()  
  10. def pingme(i,queue):  
  11.     while True:  
  12.         ip=queue.get()  
  13.         print 'Thread %s pinging %s' %(i,ip)  
  14.         ret=subprocess.call('ping -c 1 %s' % ip,shell=True,stdout=open('/dev/null','w'),stderr=subprocess.STDOUT)  
  15.         if ret==0:  
  16.             print '%s is alive!' %ip  
  17.         elif ret==1:  
  18.             print '%s is down...'%ip  
  19.         queue.task_done()  
  20.   
  21. #start num_threads threads  
  22. for i in range(num_threads):  
  23.     t=Thread(target=pingme,args=(i,q))  
  24.     t.setDaemon(True)  
  25.     t.start()  
  26.   
  27. for ip in ips:  
  28.     q.put(ip)  
  29. print 'main thread waiting...'  
  30. q.join();print 'Done'  

在上面代码中使用subprocess的主要好处是,使用多个线程来执行ping命令会节省大量时间。

假设说我们用一个线程来处理,那么每个 ping都要等待前一个结束之后再ping其他地址。那么如果有100个地址,一共需要的时间=100*平均时间。

如果使用多个线程,那么最长执行时间的线程就是整个程序运行的总时间。【时间比单个线程节省多了】

这里要注意一下Queue模块的学习。

pingme函数的执行是这样的:

启动的线程会去执行pingme函数。

pingme函数会检测队列中是否有元素。如果有的话,则取出并执行ping命令。

这个队列是多个线程共享的。所以这里我们不使用列表。【假设在这里我们使用列表,那么需要我们自己来进行同步控制。Queue本身已经通过信号量做了同步控制,节省了我们自己做同步控制的工作=。=】

代码中q的join函数是阻塞当前线程。下面是e文注释

 Queue.join()

  Blocks until all items in the queue have been gotten and processed(task_done()).

---------------------------------------------

学习Processing模块的时候,遇到了进程的join函数。进程的join函数意思说,等待进程运行结束。与这里的Queue的join有异曲同工之妙啊。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: `subprocess`是Python的一个标准库,用于在Python启动和管理外部进程。下面是一些常见的用法: 1. 运行外部命令并获取输出: ```python import subprocess result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE) print(result.stdout.decode()) ``` 这里的`run()`函数接收一个命令列表作为参数,运行该命令并等待其完成。`stdout=subprocess.PIPE`参数指定将命令输出返回到Python进程。`result.stdout.decode()`将字节字符串转换为文本输出。 2. 捕获标准错误输出: ```python import subprocess try: result = subprocess.run(['invalid-command'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as e: print(e.stderr.decode()) ``` 这里使用了`try/except`结构来捕获`CalledProcessError`异常,因为命令无效,所以会抛出这个异常。`e.stderr.decode()`将标准错误输出转换为文本输出。 3. 通过管道传递输入和输出: ```python import subprocess p1 = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) p2 = subprocess.Popen(['grep', 'hello'], stdin=p1.stdout, stdout=subprocess.PIPE) result = p2.communicate(input=b'hello world\n')[0] print(result.decode()) ``` 这里的`Popen()`函数用于启动外部进程,并将其输入和输出重定向到Python进程。使用`Popen()`函数创建两个进程,并将第一个进程的输出作为第二个进程的输入。`p2.communicate()`函数将输入数据发送到第一个进程,并返回输出结果。 这些是`subprocess`库的一些基本用法。更多详细信息,请查看Python官方文档。 ### 回答2: Python的`subprocess`库是用于在Python脚本调用外部命令的模块。它提供了创建子进程、连接子进程的输入/输出/错误管道以及获取子进程返回值的功能。 要使用`subprocess`库,首先需要导入该模块:`import subprocess` `subprocess`库通过`Popen`类来创建子进程,然后可以使用其他方法与子进程进行交互。下面是一些常见的用法: 1. 运行命令: ```python subprocess.run(['ls', '-l']) # 运行命令 ls -l ``` 2. 获取命令输出: ```python result = subprocess.run(['ls', '-l'], capture_output=True, text=True) # 捕获命令输出并以文本形式返回 print(result.stdout) # 输出命令输出结果 print(result.returncode) # 输出命令的返回值 ``` 3. 运行命令并检查返回值: ```python try: subprocess.run(['git', 'commit', '-m', 'message'], check=True) # 运行 git commit 命令,并检查返回值是否为0 except subprocess.CalledProcessError as e: print(f"Command execution failed: {e.returncode}") # 如果返回值不为0,输出错误信息 ``` 4. 管道连接多个子进程: ```python process1 = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE) process2 = subprocess.Popen(['grep', 'file.txt'], stdin=process1.stdout, stdout=subprocess.PIPE) output = process2.communicate()[0] # 获取命令输出 ``` 除了上述示例之外,`subprocess`库还提供了其他许多方法和参数,用于处理更复杂的子进程交互场景。需要根据具体的需求,参考Python文档或相关资料来更深入了解和使用`subprocess`库。 ### 回答3: Pythonsubprocess库是用来创建子进程并与其进行通信的模块。下面将简单介绍subprocess库的基本用法。 1. 导入subprocess库: ``` import subprocess ``` 2. 运行命令并获取输出: 可以使用`subprocess.run()`函数来运行命令,并通过`stdout`参数获取输出。例如,运行`ls`命令并获取输出: ``` result = subprocess.run(['ls'], stdout=subprocess.PIPE) output = result.stdout.decode('utf-8') print(output) ``` 3. 运行命令并获取返回值: 可以使用`subprocess.run()`函数来运行命令,并通过`returncode`属性获取命令的返回值。例如,运行`ls`命令并获取返回值: ``` result = subprocess.run(['ls']) return_code = result.returncode print(return_code) ``` 4. 使用管道连接多个命令: 可以使用`|`符号来连接多个命令,并通过`shell=True`参数使其生效。例如,运行`ls | grep py`命令并获取输出: ``` result = subprocess.run('ls | grep py', shell=True, stdout=subprocess.PIPE) output = result.stdout.decode('utf-8') print(output) ``` 5. 运行外部脚本文件: 可以使用`subprocess.run()`函数来运行外部的Python脚本文件。例如,运行名为`script.py`的外部脚本文件: ``` result = subprocess.run(['python', 'script.py']) ``` 这些是subprocess库的基本用法,还有更多高级的用法可以根据具体需求进一步探索和学习

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值