2013-05-08 77 views
5

我有以下三個Python腳本:bash和蟒蛇管之間的區別

parent1.py

import subprocess, os, sys 

relpath = os.path.dirname(sys.argv[0]) 
path = os.path.abspath(relpath) 
child = subprocess.Popen([os.path.join(path, 'child.lisp')], stdout = subprocess.PIPE) 
sys.stdin = child.stdout 
inp = sys.stdin.read() 
print(inp.decode()) 

parent2.py:

import sys 
inp = sys.stdin 
print(inp) 

child.py:

print("This text was created in child.py") 

如果我打電話給parent1.py:

python3 parent1.py 

它給了我像預期的輸出如下:

This text was created with child.py 

如果我叫與parent2.py:

python3 child.py | python3 parent2.py 

我得到的結果相同。但在第一個例子中,我得到child.py的輸出作爲字節,在第二個我直接獲取它作爲一個字符串。爲什麼是這樣?它只是python和bash管道之間的區別,還是有我可以做的其他方法來避免這種情況?

+0

[試試這個(http://stackoverflow.com/questions/3999114/linux-pipe-in​​to-python-ncurses-script- stdin-and-termios?answertab = votes#tab-top) – scott 2013-05-08 17:50:30

回答

3

當python打開stdinstdout時,它檢測到要使用的編碼並使用text I/O爲您提供unicode字符串。

但是subprocess沒有(也不能)檢測到你啓動的子進程的編碼,所以它會返回字節。您可以使用io.TextIOWrapper() instance來包裝child.stdout管提供Unicode數據:

sys.stdin = io.TextIOWrapper(child.stdout, encoding='utf8') 
+2

是的。我想補充一點,操作系統中只有一種管道,而bash和Python使用的管道也是一樣的。流的解釋可以不同,Python區分了兩種情況;在其中一個將輸入解釋爲字節,另一個解釋爲字符串/ unicode。 – Alfe 2013-05-08 17:51:01

+0

謝謝你的工作。如果我現在想要做一些像'cat/bin/bash | parent2.py'會引發UnicodeDecodeError,因爲sys.stdin.read()不返回字節。有沒有辦法解決這個問題? – Kritzefitz 2013-05-08 18:02:53

+1

@Alfe:在這兩種情況下,它仍然會將輸入視爲字節輸入,它只是在後一種情況下自動將流包裝在「TextIOWrapper」中。無論是哪種情況,您都可以獲取底層字節流,或手動附加您自己的包裝器。但仍然是一個有用的觀點。 – abarnert 2013-05-08 18:15:21