TypeError:execv()arg 2必须只包含字符串(subprocess和unicode)

时间:2017-12-06 14:00:01

标签: python subprocess python-unicode

我有这个Python2.7脚本,如果LANG!=' C':

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function

import os
import subprocess

import sys

print('LANG: {}'.format(os.environ['LANG']))
print('sys.getdefaultencoding(): {}'.format(sys.getdefaultencoding()))
print('sys.getfilesystemencoding(): {}'.format(sys.getfilesystemencoding()))
subprocess.check_call(['echo', 'Umlauts üöä'])

调用linux shell:

user@host:~$ python src/execv-arg-2-must-contain-only-strings.py 
LANG: de_DE.UTF-8
sys.getdefaultencoding(): ascii
sys.getfilesystemencoding(): UTF-8
Umlauts üöä

但这失败了:

user@host:~$ LANG=C python src/execv-arg-2-must-contain-only-strings.py 
LANG: C
sys.getdefaultencoding(): ascii
sys.getfilesystemencoding(): ANSI_X3.4-1968
Traceback (most recent call last):
  File "src/execv-arg-2-must-contain-only-strings.py", line 12, in <module>
    subprocess.check_call(['echo', 'Umlauts üöä'])
  File "/usr/lib/python2.7/subprocess.py", line 536, in check_call
    retcode = call(*popenargs, **kwargs)
  File "/usr/lib/python2.7/subprocess.py", line 523, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
TypeError: execv() arg 2 must contain only strings

如何使此脚本在使用LANG = C的Python2.7上运行?

2 个答案:

答案 0 :(得分:1)

使用 LANG = C.UTF-8 代替 LANG = C

user@host> LANG=C.UTF-8 python t.py
LANG: C.UTF-8
sys.getdefaultencoding(): ascii
sys.getfilesystemencoding(): UTF-8
Umlauts üöä

: - )

答案 1 :(得分:0)

我没有将其作为答案发布,因为我没有办法检查其正确性。但原则上,如果要将数据作为子进程/ shell参数发送,则必须匹配所述数据的编码(然后在接收子进程中对其进行解码),否则Python不知道如何打包参数

因此,如果您正在使用utf-8文字(如编码标题中所定义)并且您想将其发送到子流程,则应首先将其解码为 native unicode对象,然后将其编码为系统对当前环境的编码,例如:

literal_argument = "Umlauts üöä"  # string literal
unicode_argument = literal_argument.decode("utf-8")  # unicode
encoded_argument = unicode_argument.encode(sys.getdefaultencoding())  # sys encoded

subprocess.check_call(['echo', encoded_argument])

虽然更安全,但它仍然可以在非标准炮弹上打破。在可能的情况下,使用子进程的STDIN管道传递不适合当前shell的数据作为参数 - 只要两个进程都同意要使用的编码,就不必担心不同的代码页。