代码改变世界

Python subprocess 模块

2018-06-01 11:09  钱先生  阅读(426)  评论(0编辑  收藏  举报

注: 本文中代码均在shell中执行. 

os.system 输出命令结果到屏幕, 返回命令执行状态. 

 若想将os.system的命令结果保存为一个变量, 要用到popen. 

os.popen("dir").read() # 会保存命令的执行结果输出
View Code

要同时得到命令结果和命令执行状态, 需要用到subprocess.

 

subprocess

  • 目的: 代替一些老的模块, 如os.system, os.spawn*. 
  • python 3.5之后才出现subprocess
  • 推荐的调用subprocess模块方法: 通过调用 run()方法来实现

 

subprocess常用方法

1. subprocess.Popen

  • 接收字符串格式命令, 返回元组形式, 第一个元素是执行状态, 第二个是命令结果.
  • subprocess.getstatusoutput('ls/bin/ls'),  返回 (0, '/bin/ls)
    • 该方法底层封装的是subprocess.Popen方法
    • 若要输出命令结果在屏幕上, 需要这样写 (以下是在shell里执行的脚本)
      • res = subprocess.Popen("ifconfig|grep 192", shell=True,stdout=subprocess.PIPE) 
      • res.stdout.read() 注: 若res里没有加stdout=subprocess.PIPE, 直接res.stdout是读不出来结果的(stdout代表标准输出). 相当于把命令结果存储在PIPE里(在内存里以管道的形式存储), 这样读取的时候就可以读出来. 每执行一个命令都会开辟一个新的管道, 所以不会堵.
    • 如果执行错误, 想要抓到错误信息, 需要再添加stderr (以下是在shell里执行的脚本):
      • res = subprocess.Popen("ifconfig|grep 192", shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE)

      •  

        res.stderr.read()

2. poll()

  • check if child process has terminated. returns returncode.
    • 每次调subprocess命令执行shell命令, 都相当于启了一个新的shell环境(相当于一个新的应用程序/一个新的进程)
    • 若一个进程太长, 不知道什么时候会执行完毕, 就需要定时去下, 就用到pulll.
      • res = subprocess.Popen("sleep 10; echo 'hello'", shell=True,stdout=subprocess.PIPE) 
      • res.stdout.read()  需要等到10秒之后才会返回结果
      • 因为不知道res什么时候执行完, 就定时去检查一下, 一旦执行完, 就去调结果:
        • res.poll()  返回NONE, 就是还没执行完; 返回0, 就是已经执行完了, 可以读结果了.

3. wait()

  • wait for child process to terminate. returns returncode attribute.
  • 和pull()有点像, 也是检查是否执行完毕, 但是wait()会一直等, 直到执行完毕之后才会返回0代表已经出结果了; 不会像pull()一样, 若没执行完也会返回一个状态.

 

4. terminate()

  • 杀掉所有启动进程 
  • 下面这段代码什么也读不出来, 因为进程中间被杀掉了:
    • res = subprocess.Popen("sleep 10; echo 'hello'", shell=True,stdout=subprocess.PIPE) 
    • res.terminate()
    • res.stdout.read()

 

5. stdin()

  • 标准输入
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

obj.stdin.write('print 1\n') 
obj.stdin.write('print 2\n') 
obj.stdin.write('print 3\n') 
obj.stdin.write('print 4\n') 

out_error_list = obj.communicate(timeout=10)
print out_error_list
  • 例:
    • res = subprocess.Popen(['python3], shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE) 
    • res.stdin.write(b"print(1)") 必须在打印的内容前面加b, 代表byte类型, 否则会出错.
    • res.stdin.write(b"print(2)")
    • res.stdin.write(b"print(3)")
    • res.stdin.write(b"print(4)")
    • res.communicate()  把前面写的内容一次性读取出来

 

subprocess常用参数

1. args

  • shell 命令, 可以是字符串或者序列类型(如: list, 元组)

 

2. bufsize

  • 指定缓冲. 0 -> 无缓冲, 1 -> 行缓冲, 其他 -> 缓冲区大小, 负值 -> 系统缓冲.

 

3. preexec_fn

  • 只在Unix平台下有效, 用于指定一个可执行对象(callable object)

 

4. close_fds

  • windows平台下, 如果close_fds被设置为True, 则新创建的子进程将不会继承父进程的输入,输出, 错误管道.

 

5. shell

  • if shell is True, the specified command will be excuted through the shell. 

 

6. pwd

  • 用于设置子进程的当前目录
  • 例:
    • res = subprocess.Popen(['pwd'], shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE, pwd="/tmp")
    • res.stdout.read() 返回b'/tmp\n' 

7. env

  • 用于指定子进程的环境变量. 如果env=NONE,子进程的环境变量将从父进程中继承.

 

8. universal_newlines

  • 不同系统的换行符不同,True -> 同意使用\n.

 

9. startupinfo与createionflags

  • 只在windows下有效
  • 将被传递给底层的CreateProcess()函数, 用于设置子进程的一些属性, 如: 主窗口的外观,进程的优先级等.

 

终端输入的命令分为两种:

  • 输入即可得到输出, 如: ifconfig
  • 输入进行某环境, 依赖再输入, 如: python

 

 

sudo自动输密码

import subprocess

def mypass():
    mypass = '123' # get the password from anywhere
    return mypass

echo = subprocess.Popen(['echo', mypass()],
                                       stdout=subprocess.PIPE,
                                       )

sudo = subprocess.Popen(['sudo', '-S', 'iptables', '-L'],
                                       stdin=echo.stdout,
                                       studout=subprocess.PIPE,
                                      )

end_of_pipe = sudo.stdout
print "Passowrd ok \n Iptables Chains %s" % end_of_pipe.read()            

以上是在linux里执行, 还可以通过python执行

 

 注: 上图通过python执行时, '123'要用单引号, 不能用双引号.