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

注意

实际上你也可以在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. [DB那些事]数据库加密

    说到数据库加密,目前最好且唯一的方案就是SqlCipher对sqlite3整体加密,微信也用的它.开源,且支持很多平台. 单就Android来说,集成不算太麻烦,1个jar包,3个so库,1个zip. ...

  2. Angular JS 学习之过滤器

    1.过滤器可以使用一个管道字符(|)添加到表达式和指令中: 2.AngularJS过滤器可用于转换数据: **currency:格式化数字为货币格式: **filter:从数组项中选择一个子集: ** ...

  3. psql-02基本语法

    客户端 数据库: 创建:createdb mydb; 删除: dropdb mydb; 连接: 连接: psql mydb; 断开连接: \q 查看当前版本: select version(); 直接 ...

  4. Swift3.0语言教程分割字符串与截取字符串

    Swift3.0语言教程分割字符串与截取字符串 Swift3.0语言教程分割字符串 如果想要快速的创建一个数组,我们可以将字符串进行分割,分割后的内容将会生成一个数组.在NSString中有两个分割字 ...

  5. node express新项目默认主文件app.js

    var express = require('express'); var path = require('path'); var favicon = require('serve-favicon') ...

  6. 转载:CSS计数器的趣味时光之css计算数据

    CSS计数器是“啊太好了,竟不知道CSS可以做这啊”这类非常有趣的众多特性之一.简言之,用CSS使你持续某增加某个量,而无需JavaScript. 简单计数器 我们从这个简单的分页示例开始: 你见到的 ...

  7. Codeforces Round #243 (Div. 2) A. Sereja and Mugs

    #include <iostream> #include <vector> #include <algorithm> #include <numeric> ...

  8. 彻底弄明白之数据结构中的KMP算法

    如何加速朴素查找算法? KMP,当然还有其他算法,后续介绍.      Knuth–Morris–Pratt string search algorithm Start at LHS of strin ...

  9. Mac OS X中MacPorts安装和使用

      安装 官网pkg安装   搜索索引中的软件port search name 安装新软件sudo port install name 卸载软件sudo port uninstall name 查看有 ...

  10. mvc2 To 4

    asp.net mvc2新特性:1.区域,有利于分模块开发 2.数据注解和验证 3.View层强类型辅助方法 4.UI Templates 5.httppost,默认参数asp.net mvc3新特性 ...