这里是指在本地执行命令的方法,通过 SSH 的方式这里不做讨论。
Update @ 2019-09-09: Python: 通过 SSH 执行命令
声明:直接运行外部命令往往是一种简单的方案,其缺点是其开销相对较大。如果在一个有一定规模的线上服务,应该尽量避免如此设计。
commands 模块
对 os.popen
的封装。
注意:该模块在 Python3 中已经移除。
commands.getoutput(cmd: str) -> (status: int, output: str)
commands.getstatusoutput(cmd: str) -> output: str
commands.getstatus(file) -> output: str
os 模块
os.system(command)
os.popen(cmd, mode='r', buffering=- 1)
os.execl(path, arg0, arg1, ...)
os.execle(path, arg0, arg1, ..., env)
os.execlp(file, arg0, arg1, ...)
os.execlpe(file, arg0, arg1, ..., env)
os.execv(path, args)
os.execve(path, args, env)
os.execvp(file, args)
os.execvpe(file, args, env)
需要特别注意的点
如果不需要输出,os.system
是非常易于使用的。
但是 os.system
会直接执行命令,如果里面有来自用户输入内容的话,就有注入的风险,这是一个非常严重的安全问题,需要非常小心。如果是一个长期项目,依赖开发者小心,不是怎么靠谱。
subprocess 模块
如果加上 shell=True
参数, 也会将命令放到子 shell 中执行,如果输入的是字符串命令,而不是 list
风格,还是会有和 os.system
相同的注入风险。详情可以参考官方文档:17.1.1.1. Frequently Used Arguments。
如果不是非常有必要,务必保证 shell=False
(默认)!
Python2:
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
Python3:
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False,
cwd=None, timeout=None, **other_popen_kwargs)
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False,
cwd=None, timeout=None, **other_popen_kwargs)
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False,
cwd=None, encoding=None, errors=None, universal_newlines=None,
timeout=None, text=None, **other_popen_kwargs)
# Python3.5 加入的新方法
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
capture_output=False, shell=False,
cwd=None, timeout=None, check=False, encoding=None, errors=None,
text=None, env=None, universal_newlines=None, **other_popen_kwargs)
然后就是底层 API —— Popen 了,其使用相对复杂,能实现更多控制,下次单讲吧。简单使用的时候可以不管。
Update @ 2017-10-09: Subprocess Popen
示例
官方引入 .run
方法之后,将其他几个方法打包在一起,称之为 Older high-level API
。既然有官方的推荐,肯定是 .run
设计方面更强大、更安全、更高效了。
注意:返回是一个 Object 而不是 (状态码, 输出)
。
import subprocess
proc = subprocess.run(['ls', '/etc/passwd'], capture_output=True)
print([proc.args, proc.returncode, proc.stdout, proc.stderr, proc.check_returncode()])
# [['ls', '/etc/passwd'], 0, b'/etc/passwd\n', b'', None]
asyncio 模块
Python 3.4 开始引入的 asyncio 模块中有对 subprocess 的异步支持。
coroutine asyncio.create_subprocess_exec(program, *args,
stdin=None, stdout=None, stderr=None,
limit=None, **kwds)
coroutine asyncio.create_subprocess_shell(cmd,
stdin=None, stdout=None, stderr=None,
limit=None, **kwds)
用法和 subprocess 模块大同小异,详情参考官方文档。
Update @ 2019-08-31: AsyncIO 异步执行命令
第三方模块
sh 模块
-
sh
<>sh.ls('-l') ls_cmd = sh.Command('ls') ls_cmd()
-
envoy
subprocess for humans https://github.com/kennethreitz/envoy pexpect
https://pexpect.readthedocs.io/en/stable/plumbum
https://plumbum.readthedocs.io/en/latest/