shlex.split的反向操作是什么?

44

如何将shlex.split的结果反转?也就是说,如何在给定带引号的字符串的情况下获得一个列表,该列表会"类似于Unix Shell", 给定我希望带引号的list字符串?

更新0

我已经发现了一个Python bug,并提出了相应的功能请求here


1
出于好奇,如果 subprocess.Popen 接受命令的列表(当 shell=False 时),为什么您需要这个呢? - tokland
@tokland: 我实际上没有使用 shlex.split 的输出来给 Popen 使用,我在解析用户提供的路径列表。我允许他们使用 shell 样式的分割。 - Matt Joiner
6个回答

30

1
subprocess.list2cmdline() 为什么被指定为私有方法?它没有前置下划线,并且在官方文档中也有提及! - Daniel Fortunov
shlex.quote 不适用于链式命令。例如,虚拟的 cmd = ['pwd', '&&', 'cd'] 会产生错误的命令:"pwd '&&' cd" - vedar
subprocess.list2cmdline() 看起来像是不同的命令,并且在链接符号方面表现正确,尽管它是为 Windows 设计的,但用户可以在 Popen 中传递列表(即使启用了 shell - shell=True)。 - vedar
2
也许在答案中添加如何使用 shlex.quote 的实际示例会更好?在 https://bugs.python.org/issue22454 中,他们建议使用 ' '.join(shlex.quote(x) for x in split_command) 应该就足够了。 - Matthijs Kooijman

20

使用pipes.quote如何?

import pipes
strings = ["ls", "/etc/services", "file with spaces"]
" ".join(pipes.quote(s) for s in strings)
# "ls /etc/services 'file with spaces'"

.


2
pipes.quote 不适用于 Windows。Windows 需要双引号。 - Nux

12

对于Python 3.7或更早版本,请参考Matthijs Kooijman的答案 - famzah

11

有一个功能请求,希望添加shlex.join(),它将完全实现您所要求的功能。截至目前,似乎没有任何进展,因为它大多只是转发到shlex.quote()。在错误报告中,提到了一种建议的实现方法:

' '.join(shlex.quote(x) for x in split_command)

请查看 https://bugs.python.org/issue22454


2
这正是Python当前实现的内容:3.9/Lib/shlex.py - famzah

6

subprocess使用subprocess.list2cmdline()。它不是官方公共API,但在subprocess文档中提到,并且我认为它是相当安全的。它比pipes.open()更复杂(好或坏都有可能)。


list2cmdline 仅在 Windows 上使用,因此它所执行的转义只适用于 Windows。 - Eric

0

虽然Python 3.3中提供了shlex.quote方法,而Python 3.8中提供了shlex.join方法,但它们并不总是作为shlex.split的真正“反转”而存在。请看下面的代码片段:

import shlex
command = "cd /home && bash -c 'echo $HOME'"
print(shlex.split(command))
# ['cd', '/home', '&&', 'bash', '-c', 'echo $HOME']
print(shlex.join(shlex.split(command)))
# cd /home '&&' bash -c 'echo $HOME'

请注意,在拆分和连接后,&&标记现在有单引号。如果您现在尝试运行命令,您将会收到一个错误:cd: too many arguments 如果您像其他人建议的那样使用subprocess.list2cmdline(),它可以更好地处理bash运算符,如&&
import subprocess
print(subprocess.list2cmdline(shlex.split(command)))
# cd /home && bash -c "echo $HOME"

然而,您现在可能会注意到引号现在是双引号而不是单引号。这使得 $HOME 被 shell 扩展而不是像使用单引号那样按原样打印。

总之,没有 100% 的可靠方法可以撤消 shlex.split,您将不得不选择最适合您目的的选项并注意边缘情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接