Python Subprocess命令作为List Not String

Phi*_*aun 2 python subprocess

我需要使用Python中的子进程模块通过重定向stdout来创建一些新文件.我不想shell=True因为安全漏洞而使用.

我写了一些测试命令来解决这个问题,我发现这有效:

import subprocess as sp
filer = open("testFile.txt", 'w')
sp.call(["ls", "-lh"], stdout=filer)
filer.close()
Run Code Online (Sandbox Code Playgroud)

但是,当我将命令作为一个长字符串而不是列表传递时,它找不到该文件.所以当我写这篇文章时:

import subprocess as sp
filer = open("testFile.txt", 'w')
sp.call("ls -lh", stdout=filer)
filer.close()
Run Code Online (Sandbox Code Playgroud)

我收到了这个错误:

Traceback (most recent call last):
  File "./testSubprocess.py", line 16, in <module>
    sp.call(command2, stdout=filer)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 524, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1308, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
Run Code Online (Sandbox Code Playgroud)

如果我将参数作为字符串或列表传递,为什么重要?

Bri*_*ain 5

如果您希望像在shell中那样划分字符串,请使用shlex:

import subprocess as sp
import shlex
with open("testFile.txt", 'w') as filer:
    sp.call(shlex.split("ls -lh"), stdout=filer)
Run Code Online (Sandbox Code Playgroud)

顺便说一下,让我check_call在这里做个案.没有它,例如,如果添加了无效参数,则会得到空输出.你会想知道为什么输出filer为空.

with open("testFile.txt", 'w') as filer:
    sp.check_call(shlex.split("ls -lh0"), stdout=filer)
Run Code Online (Sandbox Code Playgroud)

随着check_call您收到一个错误,本地化问题并阻止后续代码执行:

Traceback (most recent call last):
  File "go.py", line 6, in <module>
    sp.check_call(shlex.split("ls -lh0"), stdout=filer)
  File "/usr/lib/python2.7/subprocess.py", line 540, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', '-lh0']' returned non-zero exit status 2
Run Code Online (Sandbox Code Playgroud)


glg*_*lgl 5

这是因为调用的方式:

使用shell=True,通过shell执行调用,并将命令作为一个字符串提供给shell.

通过shell=False,直接,通过execv()和相关功能执行调用.这些函数会释放一组参数.

如果只传递一个字符串,则将其视为仅具有不带参数的可执行文件名称的调用的缩写.但是(可能)ls -lh您的系统上没有调用可执行文件.

确切地说,在内部某处subprocess.py,发生以下情况:

        if isinstance(args, types.StringTypes):
            args = [args]
        else:
            args = list(args)
Run Code Online (Sandbox Code Playgroud)

因此传递的每个字符串都会变成一个包含一个元素的列表.

        if shell:
            args = ["/bin/sh", "-c"] + args
Run Code Online (Sandbox Code Playgroud)

这个我不知道:很明显,这允许将其他参数传递给被调用的shell.虽然以这种方式记录,但不要使用它,因为它会产生太多的混淆.

如果shell=False,我们进一步下面

if env is None:
    os.execvp(executable, args)
else:
    os.execvpe(executable, args, env)
Run Code Online (Sandbox Code Playgroud)

它只需一个列表并将其用于呼叫.