Python 2.7中subprocess.Popen传递非ASCII参数的编码问题
解决Python 2.7 subprocess.Popen传递非ASCII参数乱码问题
在Windows Server 2012 R2的Python 2.7环境下,你遇到的问题核心是subprocess.Popen处理字符串参数时的编码转换逻辑——直接传递UTF-8编码的字节串或Unicode字符串作为单命令字符串时,会被系统错误解析,而拆分参数为Unicode列表则能绕过这个问题。
最佳解决方案:使用Unicode参数列表而非单命令字符串
Python 2.7在Windows平台下,当你传入Unicode类型的参数列表给subprocess.Popen时,会调用系统的CreateProcessW(宽字符API),直接将Unicode参数传递给子进程,完全避免编码转换错误。修改你的测试脚本如下:
import subprocess # 拆分命令为参数列表,最后一个参数用Unicode字符串 cmd_args = [ 'C:\\Python27\\python.exe', 'C:\\path_to\\script.py', '-n', u'Testç on ã and ê' ] # 注意:这里不需要shell=True,直接传入参数列表 process = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output, err = process.communicate() result = process.wait() print result, '-', output
这样修改后,script.py就能正确接收到Testç on ã and ê,不会出现乱码。
为什么你之前的尝试失败了?
逐一分析你的操作:
- 保存为UTF-8编码:这只保证脚本本身的编码正确,但不影响参数传递时的编码转换。
- 使用Unicode单命令字符串:当你传递Unicode字符串作为
cmd参数(且shell=False),Python会尝试将其编码为系统的ANSI编码(比如cp1252),如果你的环境默认编码是ASCII(或字符不在ANSI编码范围内),就会触发UnicodeEncodeError。 u'...'.decode('utf-8'):Unicode字符串不能直接调用decode,Python会先隐式将其编码为ASCII,自然触发编码错误。- 编码为UTF-8字节串:此时Popen会把UTF-8字节当作ANSI编码解析,导致
ç(UTF-8为0xc3a7)被错误解码为ç,也就是你看到的乱码。 - 设置
PYTHONIOENCODING:这个环境变量仅控制stdin/stdout/stderr的编码,和参数传递无关,所以没有效果。
备选方案:如果必须使用单命令字符串
如果你因为命令复杂必须使用单字符串形式,可以将Unicode命令编码为当前CMD的OEM编码(比如cp850或cp1252,取决于你的系统配置),同时开启shell=True:
import subprocess import sys cmd_unicode = u'C:\\Python27\\python.exe C:\\path_to\\script.py -n "Testç on ã and ê"' # 获取CMD的OEM编码(通常和sys.stdout.encoding一致) oem_encoding = sys.stdout.encoding cmd_bytes = cmd_unicode.encode(oem_encoding) process = subprocess.Popen(cmd_bytes, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) output, err = process.communicate() result = process.wait() print result, '-', output
不过这种方案依赖系统编码,可靠性不如参数列表方案,优先推荐第一种方法。
内容的提问来源于stack exchange,提问作者Dinei
相关产品推荐
相关产品推荐

