如何将字符串拆分为命令行参数,例如 python 中的 shell?



我在字符串中有命令行参数,我需要拆分它以馈送到argparse.ArgumentParser.parse_args

我看到文档大量使用string.split()。但是,在复杂的情况下,这不起作用,例如

--foo "spaces in brakets"  --bar escaped spaces

在python中是否有功能可以做到这一点?

(这里提出了一个类似的Java问题(。

这就是创建shlex.split的目的。

如果您正在解析 Windows 样式的命令行,则shlex.split无法正常工作 - 对结果调用subprocess函数的行为与将字符串直接传递给 shell 的行为不同。

在这种情况下,将字符串拆分为python的最可靠方法是...要将命令行参数传递给 python:

import sys
import subprocess
import shlex
import json  # json is an easy way to send arbitrary ascii-safe lists of strings out of python
def shell_split(cmd):
"""
Like `shlex.split`, but uses the Windows splitting syntax when run on Windows.
On windows, this is the inverse of subprocess.list2cmdline
"""
if os.name == 'posix':
return shlex.split(cmd)
else:
# TODO: write a version of this that doesn't invoke a subprocess
if not cmd:
return []
full_cmd = '{} {}'.format(
subprocess.list2cmdline([
sys.executable, '-c',
'import sys, json; print(json.dumps(sys.argv[1:]))'
]), cmd
)
ret = subprocess.check_output(full_cmd).decode()
return json.loads(ret)

这些差异的一个例子:

# windows does not treat all backslashes as escapes
>>> shell_split(r'C:Usersmesome_file.txt "file with spaces"', 'file with spaces')
['C:\Users\me\some_file.txt', 'file with spaces']
# posix does
>>> shlex.split(r'C:Usersmesome_file.txt "file with spaces"')
['C:Usersmesome_file.txt', 'file with spaces']
# non-posix does not mean Windows - this produces extra quotes
>>> shlex.split(r'C:Usersmesome_file.txt "file with spaces"', posix=False)
['C:\Users\me\some_file.txt', '"file with spaces"']  

您可以使用click包中的split_arg_string帮助程序函数:

import re
def split_arg_string(string):
"""Given an argument string this attempts to split it into small parts."""
rv = []
for match in re.finditer(r"('([^'\]*(?:\.[^'\]*)*)'"
r'|"([^"\]*(?:\.[^"\]*)*)"'
r'|S+)s*', string, re.S):
arg = match.group().strip()
if arg[:1] == arg[-1:] and arg[:1] in '"'':
arg = arg[1:-1].encode('ascii', 'backslashreplace') 
.decode('unicode-escape')
try:
arg = type(string)(arg)
except UnicodeError:
pass
rv.append(arg)
return rv

例如:

>>> print split_arg_string('"this is a test" 1 2 "1 \" 2"')
['this is a test', '1', '2', '1 " 2']

click包开始在命令参数解析中占主导地位,但我认为它不支持从字符串解析参数(仅来自argv(。上面的帮助程序函数仅用于bash完成。

编辑:我只能建议按照@ShadowRanger答案中的建议使用shlex.split()。我不删除这个答案的唯一原因是因为它提供的拆分速度比shlex中使用的成熟的纯 python 分词器快一点(上面的例子大约快 3.5 倍,5.9us 对 20.5us(。但是,这不应该成为更喜欢它而不是shlex的理由。

相关内容

最新更新