如何调用外部命令?

nuypyhwy  于 2021-05-29  发布在  Hadoop
关注(0)|答案(11)|浏览(464)

如何从python脚本中调用外部命令(就像我在unixshell或windows命令提示符下键入的一样)?

oalqel3c

oalqel3c1#

下面总结了调用外部程序的方法以及每种方法的优缺点: 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 只是它提供了一个类似文件的对象,您可以使用它访问该进程的标准输入/输出。popen还有另外3种变体,它们处理i/o的方式都略有不同。如果您将所有内容作为字符串传递,那么您的命令将传递给shell;如果你把它们作为一个列表来传递,那么你就不必担心会漏掉任何东西。请参阅文档。
这个 Popensubprocess 模块。这是为了取代 os.popen 但缺点是,由于如此全面,情况稍微复杂一些。例如,你会说:

print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

而不是:

print os.popen("echo Hello World").read()

但是将所有的选项放在一个统一的类中而不是4个不同的popen函数中是很好的。请参阅文档。
这个 callsubprocess 模块。这基本上就像 Popen 类并接受所有相同的参数,但它只是等待命令完成并给出返回代码。例如:

return_code = subprocess.call("echo Hello World", shell=True)

请参阅文档。
如果您使用的是python3.5或更高版本,那么可以使用新的 subprocess.run 函数,它与上面的函数非常相似,但更加灵活,并返回 CompletedProcess 对象。
os模块还具有c程序中的所有fork/exec/spawn函数,但我不建议直接使用它们。
这个 subprocess 模块应该是您所使用的。
最后,请注意,对于所有方法,您传递的最终命令将由shell作为字符串执行,并且您负责转义它。如果您传递的字符串的任何部分都不能被完全信任,则会产生严重的安全隐患。例如,如果用户正在输入字符串的某些/任何部分。如果不确定,请仅对常量使用这些方法。要给您一个暗示,请考虑以下代码:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

想象一下,用户输入了“我妈妈不爱我&&rm-rf/”这样就可以删除整个文件系统。

8fq7wneg

8fq7wneg2#

有许多不同的库允许您使用python调用外部命令。对于每个库,我都给出了一个描述,并展示了一个调用外部命令的示例。我用的命令是 ls -l (列出所有文件)。如果您想了解更多关于我列出的任何库的信息,并链接每个库的文档。
资料来源:
子流程:https://docs.python.org/3.5/library/subprocess.html
shlex公司:https://docs.python.org/3/library/shlex.html
操作系统:https://docs.python.org/3.5/library/os.html
上海:https://amoffat.github.io/sh/
铅:https://plumbum.readthedocs.io/en/latest/
期望值: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.system 以及 os.popen (注意:还有一个子流程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.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 . 如果你想在没有外壳的情况下运行管道,铅是很有用的。

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

预期
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是一个python2.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

特使
特使被称为“人类的子进程”。它是用来作为一个方便的 Package 周围 subprocess 模块。

r = envoy.run("ls -l") # Run command
r.std_out # get output

命令 commands 包含的 Package 函数 os.popen ,但它已从python3中删除 subprocess 是更好的选择。
编辑是基于j.f.塞巴斯蒂安的评论。

vwhgwdsa

vwhgwdsa3#

import os
os.system("your command")

注意,这是危险的,因为命令没有被清除。我把‘os’和‘sys’模块的相关文档交给google。有一系列函数(exec和spawn)将执行类似的操作。

f8rj6qna

f8rj6qna4#

我建议使用subprocess模块而不是os.system,因为它可以为您进行shell转义,因此更安全。

subprocess.call(['ping', 'localhost'])
1mrurvl1

1mrurvl15#

也可以查看“pexpect”python库。
它允许交互控制外部程序/命令,甚至ssh、ftp、telnet等。您可以键入以下内容:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')
des4xlb0

des4xlb06#

import os
cmd = 'ls -al'
os.system(cmd)

如果要返回命令的结果,可以使用 os.popen . 但是,由于版本2.6支持子流程模块,这一点已被弃用,其他答案已经很好地涵盖了子流程模块。

46qrfjad

46qrfjad7#

关于从调用进程分离子进程(在后台启动子进程)的一些提示。
假设您想从一个cgi脚本开始一个长任务。也就是说,子进程的寿命应该比cgi脚本执行进程长。
子流程模块文档中的经典示例是:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

这里的想法是,您不希望在longtask.py完成之前在“callsubprocess”行中等待。但不清楚在示例中的“这里有更多代码”一行之后会发生什么。
我的目标平台是freebsd,但是开发是在windows上进行的,所以我首先在windows上面对这个问题。
在windows上(windows 在longtask.py完成其工作之前,父进程不会完成。这不是你想要的cgi脚本。这个问题不是python特有的;在php社区中,问题是相同的。
解决方案是将分离的进程创建标志传递给windowsapi中的底层createprocess函数。如果碰巧安装了pywin32,可以从win32process模块导入标志,否则应该自己定义:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/upd 2015.10.27@eryksun在下面的评论中指出,语义正确的标志是create\u new\u 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启动后台进程还不能说明什么。

sxpgvts3

sxpgvts38#

查看标准库中的子流程模块:

import subprocess
subprocess.run(["ls", "-l"])

优势 subprocess 与。 system 是因为它更灵活(你可以得到 stdout , stderr ,真正的状态码,更好的错误处理等等。
官方文件建议 subprocess 替代方案模块 os.system() :
这个 subprocess 模块提供了更强大的工具来产生新的进程和检索它们的结果;使用该模块比使用此函数更好[ os.system() ].
中的“用子流程模块替换旧函数”部分 subprocess 文档可能有一些有用的方法。
对于3.5之前的python版本,请使用 call :

import subprocess
subprocess.call(["ls", "-l"])
3htmauhk

3htmauhk9#

典型实施:

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() .

am46iovg

am46iovg10#

使用标准库

使用子流程模块(python 3):

import subprocess
subprocess.run(['ls', '-l'])

这是推荐的标准方式。但是,更复杂的任务(管道、输出、输入等)在构造和编写时可能会非常繁琐。
关于python版本的注意事项:如果您仍在使用python2,subprocess.call的工作方式类似。
protip:shlex.split可以帮助您解析 run , call ,和其他 subprocess 如果你不想要(或者你不能!)以列表形式提供:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

具有外部依赖关系

如果您不介意外部依赖关系,请使用plumbum:

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

这是最好的 subprocess Package 器。它是跨平台的,也就是说,它可以在windows和类unix系统上工作。安装方式 pip install plumbum .
另一个流行的图书馆是sh:

from sh import ifconfig
print(ifconfig('wlan0'))

然而, sh 放弃了对windows的支持,所以它不像以前那么棒了。安装方式 pip install sh .

xmjla07d

xmjla07d11#

我总是用 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)

相关问题