zoukankan      html  css  js  c++  java
  • subprocess模块还提供了很多方便的方法来使得执行 shell 命令

    现在你可以看到它正常地处理了转义。

    注意

    实际上你也可以在shell=False那里直接使用一个单独的字符串作为参数, 但是它必须是命令程序本身,这种做法和在一个列表中定义一个args没什么区别。而如果当shell=False时候直接执行字符串命令,则会报错:

    >>> subprocess.Popen('echo "Hello world!"', shell=False)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/usr/lib/python2.5/subprocess.py", line 594, in __init__
    errread, errwrite)
    File "/usr/lib/python2.5/subprocess.py", line 1147, in _execute_child
    raise child_exception
    OSError: [Errno 2] No such file or directory
    如果我们还是坚持使用一个字符串,Python 会认为这个完整的字符串是一个可执行的程序名,而实际上没有一个叫做echo "Hello world!"的程序,所以报错了。正确的做法要用 list 分开传送参数。
    检查 PATH 中的程序
    这里有个方法可以找出程序真正的位置:
    import os
    def whereis(program):
    for path in os.environ.get('PATH', '').split(':'):
    if os.path.exists(os.path.join(path, program)) and
    not os.path.isdir(os.path.join(path, program)):
    return os.path.join(path, program)
    return None
    让我们用它来找出echo程序在哪里:
    >>> location = whereis('echo')
    >>> if location is not None:
    ... print location
    /bin/echo
    这个方法同样可以检查用户的PATH里面是否有 Python 需要的程序。

    当然你也可以使用命令行中的程序whereis来找出程序的路径。

    $ whereis echo
    echo: /bin/echo /usr/share/man/man1/echo.1.gz
    注意

    无论我们使用shell为True或者False, 我们都没有指定执行程序的全路径。 如果这个程序在上下文环境的PATH变量中,我们才可以执行。 当然如果你愿意,指定全路径也没问题。

    你也可以坚持指定executable为想要执行的程序, 然后args就不设定程序。虽然没看到明确的文档,不过我电脑上面可以这么执行:

    >>> subprocess.Popen(['1', '2', '3'], shell=False, executable='echo')
    2 3
    <subprocess.Popen object at 0xb776f56c>
    不直接使用 shell 会导致不能直观地使用重定向、管道、here 文档、shell 参数或其他那些可以在命令行使用的技巧。接下来我们会看看怎么使用这些功能。
    从标准输出和错误重定向
    当你使用Popen执行程序时候,输出内容通常被发送到 stdout, 这也是为什么你能看到这些内容。

    当你想尝试从某个程序读取标准输出信息时候,则需要在调用Popen之前设定stdout参数。要设定的值是subprocess.PIPE:

    subprocess.PIPE

    可以为Popen指定标准输入、标准输出和标准错误输出的参数, 需要注意的是标准输出流需要打开可写。

    这里有个范例:

    >>> process = subprocess.Popen(['echo', 'Hello World!'], shell=False, stdout=subprocess.PIPE)
    To read the output from the pipe you use thecommunicate()method:

    为了从管道获取输出,你可以使用communicate()方法:

    >>> print process.communicate()
    ('Hello World! ', None)
    communicate()的返回值是一个 tuple,第一个值是标准输出的数据, 第二个输出是标准错误输出的内容。
    这里有段脚本能让我们测试标准输出和标准错误输出的表现行为, 将它存为test1.py:
    import sys
    sys.stdout.write('Message to stdout ')
    sys.stderr.write('Message to stderr ')
    执行它:
    >>> process = subprocess.Popen(['python', 'test1.py'], shell=False, stdout=subprocess.PIPE)
    Message to stderr
    >>> print process.communicate()
    ('Message to stdout ', None)
    注意标准错误输出在被生成后就打印了,而标准输出则被管道传输了。 这是因为我们只设定了标准输出的管道,让我们同时也设定标准错误输出。
    >>> process = subprocess.Popen(['python', 'test1.py'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    >>> print process.communicate()
    ('Message to stdout ', 'Message to stderr ')
    这次标准输出和标准错误输出都被 Python 获取到了。

    现在所有的消息能被打印出来了,如果我们再次调用communicate(), 则会得到一个错误信息:

    >>> print process.communicate()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/usr/lib/python2.5/subprocess.py", line 668, in communicate
    return self._communicate(input)
    File "/usr/lib/python2.5/subprocess.py", line 1207, in _communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])
    ValueError: I/O operation on closed file
    communicate()方法读取标准输出和标准错误输出时候,遇到结束符(EOF) 就会结束。
    重定向 stderr 到 stdout
    如果你想将错误信息重定向到标准输出,只需要给stderr参数指定一个特殊值:stderr=subprocess.STDOUT即可。
    写入标准输入
    写数据入一个进程和之前所述比较类似。为了要写入数据,需要先打开一个管道到标准输入。 通过设定Popen参数stdin=subproces.PIPE可以实现。
    为了测试,让我们另外写一个仅输出Received:和输入数据的程序。 它在退出之前会输出消息。调用这个test2.py:
    import sys
    input = sys.stdin.read()
    sys.stdout.write('Received: %s'%input)
    为了发送消息到标准输入,把你想发送的信息作为communicate()的参数input。让我们跑起来:
    >>> process = subprocess.Popen(['python', 'test2.py'], shell=False, stdin=subprocess.PIPE)
    >>> print process.communicate('How are you?')
    Received: How are you?(None, None)
    注意test2.py发送的信息被打印到标准输出,随后的是(None, None), 这是因为标准输出和标准错误输出没有设定输出管道。

    你可以和之前那样指定stdout=subprocess.PIPE和stderr=subprocess.PIPE来设定输出管道。

    类文件属性
    Popen拥有stdout和stderr属性,从而可以当作文件一样写出数据,同时stdin属性可以像文件一样读取数据。 你可以使用他们来替换communicate()。下面我们将看如何用它们。
    读写同一个进程
    这里有个例子,将它保存为test3.py:
    import sys
    while True:
    input = sys.stdin.readline()
    sys.stdout.write('Received: %s'%input)
    sys.stdout.flush()
    这个程序也是简单的响应接受到的数据,让我们把它跑起来:
    >>> import time
    >>> process = subprocess.Popen(['python', 'test3.py'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    >>> for i in range(5):
    ... process.stdin.write('%d ' % i)
    ... output = process.stdout.readline()
    ... print output
    ... time.sleep(1)
    ...
    Received: 0

    Received: 1

    Received: 2

    Received: 3

    Received: 4

    >>>
    每隔一秒钟会输出一行。

    现在你应该掌握了所有需要通过 Python 来跟 Shell 交互需要的知识。

    获取返回值,poll()和wait()
    当一个程序退出时候,他会返回一个正整数来表明它的退出状态。 0 代表「成功地结束」,非零则表示「非正常结束」。 大部分系统要求返回值在 0-127 之间,其他都是未定义的结果。 一些系统会有事先定义好的错误对应关系,但一般不被拿出来用。 Unix 程序通常使用 2 作为命令语法错误,1 作为其他错误。
    你可以通过Popen的.returncode属性获取程序返回值。这儿有个例子:
    >>> process = subprocess.Popen(['echo', 'Hello world!'], shell=False)
    >>> process.poll()
    >>> print process.returncode
    None
    >>> process.poll()
    0
    >>> print process.returncode
    0
    这个returncode并不是一开始就设定好的,最初是默认值None, 它会一直是None知道你调用subprocess的方法比如poll()和wait()。 这些方法会设定returncode。因此,如果你想知道返回值,那就调用poll(2881064151)和wait()。

    poll()和wait()方法区别很小:

    Popen.poll(): 检查子进程是否结束。并设置和返回.returncode属性。Popen.wait(): 等待子进程结束。并设置和返回.returncode属性。

    便捷的方法
    subprocess模块还提供了很多方便的方法来使得执行 shell 命令更方便。 我没有全部试试。(译者:意思是让读者自己挖掘?)
    理解sys.argv
    如果你想写一个 Python 脚本来接受命令行参数, 那么命令行的参数会被传送并成参数sys.argv。 这里有个小范例,将它保存成command.py。
    #!/usr/bin/env python
    if __name__ == '__main__':
    import sys
    print "Executable: %s"%sys.argv[0]
    for arg in sys.argv[1:]:
    print "Arg: %s"%arg
    if __name__ == '__main__'这行确保代码在被执行是才运行, 而不是被引入时候运行。给这个文件执行权限:
    1
    $ chmod 755 command.py
    这里是一些运行时的范例:
    $ python command.py
    Executable: command.py
    $ python command.py arg1
    Executable: command.py
    Arg: arg1
    $ python command.py arg1 arg2
    Executable: command.py
    Arg: arg1
    Arg: arg2
    注意无论 Python 脚本怎么执行,sys.argv[0]始终是脚本的名称。sys.argv[1]和之后的参数是命令行接受的参数。 你可以通过使用参数-m来强制 Python 脚本作为模块导入使用。
    $ python -m command
    Executable: /home/james/Desktop/command.py
    $ python -m command arg1
    Executable: /home/james/Desktop/command.py
    Arg: arg1
    $ python -m command arg1 arg2
    Executable: /home/james/Desktop/command.py
    Arg: arg1
    Arg: arg2
    如你所见,Python 将-m作为命令的一部分,因此 `sys.srgv[0] 包含了脚本的全路径。 现在我们来直接执行它:
    $ ./command.py
    Executable: ./command.py
    $ ./command.py arg1
    Executable: ./command.py
    Arg: arg1
    $ ./command.py arg1 arg2
    Executable: ./command.py
    Arg: arg1
    Arg: arg2
    看吧,sys.argv[0]包含 Python 脚本的名称,sys.argv[1]以及他的兄弟们还是老样子,包含各类参数。
    展开 Shell
    有时候,我们会在 shell 中使用通配符来设定一组参数,比如, 我们在 Bash 中运行:
    $ ./command.py *.txt
    你可能觉得输出应该是:
    Executable: ./command.py
    Arg: *.txt
    这不是你想要的结果。输出结果应该依赖当前文件夹中.txt文件的数目。执行效果如下:
    Executable: ./command.py
    Arg: errors.txt
    Arg: new.txt
    Arg: output.txt
    Bash 会将*.txt自动展开成所有符合.txt的参数。所以接受到的参数会超过你预期。

    你可以通过将参数用引号抱起来来关闭 Shell 解释特性, 但是只要你用过,就会意识到在大多数情况下面这是非常有用的功能。

    $ ./command.py "*.txt"
    Executable: ./command.py
    Arg: *.txt

  • 相关阅读:
    教你当主管:如何降低你的员工流失率?
    你问我这算什么
    推荐:职场提升的10条捷径
    压力从何而来呢?千万不要2008年结婚
    怎样“管理”你的上司?
    HTTP.sys
    IIS书籍
    IIS目录
    HTTP服务
    在 IIS 7 中使用配置文件
  • 原文地址:https://www.cnblogs.com/cbryge/p/6155272.html
Copyright © 2011-2022 走看看