Mas*_*imo 6 python windows command-line command-line-arguments shlex
当你必须拆分一个命令行,例如调用popen时,最好的做法似乎是
Popen
但是RTFM
shlex类可以很容易地为类似于Unix shell的简单语法编写词法分析器...
那么,win32上的正确方法是什么?那么引用解析和POSIX与非POSIX模式呢?最好的问候,马西莫
kxr*_*kxr 17
到目前为止,目前在Windows stdlib for Windows/multi-platform中没有有效的命令行拆分功能.(2016年3月)
所以简而言之,subprocess.Popen .call
等等最好做:
if sys.platform == 'win32':
args = cmd
else:
args = shlex.split(cmd)
subprocess.Popen(args, ...)
Run Code Online (Sandbox Code Playgroud)
在Windows上,对于shell
选项的任何值都不需要拆分,并且内部Popen只是subprocess.list2cmdline
用来再次重新加入拆分参数:-).
有了选项shell=True
,shlex.split
在Unix上也没有必要.
是否拆分,在Windows上启动.bat
或.cmd
脚本(与.exe .com不同),您需要明确包含文件扩展名 - 除非shell=True
.
shlex.split(cmd, posix=0)
在Windows路径中保留反斜杠,但它不理解引用和转义权限.它还不是很清楚posix = 0模式的shlex是否有用 - 但99%肯定会引诱Windows /跨平台程序员......
Windows API公开ctypes.windll.shell32.CommandLineToArgvW
:
解析Unicode命令行字符串并返回指向命令行参数的指针数组以及此类参数的计数,其方式类似于标准C运行时argv和argc 值.
def win_CommandLineToArgvW(cmd):
import ctypes
nargs = ctypes.c_int()
ctypes.windll.shell32.CommandLineToArgvW.restype = ctypes.POINTER(ctypes.c_wchar_p)
lpargs = ctypes.windll.shell32.CommandLineToArgvW(unicode(cmd), ctypes.byref(nargs))
args = [lpargs[i] for i in range(nargs.value)]
if ctypes.windll.kernel32.LocalFree(lpargs):
raise AssertionError
return args
Run Code Online (Sandbox Code Playgroud)
然而,该功能CommandLineToArgvW
是假的 - 或者只是与强制性标准C argv & argc
解析非常相似:
>>> win_CommandLineToArgvW('aaa"bbb""" ccc')
[u'aaa"bbb"""', u'ccc']
>>> win_CommandLineToArgvW('"" aaa"bbb""" ccc')
[u'', u'aaabbb" ccc']
>>>
Run Code Online (Sandbox Code Playgroud)
C:\scratch>python -c "import sys;print(sys.argv)" aaa"bbb""" ccc
['-c', 'aaabbb"', 'ccc']
C:\scratch>python -c "import sys;print(sys.argv)" "" aaa"bbb""" ccc
['-c', '', 'aaabbb"', 'ccc']
Run Code Online (Sandbox Code Playgroud)
观看http://bugs.python.org/issue1724822,了解Python lib中未来可能添加的内容.("fisheye3"服务器上提到的功能实际上并不正确.)
有效的Windows命令行拆分相当疯狂.试试\ \\ \" \\"" \\\"aaa """"
......
我目前用于跨平台命令行拆分的候选函数是我考虑用于Python lib提议的以下函数.它的多平台; 它比shlex快10倍,后者可以进行单字符步进和流式传输; 并且还尊重与管道相关的字符(与shlex不同).它列出了已经在Windows和Linux bash上进行的严格的实时shell测试,以及传统的posix测试模式test_shlex
.对有关剩余错误的反馈感兴趣.
def cmdline_split(s, platform='this'):
"""Multi-platform variant of shlex.split() for command-line splitting.
For use with subprocess, for argv injection etc. Using fast REGEX.
platform: 'this' = auto from current platform;
1 = POSIX;
0 = Windows/CMD
(other values reserved)
"""
if platform == 'this':
platform = (sys.platform != 'win32')
if platform == 1:
RE_CMD_LEX = r'''"((?:\\["\\]|[^"])*)"|'([^']*)'|(\\.)|(&&?|\|\|?|\d?\>|[<])|([^\s'"\\&|<>]+)|(\s+)|(.)'''
elif platform == 0:
RE_CMD_LEX = r'''"((?:""|\\["\\]|[^"])*)"?()|(\\\\(?=\\*")|\\")|(&&?|\|\|?|\d?>|[<])|([^\s"&|<>]+)|(\s+)|(.)'''
else:
raise AssertionError('unkown platform %r' % platform)
args = []
accu = None # collects pieces of one arg
for qs, qss, esc, pipe, word, white, fail in re.findall(RE_CMD_LEX, s):
if word:
pass # most frequent
elif esc:
word = esc[1]
elif white or pipe:
if accu is not None:
args.append(accu)
if pipe:
args.append(pipe)
accu = None
continue
elif fail:
raise ValueError("invalid or incomplete shell string")
elif qs:
word = qs.replace('\\"', '"').replace('\\\\', '\\')
if platform == 0:
word = word.replace('""', '"')
else:
word = qss # may be even empty; must be last
accu = (accu or '') + word
if accu is not None:
args.append(accu)
return args
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4390 次 |
最近记录: |