如何在Python脚本中调用外部命令(就像我在Unix shell或Windows命令提示符下键入它一样)?
查看标准库中的子进程模块:
import subprocess subprocess.run(["ls", "-l"])
子进程与系统的优势在于它更灵活(您可以获得stdout,stderr,"真实"状态代码,更好的错误处理等等).
在官方文档建议子在替代使用os.system模块():
该子模块提供了产卵新的流程和检索其结果更加强大的工具; 使用该模块比使用此函数[
subprocess
] 更可取.
该" 与子模块更换旧的功能中"部分子文档可能有一些有益的食谱.
以下是调用外部程序的方法及其优缺点的摘要:
os.system("some_command with args")
将命令和参数传递给系统的shell.这很好,因为您实际上可以以这种方式一次运行多个命令并设置管道和输入/输出重定向.例如:
os.system("some_command < input_file | another_command > output_file")
但是,虽然这很方便,但您必须手动处理shell字符的转义,例如空格等.另一方面,这也允许您运行只是shell命令而不是外部程序的命令.请参阅文档.
stream = os.popen("some_command with args")
将做同样的事情,os.system
除了它给你一个类似文件的对象,你可以用来访问该进程的标准输入/输出.还有3种其他的popen变体,它们对i/o的处理方式略有不同.如果您将所有内容都作为字符串传递,那么您的命令将传递给shell; 如果你将它们作为列表传递,那么你不必担心逃避任何事情.请参阅文档.
模块的Popen
类subprocess
.这是为了取代它,os.popen
但由于如此全面而具有稍微复杂的缺点.例如,你会说:
print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
代替:
print os.popen("echo Hello World").read()
但是在一个统一的类而不是4个不同的popen函数中拥有所有选项是很好的.请参阅文档.
call
来自subprocess
模块的功能.这基本上就像Popen
类一样,并且接受所有相同的参数,但它只是等待命令完成并为您提供返回代码.例如:
return_code = subprocess.call("echo Hello World", shell=True)
请参阅文档.
如果您使用的是Python 3.5或更高版本,则可以使用新subprocess.run
功能,它与上述功能非常相似,但更灵活,并CompletedProcess
在命令完成执行时返回对象.
os模块还具有C程序中的所有fork/exec/spawn函数,但我不建议直接使用它们.
该subprocess
模块可能应该是你使用的.
最后请注意,对于所有方法,您将最终命令传递给shell作为字符串执行,并且您负责转义它.如果您传递的字符串的任何部分无法完全受信任,则会产生严重的安全隐患.例如,如果用户正在输入字符串的某些/任何部分.如果您不确定,请仅将这些方法与常量一起使用.为了给您一些暗示,请考虑以下代码:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
并想象用户输入"我的妈妈不爱我&& rm -rf /".
我通常使用:
import subprocess p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in p.stdout.readlines(): print line, retval = p.wait()
您可以随意使用stdout
管道中的数据执行所需操作.事实上,你可以简单地省略那些参数(stdout=
和stderr=
),它的行为就像os.system()
.
关于将子进程从调用进程中分离的一些提示(在后台启动子进程).
假设您想从CGI脚本启动一个长任务,即子进程应该比CGI脚本执行过程更长寿.
子流程模块docs的经典示例是:
import subprocess import sys # Some code here pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess # Some more code here
这里的想法是你不想在"调用子进程"行中等待,直到longtask.py完成.但目前尚不清楚在这个例子中"更多代码"这一行之后会发生什么.
我的目标平台是freebsd,但是开发是在windows上进行的,所以我首先在windows上遇到了问题.
在Windows(win xp)上,父进程在longtask.py完成其工作之前不会完成.这不是你想要的CGI脚本.问题不是Python特有的,在PHP社区中问题是一样的.
解决方案是将DETACHED_PROCESS 流程创建标志传递给win API中的基础CreateProcess函数.如果你碰巧安装了pywin32,你可以从win32process模块导入标志,否则你应该自己定义:
DETACHED_PROCESS = 0x00000008 pid = subprocess.Popen([sys.executable, "longtask.py"], creationflags=DETACHED_PROCESS).pid
/*UPD 2015.10.27 @eryksun在下面的评论中指出,语义正确的标志是CREATE_NEW_CONSOLE(0x00000010)*/
在freebsd上我们还有另一个问题:父进程完成后,它也会完成子进程.这也不是你想要的CGI脚本.一些实验表明问题似乎是在共享sys.stdout.工作解决方案如下:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
我没有检查其他平台上的代码,也不知道freebsd上行为的原因.如果有人知道,请分享您的想法.在Python中开始后台进程的Google搜索还没有任何亮点.
我建议使用子进程模块而不是os.system,因为它为你做了shell转义,因此更加安全:http://docs.python.org/library/subprocess.html
subprocess.call(['ping', 'localhost'])
import os cmd = 'ls -al' os.system(cmd)
如果要返回命令的结果,可以使用os.popen
.但是,从版本2.6开始,这已经被弃用,而不是子进程模块,其他答案已经很好地解决了.
import os os.system("your command")
请注意,这是危险的,因为未清除该命令.我把它留给你去谷歌搜索关于'os'和'sys'模块的相关文档.有一堆函数(exec*和spawn*)会做类似的事情.
有许多不同的库允许您使用Python调用外部命令.对于每个库,我已经给出了描述并显示了调用外部命令的示例.我用作示例的命令是ls -l
(列出所有文件).如果您想了解有关我列出的任何库的更多信息,并链接每个库的文档.
资料来源:
子流程:https://docs.python.org/3.5/library/subprocess.html
shlex:https://docs.python.org/3/library/shlex.html
os:https://docs.python.org/3.5/library/os.html
sh:https://amoffat.github.io/sh/
plumbum:https://plumbum.readthedocs.io/en/latest/
pexpect:https://pexpect.readthedocs.io/en/stable/
面料:http://www.fabfile.org/
特使:https://github.com/kennethreitz/envoy
命令:https://docs.python.org/2/library/commands.html
这些都是图书馆:
希望这可以帮助您决定使用哪个库:)
子
子进程允许您调用外部命令并将它们连接到它们的输入/输出/错误管道(stdin,stdout和stderr).子进程是运行命令的默认选择,但有时其他模块更好.
subprocess.run(["ls", "-l"]) # Run command subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
口
os用于"依赖于操作系统的功能".它也可以用来调用外部命令os.system
和os.popen
(注意:还有一个subprocess.popen).操作系统将始终运行shell,对于不需要或不知道如何使用的人来说,它是一个简单的选择subprocess.run
.
os.system("ls -l") # run command os.popen("ls -l").read() # This will run the command and return any output
SH
sh是一个子进程接口,它允许您像调用函数一样调用程序.如果要多次运行命令,这非常有用.
sh.ls("-l") # Run command normally ls_cmd = sh.Command("ls") # Save command as a variable ls_cmd() # Run command as if it were a function
铅
plumbum是一个用于"类似脚本"的Python程序的库.您可以调用类似函数的程序sh
.如果要运行没有shell的管道,Plumbum很有用.
ls_cmd = plumbum.local("ls -l") # get command ls_cmd() # run command
Pexpect的
pexpect允许您生成子应用程序,控制它们并在其输出中查找模式.对于期望在Unix上使用tty的命令,这是替代子进程的更好的替代方法.
pexpect.run("ls -l") # Run command as normal child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application child.expect('Password:') # When this is the output child.sendline('mypassword')
布
fabric是一个Python 2.5和2.7库.它允许您执行本地和远程shell命令.Fabric是在安全shell(SSH)中运行命令的简单替代方法
fabric.operations.local('ls -l') # Run command as normal fabric.operations.local('ls -l', capture = True) # Run command and receive output
使者
特使被称为"人类的子过程".它被用作subprocess
模块周围的便利包装器.
r = envoy.run("ls -l") # Run command r.std_out # get output
命令
commands
包含包装函数os.popen
,但它已从Python 3中删除,因为它subprocess
是一个更好的选择.
该编辑基于JF Sebastian的评论.
检查"pexpect"Python库.
它允许交互式控制外部程序/命令,甚至ssh,ftp,telnet等.你可以输入如下内容:
child = pexpect.spawn('ftp 192.168.0.24') child.expect('(?i)name .*: ') child.sendline('anonymous') child.expect('(?i)password')
我总是使用fabric
这样的东西:
from fabric.operations import local result = local('ls', capture=True) print "Content:/n%s" % (result, )
但这似乎是一个很好的工具:( sh
Python子进程接口).
看一个例子:
from sh import vgdisplay print vgdisplay() print vgdisplay('-v') print vgdisplay(v=True)
如果您需要从您所呼叫的命令的输出,那么你可以使用subprocess.check_output(Python的2.7+).
>>> subprocess.check_output(["ls", "-l", "/dev/null"]) 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
另请注意shell参数.
如果是shell
True
,则将通过shell执行指定的命令.如果您主要使用Python来提供它在大多数系统shell上提供的增强控制流,并且仍然希望方便地访问其他shell功能,例如shell管道,文件名通配符,环境变量扩展以及将〜扩展到用户家中,这将非常有用.目录.但是请注意,Python本身提供了很多贝壳般的功能实现(特别是glob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
,和shutil
).
使用子进程模块(Python 3):
import subprocess subprocess.run(['ls', '-l'])
这是推荐的标准方式.但是,更复杂的任务(管道,输出,输入等)构造和写入可能很繁琐.
关于Python版本的注意事项:如果您仍在使用Python 2,则subprocess.call以类似的方式工作.
ProTip:shlex.split可以帮助你解析for 和其他函数的命令run
,以防你不想要(或者你不能!)以列表的形式提供它们:call
subprocess
import shlex import subprocess subprocess.run(shlex.split('ls -l'))具有外部依赖性
如果您不介意外部依赖项,请使用plumbum:
from plumbum.cmd import ifconfig print(ifconfig['wlan0']())
它是最好的subprocess
包装纸.它是跨平台的,即它适用于Windows和类Unix系统.安装方式pip install plumbum
.
另一种流行的库是SH:
from sh import ifconfig print(ifconfig('wlan0'))
但是,sh
Windows支持下降,所以它不像过去那样棒.安装方式pip install sh
.
这就是我运行命令的方式.此代码包含您需要的所有内容
from subprocess import Popen, PIPE cmd = "ls -l ~/" p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE) out, err = p.communicate() print "Return code: ", p.returncode print out.rstrip(), err.rstrip()
subprocess.run
如果您的代码不需要保持与早期Python版本的兼容性,那么从Python 3.5开始是推荐的方法.它更加一致,并提供与Envoy类似的易用性.(虽然管道不是那么简单.请参阅这个问题.)
以下是文档中的一些示例.
运行一个过程:
>>> 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"], stdout=subprocess.PIPE) 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')原始答案:
我建议尝试特使.它是子进程的包装器,后者又旨在替换旧的模块和功能.特使是人类的子过程.
自述文件的用法示例:
>>> r = envoy.run('git config', data='data to pipe in', timeout=2) >>> r.status_code 129 >>> r.std_out 'usage: git config [options]' >>> r.std_err ''
管道周围的东西:
>>> r = envoy.run('uptime | pbcopy') >>> r.command 'pbcopy' >>> r.status_code 0 >>> r.history []
没有结果的输出:
import os os.system("your command here")
输出结果:
import commands commands.getoutput("your command here") or commands.getstatusoutput("your command here")
https://docs.python.org/2/library/subprocess.html
......或者是一个非常简单的命令:
import os os.system('cat testfile')
还有Plumbum
>>> from plumbum import local >>> ls = local["ls"] >>> ls LocalCommand() >>> ls() u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n' >>> notepad = local["c:\\windows\\notepad.exe"] >>> notepad() # Notepad window pops up u'' # Notepad window is closed by user, command returns
在Python中调用外部命令
简单,使用subprocess.run
,返回一个CompletedProcess
对象:
>>> import subprocess >>> completed_process = subprocess.run('python --version') Python 3.6.1 :: Anaconda 4.4.0 (64-bit) >>> completed_process CompletedProcess(args='python --version', returncode=0)
从Python 3.5开始,文档推荐使用subprocess.run:
调用子进程的推荐方法是对它可以处理的所有用例使用run()函数.对于更高级的用例,可以直接使用底层的Popen接口.
以下是最简单的使用示例 - 它完全按照要求执行:
>>> import subprocess >>> completed_process = subprocess.run('python --version') Python 3.6.1 :: Anaconda 4.4.0 (64-bit) >>> completed_process CompletedProcess(args='python --version', returncode=0)
run
等待命令成功完成,然后返回一个CompletedProcess
对象.它可能会提高TimeoutExpired
(如果你给它一个timeout=
参数)或CalledProcessError
(如果它失败并且你通过check=True
).
正如您可能从上面的示例中推断的那样,默认情况下,stdout和stderr都会通过管道输出到您自己的stdout和stderr.
我们可以检查返回的对象并查看给出的命令和返回码:
>>> completed_process.args 'python --version' >>> completed_process.returncode 0
如果要捕获输出,可以传递subprocess.PIPE
给相应的stderr
或stdout
:
>>> cp = subprocess.run('python --version', stderr=subprocess.PIPE, stdout=subprocess.PIPE) >>> cp.stderr b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n' >>> cp.stdout b''
(我觉得有趣且有点违反直觉,版本信息被放到stderr而不是stdout.)
人们可以轻松地从手动提供命令字符串(如问题建议)到提供以编程方式构建的字符串.不要以编程方式构建字符串.这是一个潜在的安全问题.假设你不相信输入,那就更好了.
>>> import textwrap >>> args = ['python', textwrap.__file__] >>> cp = subprocess.run(args, stdout=subprocess.PIPE) >>> cp.stdout b'Hello there.\r\n This is indented.\r\n'
注意,只args
应该通过位置传递.
这是源中的实际签名,如下所示help(run)
:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
该popenargs
和kwargs
被给予Popen
的构造.input
可以是一串字节(或unicode,如果指定编码或universal_newlines=True
)将通过管道传递到子进程的stdin.
文档描述timeout=
并且check=True
比我更好:
timeout参数传递给Popen.communicate().如果超时到期,子进程将被终止并等待.子进程终止后,将重新引发TimeoutExpired异常.
如果check为true,并且进程以非零退出代码退出,则将引发CalledProcessError异常.该异常的属性包含参数,退出代码以及stdout和stderr(如果它们被捕获).
这个例子check=True
比我想出的更好:
>>> 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(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
请注意,这表示只应按位置传递args列表.因此将剩余的参数作为关键字参数传递.
什么时候使用Popen
?我很难根据论据单独找到用例.Popen
但是,直接使用poll
will 会让您访问其方法,包括'send_signal','terminate'和'wait'.
这是源中Popen
给出的签名.我认为这是对信息的最精确封装(相对于):help(Popen)
def __init__(self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None):
但更多的是信息的Popen
文档:
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)在新进程中执行子程序.在POSIX上,该类使用os.execvp() - 类似行为来执行子程序.在Windows上,该类使用Windows CreateProcess()函数.Popen的论点如下.
了解剩余的文档Popen
将留给读者练习.
os.system
没关系,但有点过时了.它也不是很安全.相反,试试吧subprocess
. subprocess
不直接调用sh,因此比安全更安全os.system
.
在这里获取更多信息.
使用:
import os cmd = 'ls -al' os.system(cmd)
os - 此模块提供了一种使用操作系统相关功能的便携方式.
对于更多的os
功能,这里是文档.
它可以很简单:
import os cmd = "your command" os.system(cmd)
使用os模块
import os os.system("your command")
例如
import os os.system("ifconfig")
这里有另一个不同之处,前面没有提到过.
subprocess.Popen
执行
我尝试了subprocess,执行成功了.但是无法与通信.当我从终端运行时,一切正常.
还有一个:(注意:kwrite的行为与其他应用程序不同.如果您使用Firefox尝试以下操作,结果将不同.)
如果您尝试os.system("kwrite")
,程序流冻结,直到用户关闭kwrite.为了克服这一点,我尝试了os.system(konsole -e kwrite)
.这个时间程序继续流动,但kwrite成为控制台的子进程.
任何人都运行kwrite不是一个子进程(即在系统监视器中它必须出现在树的最左边).
我非常喜欢shell_command,因为它简单.它建立在子进程模块之上.
以下是文档中的示例:
>>> from shell_command import shell_call >>> shell_call("ls *.py") setup.py shell_command.py test_shell_command.py 0 >>> shell_call("ls -l *.py") -rw-r--r-- 1 ncoghlan ncoghlan 391 2011-12-11 12:07 setup.py -rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py -rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py 0
subprocess.check_call
如果您不想测试返回值,这很方便.它会在任何错误上抛出异常.
我倾向于将子进程与shlex一起使用(以处理引用字符串的转义):
>>> import subprocess, shlex >>> command = 'ls -l "/your/path/with spaces/"' >>> call_params = shlex.split(command) >>> print call_params ["ls", "-l", "/your/path/with spaces/"] >>> subprocess.call(call_params)
os.system
不允许您存储结果,因此如果您想将结果存储在某个列表或某些subprocess.call
工作中.
无耻的插件,我为此写了一个库:P https://github.com/houqp/shell.py
它现在基本上是popen和shlex的包装器.它还支持管道命令,因此您可以在Python中更轻松地链接命令.所以你可以这样做:
ex('echo hello shell.py') | "awk '{print $2}'"
您可以使用Popen,然后您可以检查程序的状态:
from subprocess import Popen proc = Popen(['ls', '-l']) if proc.poll() is None: proc.kill()
检查subprocess.Popen.
在Windows中你可以导入subprocess
模块,并通过调用运行外部命令subprocess.Popen()
,subprocess.Popen().communicate()
并subprocess.Popen().wait()
如下:
# Python script to run a command line import subprocess def execute(cmd): """ Purpose : To execute a command and return exit status Argument : cmd - command to execute Return : exit_code """ process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (result, error) = process.communicate() rc = process.wait() if rc != 0: print "Error: failed to execute command:", cmd print error return result # def command = "tasklist | grep python" print "This process detail: \n", execute(command)
输出:
This process detail: python.exe 604 RDP-Tcp#0 4 5,660 K
在Linux下,如果你想调用一个独立执行的外部命令(将在python脚本终止后继续运行),你可以使用一个简单的队列作为任务假脱机程序或at命令
任务假脱机程序的示例:
import os os.system('ts')
有关任务假脱机程序(ts
)的说明:
您可以使用以下命令设置要运行的并发进程数("slots"):
ts -S
安装ts
不需要管理员权限.您可以从源代码下载并编译它make
,只需将其添加到您的路径中即可完成.
Invoke是一个Python(2.7和3.4+)任务执行工具和库.它为运行shell命令提供了一个干净的高级API
>>> from invoke import run >>> cmd = "pip install -r requirements.txt" >>> result = run(cmd, hide=True, warn=True) >>> print(result.ok) True >>> print(result.stdout.splitlines()[-1]) Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
运行任何命令并获得结果的最简单方法:
from commands import getstatusoutput try: return getstatusoutput("ls -ltr") except Exception, e: return None
从openstack中子获取网络ID:
#!/usr/bin/python import os netid = "nova net-list | awk '/ External / { print $2 }'" temp = os.popen(netid).read() /* Here temp also contains new line (\n) */ networkId = temp.rstrip() print(networkId)
新星网表的输出
+--------------------------------------+------------+------+ | ID | Label | CIDR | +--------------------------------------+------------+------+ | 431c9014-5b5d-4b51-a357-66020ffbb123 | test1 | None | | 27a74fcd-37c0-4789-9414-9531b7e3f126 | External | None | | 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None | | 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal | None | +--------------------------------------+------------+------+
打印输出(networkId)
27a74fcd-37c0-4789-9414-9531b7e3f126
这是我的两分钱:在我看来,这是处理外部命令时的最佳做法......
这些是execute方法的返回值......
pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
这是执行方法......
def execute(cmdArray,workingDir): stdout = '' stderr = '' try: try: process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1) except OSError: return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!'] for line in iter(process.stdout.readline, b''): try: echoLine = line.decode("utf-8") except: echoLine = str(line) stdout += echoLine for line in iter(process.stderr.readline, b''): try: echoLine = line.decode("utf-8") except: echoLine = str(line) stderr += echoLine except (KeyboardInterrupt,SystemExit) as err: return [False,'',str(err)] process.stdout.close() returnCode = process.wait() if returnCode != 0 or stderr != '': return [False, stdout, stderr] else: return [True, stdout, stderr]
通常,我将以下函数用于外部命令,这对于长时间运行的进程尤其方便.下面的方法尾部过程输出 ,同时它正在运行并返回输出,引发一个例外,如果过程将失败.
如果在进程上使用poll()方法完成该过程,则会出现.
import subprocess,sys def exec_long_running_proc(command, args): cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args)) print(cmd) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Poll process for new output until finished while True: nextline = process.stdout.readline().decode('UTF-8') if nextline == '' and process.poll() is not None: break sys.stdout.write(nextline) sys.stdout.flush() output = process.communicate()[0] exitCode = process.returncode if (exitCode == 0): return output else: raise Exception(command, exitCode, output)
你可以像这样调用它:
exec_long_running_proc(command = "hive", args=["-f", hql_path])
作为一个例子(在Linux中):
import subprocess subprocess.run('mkdir test.dir', shell=True)
这将在当前目录中创建test.dir.请注意,这也有效:
import subprocess subprocess.call('mkdir test.dir', shell=True)
使用os.system的等效代码是:
import os os.system('mkdir test.dir')
最佳实践是使用subprocess而不是os,.run优于.call.您需要了解的有关子进程的所有信息.另请注意,所有Python文档都可从此处下载.我下载了打包为.zip的PDF文件.我之所以提到这一点是因为在tutorial.pdf(第81页)中对os模块进行了很好的概述.此外,它是Python编码人员的权威资源.
我写了一个小库来帮助解决这个用例:
https://pypi.org/project/citizenshell/
可以使用安装
pip install citizenshell
然后使用如下:
from citizenshell import sh assert sh("echo Hello World") == "Hello World"
您可以将stdout与stderr分开,并提取退出代码,如下所示:
result = sh(">&2 echo error && echo output && exit 13") assert result.stdout() == ["output"] assert result.stderr() == ["error"] assert result.exit_code() == 13
而且很酷的事情是,您不必在开始处理输出之前就等待底层shell退出:
for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False) print ">>>", line + "!"
由于wait = False,将打印可用的行
>>> It is 14:24:52! >>> It is 14:24:53! >>> It is 14:24:54! >>> It is 14:24:55!
更多示例可以在https://github.com/meuter/citizenshell找到
可以使用两种主要方式使用Python执行Shell命令。以下两个示例均展示了如何pwd
使用Python 获取当前工作目录()的名称。您可以使用任何其他Unix命令代替pwd
。
1.>第一种方法:可以使用Python中的os模块,然后使用system()函数在Python中执行shell命令。
import os os.system('pwd')
输出:
/Users/siddharth
1.>第二种方法:另一种方法是使用子流程模块和call()函数。
import subprocess subprocess.call('pwd')
输出:
/Users/siddharth
只是为了添加讨论,如果您使用Python控制台,则可以从IPython调用外部命令.在IPython提示符下,您可以通过前缀'!'来调用shell命令.您还可以将Python代码与shell结合使用,并将shell脚本的输出分配给Python变量.
例如:
In [9]: mylist = !ls In [10]: mylist Out[10]: ['file1', 'file2', 'file3',]
在Python中调用外部命令
调用外部命令的一种简单方法是使用os.system(...)
.此函数返回命令的退出值.但缺点是我们不会得到stdout和stderr.
ret = os.system('some_cmd.sh') if ret != 0 : print 'some_cmd.sh execution returned failure'
在后台调用Python中的外部命令
subprocess.Popen
为运行外部命令而不是使用提供了更大的灵活性os.system
.我们可以在后台启动命令并等待它完成.之后我们可以得到stdout和stderr.
proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE) print 'waiting for ' + str(proc.pid) proc.wait() print 'some_cmd.sh execution finished' (out, err) = proc.communicate() print 'some_cmd.sh output : ' + out
在后台调用Python中长时间运行的外部命令,并在一段时间后停止
我们甚至可以在后台启动一个长时间运行的进程,subprocess.Popen
并在完成任务后的某个时间终止它.
proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE) # Do something else # Now some_long_run_cmd.sh exeuction is no longer needed, so kill it os.system('kill -15 ' + str(proc.pid)) print 'Output : ' proc.communicate()[0]
在Python中运行外部命令有很多种不同的方法,所有这些方法都有自己的优缺点.
我的同事和我一直在编写Python系统管理工具,因此我们需要运行大量外部命令,有时您希望它们以异步方式阻塞或运行,超时,每秒更新等.
还有不同的方法来处理返回代码和错误,您可能想要解析输出,并提供新的输入(以期望的样式).或者您需要重定向stdin,stdout和stderr以在不同的tty中运行(例如,在使用屏幕时).
所以你可能不得不围绕外部命令编写很多包装器.所以这里有一个Python模块,我们已经编写了几乎可以处理你想要的任何东西,如果没有,它非常灵活,所以你可以轻松扩展它:
https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py
使用:
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 Subprocess check_output很适合
使用参数运行命令并将其输出作为字节字符串返回.
import subprocess proc = subprocess.check_output('ipconfig /all') print proc
如果您需要从Python笔记本(如Jupyter,Zeppelin,Databricks或Google Cloud Datalab)调用shell命令,则可以仅使用!
前缀。
例如,
!ls -ilF
一种简单的方法是使用os模块:
import os os.system('ls')
或者,您也可以使用子流程模块:
import subprocess subprocess.check_call('ls')
如果要将结果存储在变量中,请尝试:
import subprocess r = subprocess.check_output('ls')
对于Python 3.5+,建议您使用子进程模块中的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)