如何从Python
脚本中调用外部命令(就像我在Unix shell或Windows命令提示符下键入它一样)?
看看标准库中的subprocess module:
import subprocess
subprocess.run(["ls", "-l"])
子进程与系统的优势在于它更灵活(您可以获得stdout,stderr,“真实”状态代码,更好的错误处理等等)。
official documentation推荐使用替代os.system()的子进程模块:
子流程模块提供了更强大的工具来生成新流程并检索其结果;使用该模块比使用此函数[
os.system()
]更可取。
子流程文档中的“Replacing Older Functions with the subprocess Module”部分可能有一些有用的配方。
旧版本的Python使用调用:
import subprocess
subprocess.call(["ls", "-l"])
检查“pexpect”Python库。
它允许交互式控制外部程序/命令,甚至ssh,ftp,telnet等。你可以输入如下内容:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
如果您需要调用命令的输出,则可以使用sh
(Python subprocess interface)(Python 2.7+)。
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
另请注意child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
参数。
如果shell是subprocess.check_output,则指定的命令将通过shell执行。如果您主要使用Python来提供它在大多数系统shell上提供的增强控制流,并且仍然希望方便地访问其他shell功能,例如shell管道,文件名通配符,环境变量扩展以及将〜扩展到用户家中,这将非常有用。目录。但请注意,Python本身提供了许多类似shell的功能(特别是
>>> subprocess.check_output(["ls", "-l", "/dev/null"]) 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
,shell,True
,glob
,fnmatch
和os.walk()
)的实现。
使用os.path.expandvars()
(Python 3):
os.path.expanduser()
这是推荐的标准方式。但是,更复杂的任务(管道,输出,输入等)构造和写入可能很繁琐。
关于Python版本的注意事项:如果您仍在使用Python 2,则shutil
的工作方式类似。
ProTip:subprocess module可以帮助您解析import subprocess
subprocess.run(['ls', '-l'])
,subprocess.call和其他shlex.split函数的命令,以防您不希望(或者您不能!)以列表的形式提供它们:
run
如果您不介意外部依赖项,请使用qazxsw poi:
call
这是最好的subprocess
包装。它是跨平台的,即它适用于Windows和类Unix系统。由import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
安装。
另一个受欢迎的图书馆是plumbum:
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
然而,subprocess
放弃了Windows支持,所以它不像过去那样棒。由pip install plumbum
安装。
这就是我运行命令的方式。此代码包含您需要的所有内容
sh
如果您的代码不需要保持与早期Python版本的兼容性,那么from sh import ifconfig
print(ifconfig('wlan0'))
是推荐的方法sh
。它更加一致,并提供与Envoy类似的易用性。 (虽然管道不是那么简单。请参阅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
提高失败的运行:
as of Python 3.5
捕获输出:
this question for how
我建议尝试the docs。它是子进程的包装器,后者反过来>>> 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')
管道周围的东西:
Envoy
>>> 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
[<Response 'uptime'>]
还有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没有直接打电话给sh,因此比>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> 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
更安全。
获取更多信息os.system
。
在Python中调用外部命令
简单,使用subprocess
,它返回一个subprocess
对象:
os.system
从Python 3.5开始,文档推荐使用here:
调用子进程的推荐方法是对它可以处理的所有用例使用run()函数。对于更高级的用例,可以直接使用底层的Popen接口。
以下是最简单的使用示例 - 它完全按照要求执行:
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)
对象。它可能会提高subprocess.run(如果你给它一个>>> 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
)。
正如您可能从上面的示例中推断的那样,默认情况下,stdout和stderr都会通过管道输出到您自己的stdout和stderr。
我们可以检查返回的对象并查看给出的命令和返回码:
TimeoutExpired
如果要捕获输出,可以将timeout=
传递给相应的CalledProcessError
或check=True
:
>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
(我觉得有趣且有点违反直觉,版本信息被放到stderr而不是stdout。)
人们可以轻松地从手动提供命令字符串(如问题建议)到提供以编程方式构建的字符串。不要以编程方式构建字符串。这是一个潜在的安全问题。假设你不相信输入,那就更好了。
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''
>>> 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):
可以是一串字节(或unicode,如果指定编码或popenargs
),它将被传送到子进程的stdin。
该文档比我更好地描述了kwargs
和Popen
:
timeout参数传递给Popen.communicate()。如果超时到期,子进程将被终止并等待。子进程终止后,将重新引发TimeoutExpired异常。
如果check为true,并且进程以非零退出代码退出,则将引发CalledProcessError异常。该异常的属性包含参数,退出代码以及stdout和stderr(如果它们被捕获)。
而这个input
的例子比我想出的更好:
universal_newlines=True
这是一个扩展的签名,如文档中所示:
timeout=
请注意,这表示只应按位置传递args列表。因此将剩余的参数作为关键字参数传递。
当使用check=True
而不是?我很难根据论据单独找到用例。但是,直接使用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
,'send_signal','terminate'和'wait'。
这是subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
shell=False, cwd=None, timeout=None, check=False, encoding=None,
errors=None)
中给出的Popen
签名。我认为这是对信息的最精确封装(与Popen
相反):
poll
但更多信息是Popen
:
the source在新进程中执行子程序。在POSIX上,该类使用os.execvp() - 类似行为来执行子程序。在Windows上,该类使用Windows CreateProcess()函数。 Popen的论点如下。
理解help(Popen)
上的剩余文档将留给读者练习。
以下是调用外部程序的方法及其优缺点的摘要:
os.system("some_command with args")
将命令和参数传递给系统的shell。这很好,因为您实际上可以以这种方式一次运行多个命令并设置管道和输入/输出重定向。例如:
os.system("some_command < input_file | another_command > output_file")
但是,虽然这很方便,但您必须手动处理shell字符的转义,例如空格等。另一方面,这也允许您运行仅仅是shell命令而不是实际外部程序的命令。见the documentation。stream = os.popen("some_command with args")
将执行与os.system
相同的操作,除了它为您提供了一个类似文件的对象,您可以使用它来访问该进程的标准输入/输出。还有3种其他的popen变体,它们对i / o的处理方式略有不同。如果您将所有内容都作为字符串传递,那么您的命令将传递给shell;如果你将它们作为列表传递,那么你不必担心逃避任何事情。见the documentation。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函数中拥有所有选项是很好的。见the documentation。call
模块的subprocess
函数。这基本上就像Popen
类并采用所有相同的参数,但它只是等待命令完成并给你返回代码。例如:
return_code = subprocess.call("echo Hello World", shell=True)
见the documentation。subprocess.run
函数,它与上面的内容非常相似,但更灵活,并在命令完成执行时返回CompletedProcess
对象。subprocess
模块可能应该是你使用的。
最后请注意,对于所有方法,您将最终命令传递给shell作为字符串执行,并且您负责转义它。如果您传递的字符串的任何部分无法完全受信任,则会产生严重的安全隐患。例如,如果用户正在输入字符串的某些/任何部分。如果您不确定,请仅将这些方法与常量一起使用。为了给您一些暗示,请考虑以下代码:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
并且想象用户输入“我的妈妈不爱我&& rm -rf /”这可能会删除整个文件系统。
使用:
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):
os - 此模块提供了一种使用操作系统相关功能的便携方式。
对于更多the Popen
documentation函数,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)
是文档。
它可以很简单:
Popen
使用os模块
import os
cmd = 'ls -al'
os.system(cmd)
例如
os
如果您不想测试返回值,here很方便。它会在任何错误上抛出异常。
我倾向于使用import os
cmd = "your command"
os.system(cmd)
和import os
os.system("your command")
(处理引用字符串的转义):
import os
os.system("ifconfig")
这里有另一个不同之处,前面没有提到过。
subprocess.check_call
执行
作为子进程。在我的情况下,我需要执行需要与另一个程序通信的文件。
我尝试了subprocess,执行成功了。但是<b>无法与<a>通信。当我从终端运行时,一切正常。
还有一个:(注意:kwrite的行为与其他应用程序不同。如果您使用Firefox尝试以下操作,结果将不同。)
如果你尝试subprocess,程序流冻结,直到用户关闭kwrite。为了克服这一点,我尝试了shlex。这个时间程序继续流动,但kwrite成为控制台的子进程。
任何人都运行kwrite不是一个子进程(即在系统监视器中它必须出现在树的最左边)。
>>> 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)
不允许您存储结果,因此如果您想将结果存储在某些列表或subprocess.Popen
工作的东西。
我非常喜欢os.system("kwrite")
的简单性。它建立在子进程模块之上。
以下是文档中的示例:
os.system(konsole -e kwrite)
无耻的插件,我为此写了一个库:P os.system
它现在基本上是popen和shlex的包装器。它还支持管道命令,因此您可以在Python中更轻松地链接命令。所以你可以这样做:
subprocess.call
在Linux下,如果你想调用一个独立执行的外部命令(将在python脚本终止后继续运行),你可以使用一个简单的队列作为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
命令
任务假脱机程序的示例:
https://github.com/houqp/shell.py
关于任务假脱机程序的注释(ex('echo hello shell.py') | "awk '{print $2}'"
):
import os
os.system('ts <your-command>')
从源代码下载并编译它,将其添加到您的路径中,您就完成了。我通常使用:
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()
您可以使用管道中的qazxsw poi数据自由地执行您想要的操作。事实上,你可以简单地省略那些参数(qazxsw poi和qazxsw poi),它的行为就像stdout
。
您可以使用Popen,然后您可以检查程序的状态:
ts
看看ts -S <number-of-slots>
。
关于将子进程从调用进程中分离的一些提示(在后台启动子进程)。
假设您想从CGI脚本启动一个长任务,即子进程应该比CGI脚本执行过程更长寿。
子流程模块docs的经典示例是:
stdout=
这里的想法是你不想在“调用子进程”行中等待,直到longtask.py完成。但目前尚不清楚在这个例子中“更多代码”这一行之后会发生什么。
我的目标平台是freebsd,但开发是在windows上,所以我首先在windows上遇到了问题。
在Windows(win xp)上,父进程在longtask.py完成其工作之前不会完成。这不是你想要的CGI脚本。问题不是Python特有的,在PHP社区中问题是一样的。
解决方案是将DETACHED_PROCESS stderr=
传递给win API中的底层CreateProcess函数。如果你碰巧安装了pywin32,你可以从win32process模块导入标志,否则你应该自己定义:
os.system()
/ * UPD 2015.10.27 @eryksun在下面的评论中指出,语义正确的标志是CREATE_NEW_CONSOLE(0x00000010)* /
在freebsd上我们还有另一个问题:父进程完成后,它也会完成子进程。这也不是你想要的CGI脚本。一些实验表明问题似乎是在共享sys.stdout。工作解决方案如下:
import subprocess
import sys
# some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess
# some more code here
我没有检查其他平台上的代码,也不知道freebsd上行为的原因。如果有人知道,请分享您的想法。谷歌搜索Python中的后台进程并没有任何亮点。
我建议使用子进程模块而不是os.system,因为它会为你进行shell转义,因此更加安全:Process Creation Flag
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
如果要返回命令的结果,可以使用http://docs.python.org/library/subprocess.html。但是,自2.6版本以来,这已经被弃用了subprocess.call(['ping', 'localhost'])
,其他答案已经很好地解决了。
import os
cmd = 'ls -al'
os.system(cmd)
请注意,这是危险的,因为未清除该命令。我把它留给你去谷歌搜索关于'os'和'sys'模块的相关文档。有一堆函数(exec *和spawn *)会做类似的事情。
有许多不同的库允许您使用Python调用外部命令。对于每个库,我已经给出了描述并显示了调用外部命令的示例。我用作示例的命令是os.popen
(列出所有文件)。如果您想了解有关我列出的任何库的更多信息,并链接每个库的文档。
资料来源:
import os
os.system("your command")
ls -l
这些都是图书馆:
希望这可以帮助您决定使用哪个库:)
子
子进程允许您调用外部命令并将它们连接到它们的输入/输出/错误管道(stdin,stdout和stderr)。子进程是运行命令的默认选择,但有时其他模块更好。
http://www.fabfile.org/
该
os用于“依赖于操作系统的功能”。它还可以用于使用https://github.com/kennethreitz/envoy和https://docs.python.org/2/library/commands.html调用外部命令(注意:还有一个subprocess.popen)。操作系统将始终运行shell,对于那些不需要或不知道如何使用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.system
SH
sh是一个子进程接口,它允许您像调用函数一样调用程序。如果要多次运行命令,这非常有用。
os.popen
带领
plumbum是一个用于“类似脚本”的Python程序的库。您可以像subprocess.run
一样调用类似函数的程序。如果要运行没有shell的管道,Plumbum很有用。
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
Pexpect的
pexpect允许您生成子应用程序,控制它们并在其输出中查找模式。对于期望在Unix上使用tty的命令,这是替代子进程的更好的替代方法。
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
布
fabric是一个Python 2.5和2.7库。它允许您执行本地和远程shell命令。 Fabric是在安全shell(SSH)中运行命令的简单替代方法
sh
使者
特使被称为“人类的子过程”。它被用作围绕ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
模块的便利包装器。
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo [email protected]:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
命令
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
包含subprocess
的包装函数,但它已从Python 3中删除,因为r = envoy.run("ls -l") # Run command
r.std_out # get output
是一个更好的选择。
该编辑基于J.F. Sebastian的评论。
我总是使用commands
这样的事情:
os.popen
但这似乎是一个很好的工具:subprocess
。
看一个例子:
fabric