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!\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 命令的更多相关文章
- python之commands和subprocess入门介绍(可执行shell命令的模块)
一.commands模块 1.介绍 当我们使用Python进行编码的时候,但是又想运行一些shell命令,去创建文件夹.移动文件等等操作时,我们可以使用一些Python库去执行shell命令. com ...
- python的subprocess模块执行shell命令
subprocess模块可以允许我们执行shell命令 一般来说,使用run()方法就可以满足大部分情况 使用run执行shell命令 In [5]: subprocess.run('echo &qu ...
- subprocess使用,进入到某个目录下执行shell命令
subprocess是用来fork一个子进程的.这个子进程可以运行一个外部程序. 函数: subprocess.call() subprocess.check_output() subprocess. ...
- 利用commands模块执行shell命令
利用commands模块执行shell命令 用Python写运维脚本时,经常需要执行linux shell的命令,Python中的commands模块专门用于调用Linux shell命令,并返回状态 ...
- python重要模块之subprocess模块
python重要模块之subprocess模块 我们经常要通过python去执行系统的命令或者脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就相当于发起了一个新的进程, ...
- python学习之subprocess模块
subprocess.Popen 这个模块主要就提供一个类Popen: class subprocess.Popen( args, bufsize=0, executable=None, stdin= ...
- Python学习笔记——基础篇【第六周】——Subprocess模块
执行系统命令 可以执行shell命令的相关模块和函数有: os.system os.spawn* os.popen* --废弃 popen2.* --废弃 com ...
- python基础--subprocess模块
可以执行shell命令的相关模块和函数有: os.system os.spawn* os.popen* --废弃 popen2.* --废弃 commands.* ...
- logging模块、shutil模块、subprocess模块、xml模块
logging模块 shutil模块 subprocess模块 xml模块 logging模块 函数式简单配置 import logging logging.debug('debug message' ...
随机推荐
- [DB那些事]数据库加密
说到数据库加密,目前最好且唯一的方案就是SqlCipher对sqlite3整体加密,微信也用的它.开源,且支持很多平台. 单就Android来说,集成不算太麻烦,1个jar包,3个so库,1个zip. ...
- Angular JS 学习之过滤器
1.过滤器可以使用一个管道字符(|)添加到表达式和指令中: 2.AngularJS过滤器可用于转换数据: **currency:格式化数字为货币格式: **filter:从数组项中选择一个子集: ** ...
- psql-02基本语法
客户端 数据库: 创建:createdb mydb; 删除: dropdb mydb; 连接: 连接: psql mydb; 断开连接: \q 查看当前版本: select version(); 直接 ...
- Swift3.0语言教程分割字符串与截取字符串
Swift3.0语言教程分割字符串与截取字符串 Swift3.0语言教程分割字符串 如果想要快速的创建一个数组,我们可以将字符串进行分割,分割后的内容将会生成一个数组.在NSString中有两个分割字 ...
- node express新项目默认主文件app.js
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon') ...
- 转载:CSS计数器的趣味时光之css计算数据
CSS计数器是“啊太好了,竟不知道CSS可以做这啊”这类非常有趣的众多特性之一.简言之,用CSS使你持续某增加某个量,而无需JavaScript. 简单计数器 我们从这个简单的分页示例开始: 你见到的 ...
- Codeforces Round #243 (Div. 2) A. Sereja and Mugs
#include <iostream> #include <vector> #include <algorithm> #include <numeric> ...
- 彻底弄明白之数据结构中的KMP算法
如何加速朴素查找算法? KMP,当然还有其他算法,后续介绍. Knuth–Morris–Pratt string search algorithm Start at LHS of strin ...
- Mac OS X中MacPorts安装和使用
安装 官网pkg安装 搜索索引中的软件port search name 安装新软件sudo port install name 卸载软件sudo port uninstall name 查看有 ...
- mvc2 To 4
asp.net mvc2新特性:1.区域,有利于分模块开发 2.数据注解和验证 3.View层强类型辅助方法 4.UI Templates 5.httppost,默认参数asp.net mvc3新特性 ...