【问题标题】:Python module to shellquote/unshellquote? [duplicate]Python 模块到 shellquote/unshellquote? [复制]
【发布时间】:2010-11-01 07:59:27
【问题描述】:

Python 标准库中是否有任何东西可以正确解析/解析字符串以在 shell 命令中使用?我正在寻找 perl 的 String::ShellQuote::shell_quote 的 python 模拟:

$ print String::ShellQuote::shell_quote("hello", "stack", "overflow's", "quite", "cool")
hello stack 'overflow'\''s' quite cool

而且,更重要的是,一些可以反向工作的东西(获取一个字符串并将其分解为一个列表)。

【问题讨论】:

    标签: python shell quoting


    【解决方案1】:

    看起来像

    try:  # py3
        from shlex import quote
    except ImportError:  # py2
        from pipes import quote
    
    quote("hello stack overflow's quite cool")
    >>> '"hello stack overflow\'s quite cool"'
    

    让我走得够远。

    【讨论】:

    【解决方案2】:

    pipes.quote 现在在 python 3 中是 shlex.quote。 使用那段代码很容易。

    https://github.com/python/cpython/blob/master/Lib/shlex.py#L281

    该版本正确处理零长度参数。

    【讨论】:

      【解决方案3】:

      我很确定 pipe.quote 已损坏,不应使用,因为它不能正确处理零长度参数:

      >>> from pipes import quote
      >>> args = ['arg1', '', 'arg3']
      >>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
      mycommand arg1  arg3
      

      我相信结果应该是这样的

      mycommand arg1 '' arg3
      

      【讨论】:

      • 很公平。但是我们需要一个更好的解决方案:-)
      • print 'mycommand %s' % (' '.join(quote(arg) or "''" for arg in args)) ?
      • 在约翰的倡议下,this was fixed in Python 2.6.
      • ...但是使用join 破坏了使用quote 的大部分目的!
      • 为什么这么说?
      【解决方案4】:

      要取消引用,请尝试shlex.split()

      【讨论】:

        【解决方案5】:

        对于 shell 引用,这是可行的:我已经在 Posix 上对其进行了严格测试。 [我假设 Python 提供的 list2cmdline 函数在 Windows 上像宣传的那样工作]

        # shell.py
        import os
        if os.name == 'nt':
            from subprocess import list2cmdline
        
            def quote(arg):
                return list2cmdline([arg])[0]
        else:
            import re
            _quote_pos = re.compile('(?=[^-0-9a-zA-Z_./\n])')
        
            def quote(arg):
                r"""
                >>> quote('\t')
                '\\\t'
                >>> quote('foo bar')
                'foo\\ bar'
                """
                # This is the logic emacs uses
                if arg:
                    return _quote_pos.sub('\\\\', arg).replace('\n',"'\n'")
                else:
                    return "''"
        
            def list2cmdline(args):
                return ' '.join([ quote(a) for a in args ])
        

        测试是here,如果有人关心的话。

        【讨论】:

        • 反例:要引用的字符串包含"\xC3\xA9",这是UTF-8 中的一个é,因此在文件名中并不少见。上面的代码在两个字符前面都加上了反斜杠,这是不正确的。 pipes.quote 会将其放在单引号中。
        【解决方案6】:

        标准库模块 subprocess 具有执行此操作的 list2cmdline 函数,尽管根据 Microsoft rules,所以我不确定它在类 Unix 环境中对于更复杂的命令行的工作可靠性。

        【讨论】:

          【解决方案7】:

          quote 函数在相当长一段时间内都可用(Python 2.7?)——主要缺点是它在 3.2 和 3.3 之间从 pipe 模块移动到 shlex

          在导入该函数时,您必须准备好处理这两种情况:

          try:
              from shlex import quote
          except ImportError:
              from pipes import quote
          

          【讨论】:

            【解决方案8】:

            你不应该用壳引用。执行命令的正确方法是不执行 shell 引用,而是使用 subprocess.callsubprocess.Popen,并传递未引用参数的列表。这不受外壳膨胀的影响。

            subprocess.Popen(['echo', '"', '$foo'], shell=False)
            

            如果你想取消引用 shell 引用的数据,你可以像这样使用shlex.shlex

            list(shlex.shlex("hello stack 'overflow'\''s' quite cool"))
            

            【讨论】:

            • 如果我需要传递一个命令(需要转义)以便 ssh 在到达另一端时执行?
            • 这不是一个有用的答案(它回答了我的问题的一半,所以它有一半的帮助......)。在很多情况下,您都需要壳引用——Mike Boers 只举了一个很好的例子(事实上,这就是我遇到的例子)
            • 实际上更糟糕的是,给定的示例会中断: (Pdb) list(shlex.shlex("hello stack 'overflow'\''s' pretty cool")) *** 参数错误:' (shlex.shlex("hello stack\'overflow\'\\\'\'s\'相当酷"))'
            • 来自子进程文档:如果 shell 为 True,建议将 args 作为字符串而不是序列传递。 ...这包括,例如,引用或反斜杠转义文件名,其中包含空格。 - 这只是您需要引用的另一个示例。
            • 我的 shell 引用用例是:我的 Python 程序按照建议使用 subprocess.Popen() ,但是当它这样做时,我希望它可以在控制台上打印一些可以直接剪切的东西-并粘贴到 shell 中,以便在命令失败时进行手动调试。
            猜你喜欢
            • 2022-11-03
            • 2012-08-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-01
            • 1970-01-01
            相关资源
            最近更新 更多