【问题标题】:shlex.split() returning whole command as a single stringshlex.split() 将整个命令作为单个字符串返回
【发布时间】:2019-05-07 14:59:23
【问题描述】:

shlex.split() 没有在输入字符串上给出正确的输出。

在 python 解释器中,将输入值存储在变量中会产生预期的输出。

但如果我通过脚本执行,shlex.split() 输出不正确,输入字符串没有在空格上拆分。

>>> import shlex

>>> var = "/usr/bin/ansible-playbook --timeout=60 --module-path /var/sandeep> /playbooks/ --extra-vars '{ \"text\": \"DUMMY\", \"addition\": [\"1\", \"2\", \"3\", ], \"deletion\": [], \"update\": \"update\", \"path\": \"/var/sandeep\", }' /tmp/sandeep//tmp/example.yaml"
>>>
>>>
>>> shlex.split(var)

['/usr/bin/ansible-playbook', '--timeout=60', '--module-path', '/var/sandeep/playbooks/', '--extra-vars', '{ "text": "DUMMY", "addition": ["1", "2", "3", ], "deletion": [], "update": "update", "path": "/var/sandeep", }', '/tmp/sandeep//tmp/example.yaml']
def create_extra(text, extra_dict):
    extra = "'{{ \\\"text\\\": \\\"{}\\\", ".format(text)
    for key, value in extra_dict.items():
        if isinstance(value, list):
            extra += '\\\"{}\\\": ['.format(key)
            for item in value:
                extra += '\\\"{}\\\", '.format(item)
            extra += '], '
        elif isinstance(value, dict):
            extra += '\\\"{}\\\": {{'.format(key)
            for item_key, item_value in value.items():
                extra += '\\\"{}\\\": \\\"{}\\\", '.format(item_key, item_value)
            extra += "}, "
        else:
            extra += '\\\"{}\\\": \\\"{}\\\", '.format(key, value)
    extra += "}'"
    #print("extra: %s" % extra)
    return extra

extra_dict = {'addition': ["1", "2", "3"],
                   'deletion': [],
                   'update': 'update',
                   'path' : '/var/sandeep'
                  }


temp = create_extra("DUMMY", extra_dict)

"""create_extra function formats and return string"""

cmd = ('"/usr/bin/ansible-playbook ' +
        '--timeout=60 '  +
        '--module-path /var/sandeep/playbooks/ ' +
        '--extra-vars {} {}/{}"'.format(temp, "/tmp/sandeep", "/tmp/example.yaml"))

print(cmd)
print(shlex.split(cmd))
output of print(cmd)
"/usr/bin/ansible-playbook --timeout=60 --module-path /var/sandeep/playbooks/ --extra-vars '{ \"text\": \"DUMMY\", \"addition\": [\"1\", \"2\", \"3\", ], \"deletion\": [], \"update\": \"update\", \"path\": \"/var/sandeep\", }' /tmp/sandeep//tmp/example.yaml"


Expected results:
['/usr/bin/ansible-playbook', '--timeout=60', '--module-path', '/var/sandeep/playbooks/', '--extra-vars', '{ "text": "DUMMY", "addition": ["1", "2", "3", ], "deletion": [], "update": "update", "path": "/var/sandeep", }', '/tmp/sandeep//tmp/example.yaml']


Actual Results:
['/usr/bin/ansible-playbook --timeout=60 --module-path /var/sandeep/playbooks/ --extra-vars \'{ "text": "DUMMY", "addition": ["1", "2", "3", ], "deletion": [], "update": "update", "path": "/var/sandeep", }\' /tmp/sandeep//tmp/example.yaml']

我错过了什么吗?

【问题讨论】:

  • 当您可以构建显式数组时,为什么还要使用shlex.split()?假设您正在构建一个列表以传递给subprocess.Popen() 或类似的东西,那么执行['--extra-vars', temp, os.path.join('/tmp/sandeep', 'example.yaml')] 之类的事情要安全得多;这样,如果您的任何名称中有空格或文字引号字符,您的代码就不会中断。
  • Serge,如果您使用 OP 的未修改代码,它是完全可重现的。见ideone.com/TN6mfy
  • @CharlesDuffy:我从第一部分开始,它没有产生什么问题。我现在意识到这不是问题所在。将删除 cmets...
  • @sandeepnagendra, ...记住字面引号和句法引号之间的区别很重要。您在交互式解释器中的原始代码只有语法引号,没有文字引号;您在脚本中不起作用的代码具有单引号作为句法,然后在其中包含文字引号
  • create_extra 是……是的。坦率地说,只要您不再需要对内容进行 shell 引用,就可以而且应该将其替换为 json.dumps(extra_dict)

标签: python string python-3.6 shlex


【解决方案1】:

shlex 输出完全正确,因为字符串中包含文字 " 字符。

cmd = ('"/usr/bin/ansible-playbook ' +
#       ^- that right there
        '--timeout=60 '  +
        '--module-path /var/sandeep/playbooks/ ' +
        '--extra-vars {} {}/{}"'.format(temp, "/tmp/sandeep", "/tmp/example.yaml"))
#        and this right here -^

正如您的print(cmd) 这样显示:

"/usr/bin/ansible-playbook --timeout=60 --module-path /var/sandeep/playbooks/ --extra-vars whatever /tmp/sandeep//tmp/example.yaml"

...您的字符串以" 开头并以" 结尾,这使得它在被shell 解析时成为单个文字字符串。


只要去掉那些字符,问题就不会再发生了:

cmd = ('/usr/bin/ansible-playbook ' +
       '--timeout=60 '  +
       '--module-path /var/sandeep/playbooks/ ' +
       '--extra-vars {} {}/{}'.format(temp, "/tmp/sandeep", "/tmp/example.yaml"))

print(cmd)
print(shlex.split(cmd))

但是,您还有其他严重的错误,因为字符串连接本质上不适合构建命令行。与其尝试采用这种方法,不如直接构建一个数组:

cmd = ['/usr/bin/ansible-playbook',
       '--timeout=60',
       '--module-path', '/var/sandeep/playbooks/',
       '--extra-vars', temp, os.path.join('/tmp/sandeep', '/tmp/example.yml')]

...然后temp 的值或其他带有空格或文字引号的变量将不再破坏您的代码或允许注入任意参数。

【讨论】:

    猜你喜欢
    • 2013-12-29
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    相关资源
    最近更新 更多