2012-11-15 34 views
2

我有Django在标准WSGI/Apache httpd组合上运行。subprocess.Popen命令(antiword)在shell和web应用程序中产生不同的输出

我注意到,当我在shell或浏览器中运行代码时,文件输出不同。我已经隔离了一切,并且仍然遇到同样的问题。

下面的代码:

def test_antiword(filename): 
    import subprocess 
    with open(filename, 'w') as writefile: 
     subprocess.Popen(["antiword", '/tmp/test.doc'], stdout=writefile) 
    p = subprocess.Popen(["antiword", '/tmp/test.doc'], stdout=subprocess.PIPE) 
    out, _ = p.communicate() 
    ords = [] 
    for kk in out: 
     ords.append(ord(kk)) 
    return out, ords 

def test_antiword_view(request): 
    import HttpResponse 
    return HttpResponse(repr(test_antiword('/tmp/web.txt'))) 

当打开浏览器的URL,这是输出:

('\n"I said good day sir. Good day!" shouted Sh\xe9rlo\xe7k H\xf8lme\xa3.\n\n "Why not Zoidberg?" queried Zoidberg.\n', [10, 34, 73, 32, 115, 97, 105, 100, 32, 103, 111, 111, 100, 32, 100, 97, 121, 32, 115, 105, 114, 46, 32, 71, 111, 111, 100, 32, 100, 97, 121, 33, 34, 32, 115, 104, 111, 117, 116, 101, 100, 32, 83, 104, 233, 114, 108, 111, 231, 107, 32, 72, 248, 108, 109, 101, 163, 46, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 87, 104, 121, 32, 110, 111, 116, 32, 90, 111, 105, 100, 98, 101, 114, 103, 63, 34, 32, 113, 117, 101, 114, 105, 101, 100, 32, 90, 111, 105, 100, 98, 101, 114, 103, 46, 10])

这是对应的输出,当我打电话test_antiword('/tmp/shell.txt') INE兴田壳:

('\n\xe2\x80\x9cI said good day sir. Good day!\xe2\x80\x9d shouted Sh\xc3\xa9rlo\xc3\xa7k H\xc3\xb8lme\xc2\xa3.\n\n \xe2\x80\x9cWhy not Zoidberg?\xe2\x80\x9d queried Zoidberg.\n', [10, 226, 128, 156, 73, 32, 115, 97, 105, 100, 32, 103, 111, 111, 100, 32, 100, 97, 121, 32, 115, 105, 114, 46, 32, 71, 111, 111, 100, 32, 100, 97, 121, 33, 226, 128, 157, 32, 115, 104, 111, 117, 116, 101, 100, 32, 83, 104, 195, 169, 114, 108, 111, 195, 167, 107, 32, 72, 195, 184, 108, 109, 101, 194, 163, 46, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 226, 128, 156, 87, 104, 121, 32, 110, 111, 116, 32, 90, 111, 105, 100, 98, 101, 114, 103, 63, 226, 128, 157, 32, 113, 117, 101, 114, 105, 101, 100, 32, 90, 111, 105, 100, 98, 101, 114, 103, 46, 10])

正如你所看到的,输出是非常不同的。一方面,shell输出保持原始文件中的空白;它在网络版中丢失了。

正如您在代码中看到的那样,我还将文档输出到文件。所产生的输出是下面:

web.txt

"I said good day sir. Good day!" shouted Sh?rlo?k H?lme?. 

      "Why not Zoidberg?" queried Zoidberg. 

shell.txt

“I said good day sir. Good day!” shouted Shérloçk Hølme£. 

      “Why not Zoidberg?” queried Zoidberg. 

在网页版,字符是不可识别的,并且编码由file识别作为ISO-8859。在shell版本中,字符正确显示,编码由file标识为UTF-8。

我不知道为什么会发生这种情况。我已经检查过,两个进程都使用相同版本的antiword。另外,我已经验证它们都使用相同的Python模块文件subprocess。在这两种情况下使用的Python版本也完全匹配。

任何人都可以解释可能发生了什么?

+0

此外,在这个例子的目的,我用了很短的文件,但在更长的文件换行符是不同的。由shell生成的文件的宽度为150个字符,而由Web生成的文件的宽度为80个字符。 –

+0

此外,它似乎是唯一的反词。我也用'cat'试过了,web和shell的表现都一样。 –

回答

3

这种差异可能是由于环境变量造成的。按照man page

Antiword uses the environment variables LC_ALL , LC_CTYPE and LANG (in that order) to get the current locale and uses this information to select the default mapping file.

我怀疑发生的事情是,当你从你的shell中运行它,你的shell是在UTF-8语言环境,但是当你从Django中运行它,它在不同的语言环境,并且它不能正确地转换Unicode字符。尝试运行子这样当切换成UTF-8码:

new_env = dict(os.environ) # Copy current environment 
new_env['LANG'] = 'en_US.UTF-8' 
p = subprocess.Popen(..., env=new_env) 
+0

就是这样!请注意,出于某种原因,当使用'new_env = os.environ [:]'时,出现'TypeError:unhashable type'错误。相反,我使用了'new_env = dict(** os.environ)'这个技巧。 –

+0

@Jordan:糟糕,我忘了你不能使用切片运算符来复制'dict'。这种方式的作用,[copy.copy'](http://docs.python.org/2/library/copy.html#copy.copy)。 –

相关问题