如何在Python中调用外部命令,就像在shell或命令提示符中键入它一样?
如何在Python中调用外部命令,就像在shell或命令提示符中键入它一样?
使用:
import subprocess
p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
['Filesystem Size Used Avail Use% Mounted on',
'/dev/sda6 32G 21G 11G 67% /',
'none 4.0K 0 4.0K 0% /sys/fs/cgroup',
'udev 1.9G 4.0K 1.9G 1% /dev',
'tmpfs 387M 1.4M 386M 1% /run',
'none 5.0M 0 5.0M 0% /run/lock',
'none 1.9G 58M 1.9G 3% /run/shm',
'none 100M 32K 100M 1% /run/user',
'/dev/sda5 340G 222G 100G 69% /home',
'']
在Python中运行外部命令有很多不同的方法,它们都有各自的优点和缺点。
我和我的同事一直在编写Python系统管理工具,因此我们需要运行很多外部命令,有时您希望它们阻塞或异步运行,超时,每秒更新等。
处理返回代码和错误的方式也不同,您可能需要解析输出并提供新输入(以 expect 类型的方式)。或者您需要将 标准输入, 标准输出 和 标准错误 重定向到不同的 tty 中运行(例如使用 GNU Screen 时)。
因此,您可能需要编写许多外部命令的包装器。因此,这是一个我们编写的Python模块,可以处理几乎任何您想要的内容,如果不行,它非常灵活,因此您可以轻松扩展:
https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py
它不能独立工作,需要我们的其他工具,并且多年来获得了许多专业功能,因此它可能不适合作为您的即插即用替代品,但它可以为您提供有关运行命令的Python内部工作原理以及如何处理某些情况的想法。from subprocess import call
# Using list
call(["echo", "Hello", "world"])
# Single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
subprocess
时,在Linux上我使用以下方法解决了问题:import subprocess
# subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
PIPE
值是字节序列,为了正确显示它们,应考虑解码。对于Python的较新版本,text=True
和encoding='utf-8'
已添加到subprocess.run()
的kwargs中。total 113M
-rwxr-xr-x 1 farzad farzad 307 Jan 15 2018 vpnscript
-rwxrwxr-x 1 farzad farzad 204 Jan 15 2018 ex
drwxrwxr-x 4 farzad farzad 4.0K Jan 22 2018 scripts
.... # Some other lines
stdout_result = 1
stderr_result = 1
def stdout_thread(pipe):
global stdout_result
while True:
out = pipe.stdout.read(1)
stdout_result = pipe.poll()
if out == '' and stdout_result is not None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
def stderr_thread(pipe):
global stderr_result
while True:
err = pipe.stderr.read(1)
stderr_result = pipe.poll()
if err == '' and stderr_result is not None:
break
if err != '':
sys.stdout.write(err)
sys.stdout.flush()
def exec_command(command, cwd=None):
if cwd is not None:
print '[' + ' '.join(command) + '] in ' + cwd
else:
print '[' + ' '.join(command) + ']'
p = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
)
out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))
err_thread.start()
out_thread.start()
out_thread.join()
err_thread.join()
return stdout_result + stderr_result
这里是调用外部命令并返回或打印命令输出的方法:
Python Subprocess 的 check_output 很适合此类操作。
运行带有参数的命令,并将其输出作为字节字符串返回。
import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
shell=True
。在 Python 3.x(其中 x > 3,我想)中,您可以使用 universal_newlines=True
将输出作为适当的字符串检索,并且您可能希望切换到 subprocess.run()
。 - tripleee如果你正在编写一个Python shell脚本并且已经安装了IPython,你可以使用感叹号前缀在IPython中运行一个shell命令:
!ls
filelist = !ls
更新于2015年:Python 3.5添加了subprocess.run,比subprocess.Popen更易于使用。我建议使用它。
>>> subprocess.run(["ls", "-l"]) # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
>>> subprocess.run(["ls", "-l", "/dev/null"], capture_output=True)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n', stderr=b'')
对于 Python 3.5+,建议使用 subprocess 模块中的 run 函数。它会返回一个 CompletedProcess
对象,您可以轻松地获取输出以及返回代码。
from subprocess import PIPE, run
command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)