首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >驯服shlex.split()行为

驯服shlex.split()行为
EN

Stack Overflow用户
提问于 2021-11-10 07:48:18
回答 3查看 43关注 0票数 0

还有其他问题需要回答,但我有一个非常具体的用例,我很难解决。请考虑以下内容:

代码语言:javascript
复制
from asyncio import create_subprocess_exec, run


async def main():
    command = r'program.exe "C:\some folder" -o"\\server\share\some folder" "a \"quote\""'
    proc = await create_subprocess_exec(*command)
    await proc.wait()


run(main())

这会带来麻烦,因为program.exe是用以下参数调用的:

代码语言:javascript
复制
['C:\\some folder', '-o\\server\\share\\some folder', 'a "quote"']

也就是说,双反斜杠不再存在,因为shlex.split()将其删除。当然,我可以(正如其他答案所建议的)这样做:

代码语言:javascript
复制
    proc = await create_subprocess_exec(*command, posix=False)

但是,使用这些参数可以有效地调用program.exe

代码语言:javascript
复制
['"C:\\some folder"', '-o"\\\\server\\share\\some folder"', '"a \\"', 'quote\\""']

这也是不好的,因为现在双引号已经成为第一个参数内容的一部分,即使第二个参数现在是好的,但它们不属于那里。第三个参数已经变得一团糟。

由于类似的原因,用正斜杠替换反斜杠,或者用正则表达式删除引号都不起作用。

有什么方法可以让shlex.split()在服务器名称前单独保留双反斜杠吗?或者根本就是这样?为什么它首先要删除它们呢?

请注意,这些命令本身是完全有效的命令(无论如何,分别在Windows和Linux上):

代码语言:javascript
复制
program.exe "C:\some folder" -o"\\server\share\some folder"
echo "hello \"world""

即使我确实检测到了操作系统并相应地使用了posix=True/False,我仍然会使用第二个参数中包含的双引号,而这不应该是双引号。

EN

回答 3

Stack Overflow用户

发布于 2021-11-10 08:31:52

据我所知,如果您正在处理Windows shell,那么shlex模块是错误的工具。

文档的第一段说(我的斜体):

shlex类

使得编写简单语法的词法分析器变得很容易,类似于Unix shell。

诚然,这只涉及一个类,而不是整个模块。稍后,quote函数的文档显示(这一次以粗体显示):

警告shlex模块仅为Unix shell设计。

老实说,我不确定非Posix模式应该与什么兼容。有可能,但这只是我的猜测,shlex的原始版本解析了它自己的语法,它与其他任何东西都不太兼容,然后添加了Posix模式,以便实际上与Posix shell兼容。包括this mail from ESR在内的This mailing list thread似乎支持这一点。

票数 0
EN

Stack Overflow用户

发布于 2021-11-10 09:42:43

对于-o参数,但其开头的“不在中间,并且双反斜杠

然后使用posix=True

代码语言:javascript
复制
import shlex

command = r'program.exe "C:\some folder" -o"\\server\share\some folder" "a \"quote\""'

print( "Original command Posix=True", shlex.split(command, posix=True) )

command = r'program.exe "C:\some folder" "-o\\\\server\\share\\some folder" "a \"quote\""'

print( "Updated command Posix=True", shlex.split(command, posix=True) )

结果:

代码语言:javascript
复制
Original command Posix=True ['program.exe', 'C:\\some folder', '-o\\server\\share\\some folder', 'a "quote"']
Updated command Posix=True ['program.exe', 'C:\\some folder', '-o\\\\server\\share\\some folder', 'a "quote"']

结果中的反斜杠仍然是双斜杠,但这是字符串中\的标准Python表示。

票数 0
EN

Stack Overflow用户

发布于 2021-11-10 23:01:38

就目前而言,我最终得到了这个(可以说是一个小技巧):

代码语言:javascript
复制
from os import name as os_name
from shlex import split


def arg_split(args, platform=os_name):
    """
    Like calling shlex.split, but sets `posix=` according to platform 
    and unquotes previously quoted arguments on Windows
    :param args: a command line string consisting of a command with arguments, 
                 e.g. r'dir "C:\Program Files"'  
    :param platform: a value like os.name would return, e.g. 'nt'
    :return: a list of arguments like shlex.split(args) would have returned
    """
    return [a[1:-1].replace('""', '"') if a[0] == a[-1] == '"' else a
            for a in (split(args, posix=False) if platform == 'nt' else split(args))]

使用它而不是shlex.split()可以得到我需要的东西,同时又不会破坏UNC路径。然而,我敢肯定在一些边缘情况下,双引号的正确转义没有得到正确的处理,但它在我的所有测试用例中都有效,而且到目前为止似乎对所有实际用例都有效。使用风险自负。

@balmy做了一个很好的观察,大多数人可能只需要使用:

代码语言:javascript
复制
command = r'program.exe "C:\some folder" -o"\\server\share\some folder" "a \"quote\""'
proc = await create_subprocess_shell(command)

而不是

代码语言:javascript
复制
command = r'program.exe "C:\some folder" -o"\\server\share\some folder" "a \"quote\""'
proc = await create_subprocess_exec(*command)

但是,请注意,这意味着:

的话说,使用create_subprocess_exec时总是会出现问题

应用程序有责任确保适当地引用所有空格和特殊字符,以避免外壳注入漏洞。shlex.quote()函数可用于正确转义将要用于构造外壳命令的字符串中的空格和特殊外壳字符。

这仍然是一个问题,因为quote()也不能在Windows上正常工作(根据设计)。

如果有人想指出为什么上面的想法真的很糟糕,或者如果有人有更好的想法,我就先把这个问题留下来。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69909487

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档