在Windows中处理unicode子进程环境的正确方法是什么?

Ayr*_*yrx 3 python windows python-2.7

以这个示例片段为例。

import subprocess
import os

env = os.environ.copy()
env["FOO"] = u"foo"
subprocess.check_call(["ls", "-l"], env=env)
Run Code Online (Sandbox Code Playgroud)

在Windows上,这将失败。

C:\Python27\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    subprocess.check_call(["ls", "-l"], env=env)
  File "C:\Python27\lib\subprocess.py", line 535, in check_call
    retcode = call(*popenargs, **kwargs)
  File "C:\Python27\lib\subprocess.py", line 522, in call
    return Popen(*popenargs, **kwargs).wait()
  File "C:\Python27\lib\subprocess.py", line 710, in __init__
    errread, errwrite)
  File "C:\Python27\lib\subprocess.py", line 958, in _execute_child
    startupinfo)
TypeError: environment can only contain strings
Run Code Online (Sandbox Code Playgroud)

sys.path证明,使用unicode完全可以。什么可以正确处理此代码(及类似代码)?显而易见的解决方案是调用.encode()unicode路径,但是我不确定这是否会导致意外行为。

dhk*_*hke 5

在Windows上,将环境dict传递subprocess.check_call()归结为将环境传递给CreateProcess()。那实际上可以采用unicode字符串(以其CreateProcessW()形式)。

但是,从python 2.7的_subprocess.c

/* TODO: handle unicode command lines? */
/* TODO: handle unicode environment? */
Run Code Online (Sandbox Code Playgroud)

因此,您不是第一个想到这个问题的人。

对于您的问题,也没有通用的解决方案,因为环境是由被调用的进程解释的,并且其中的某些环境也会由系统或系统库自动进行解释。因此,正确的编码取决于目标进程的期望。

不幸的是,尽管Windows上的Python 2确实处理Unicode,但实际上将零终止的窄字符串(即PyString_AS_STRING()return char *)传递给系统函数。

现在,Windows本身如何处理两种不同版本的环境变量,因为显然可以传递宽或窄环境字符串。

目标进程只能访问GetEnvironmentStrings()它,返回的是宽字符还是窄字符,这取决于应用程序是否使用Unicode支持进行编译。

那么,当您CreateProcess()从狭窄(ANSI)进程启动Unicode进程时会发生什么呢?所有参数都发生同样的事情,它们在调用者的代码页中被解码,并转换为Windows版本的UCS-2宽字符。

因此,正确的方法可能是使用系统代码页,因为只有这样,字符串才能真正在unicode目标进程中正确显示。当然-这可以防止您使用不在该代码页中的字符...

因此,是的,Python 2上的Unicode环境或多或少受到破坏。