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

注意

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

subprocess模块还提供了很多方便的方法来使得执行 shell 命令的更多相关文章

  1. python之commands和subprocess入门介绍(可执行shell命令的模块)

    一.commands模块 1.介绍 当我们使用Python进行编码的时候,但是又想运行一些shell命令,去创建文件夹.移动文件等等操作时,我们可以使用一些Python库去执行shell命令. com ...

  2. python的subprocess模块执行shell命令

    subprocess模块可以允许我们执行shell命令 一般来说,使用run()方法就可以满足大部分情况 使用run执行shell命令 In [5]: subprocess.run('echo &qu ...

  3. subprocess使用,进入到某个目录下执行shell命令

    subprocess是用来fork一个子进程的.这个子进程可以运行一个外部程序. 函数: subprocess.call() subprocess.check_output() subprocess. ...

  4. 利用commands模块执行shell命令

    利用commands模块执行shell命令 用Python写运维脚本时,经常需要执行linux shell的命令,Python中的commands模块专门用于调用Linux shell命令,并返回状态 ...

  5. python重要模块之subprocess模块

    python重要模块之subprocess模块 我们经常要通过python去执行系统的命令或者脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就相当于发起了一个新的进程, ...

  6. python学习之subprocess模块

    subprocess.Popen 这个模块主要就提供一个类Popen: class subprocess.Popen( args, bufsize=0, executable=None, stdin= ...

  7. Python学习笔记——基础篇【第六周】——Subprocess模块

    执行系统命令 可以执行shell命令的相关模块和函数有: os.system os.spawn* os.popen*          --废弃 popen2.*           --废弃 com ...

  8. python基础--subprocess模块

    可以执行shell命令的相关模块和函数有: os.system os.spawn* os.popen*          --废弃 popen2.*           --废弃 commands.* ...

  9. logging模块、shutil模块、subprocess模块、xml模块

    logging模块 shutil模块 subprocess模块 xml模块 logging模块 函数式简单配置 import logging logging.debug('debug message' ...

随机推荐

  1. css 让内容满屏居中不变形

    .selector { position: fixed; width: 100%; height: 100%; background-image: url(path); background-repe ...

  2. DOM--3 DOM核心和DOM2 HTML(2)

    核心Node对象 由于继承扩展的关系,DOM中大部分对象会有Node对象的属性和方法,其中包括: nodeName DOM2核心中规定的每种nodeType预期的nodeName值 对象 返回值 El ...

  3. MVVM datatemplate 下button.contextmenu的command 失效解决方案

    <Button CommandParameter="{Binding}" Tag="{Binding RelativeSource={RelativeSource ...

  4. asp.net正则表达式提取网页网址、标题、图片实例以及过滤所有HTML标签实例

    无论你用什么语言,正则表达式的处理方法都是非常灵活.高效的,尤其是对某些字符串的抓取.过滤方面,更显其优势. 正则表达式的写法通常比较简单,几行短代码便能轻松完成看似很复杂的事情,更值得称赞的是,它的 ...

  5. DP ZOJ 2745 01-K Code

    题目传送门 题意:要求任意连续子序列中0和1的数量差不超过k的方案数 分析:想好状态其实不难.dp[i][j][k]表示考虑前i长度,后缀中最大的 sum(0) - sum(1) = j, sum ( ...

  6. 转载:python发送HTTP请求

    1. [代码]GET 方法 import httplib #----------------------------- conn = httplib.HTTPConnection("www. ...

  7. 【BZOJ1827】[Usaco2010 Mar]gather 奶牛大集会 树形DP

    [BZOJ][Usaco2010 Mar]gather 奶牛大集会 Description Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来 ...

  8. Java NIO之选择器Selector

    在单独的线程中,检查多个通道是否可以进行IO操作. Selector创建:静态工厂方法创建 Selector selector = Selector.open(); 注册通道 channel.conf ...

  9. SVN版本控制工具使用学习

    SVN版本控制工具使用学习 Subversion是优秀的版本控制工具. 1.下载和搭建SVN服务器 http://subversion.apache.org/packages.html 类型有5种,推 ...

  10. box-sizing的相关属性

    box-sizing有三个属性,分别是:content-box,border-box,inherit (1)content-box:在宽度和高度之外绘制元素的内边距和边框(默认属性) (2)borde ...