2017-06-11 27 views
3

說,你已經通過os.urandom(24)生成的字節串,如何在Python中設置一個來自環境變量的字節串?

b'\x1b\xba\x94(\xae\xd0\xb2\xa6\xf2f\xf6\x1fI\xed\xbao$\xc6D\x08\xba\x81\x96v' 

,你想存儲在一個環境變量,

export FOO='\x1b\xba\x94(\xae\xd0\xb2\xa6\xf2f\xf6\x1fI\xed\xbao$\xc6D\x08\xba\x81\x96v' 

,並從一個Python程序中檢索值使用os.environ

foo = os.environ['FOO'] 

的問題是,在這裏,foo具有字符串文本值'\\x1b\\xba\\x94...而不是字節序列b'\x1b\xba\x94...

什麼是正確的export值使用,或使用os.environ作爲一個字節字符串對待FOO

+0

可能是因爲單引號。 –

+0

我很困惑;如果你在Python中打印(repr)'foo',它來自'os.urandom'之類並且看到'b'\ x1b \ xba ...'',那麼它是(在Python中)原始字節。如果您從envvar中讀取它並查看''\\ x1b \\ xba'',那麼它是一個仍然轉義的(Unicode)字符串。根據[這個問題](https://stackoverflow.com/questions/43214001/how-to-write-binary-data-in-bash),似乎bash不會將您的'export FOO'行解釋爲真實二進制文件,但是有一串'\ x'的字符串。 –

回答

2

你可以 'UNESCAPE' 你在Python個字節:

import os 
import sys 

if sys.version_info[0] < 3: # sadly, it's done differently in Python 2.x vs 3.x 
    foo = os.environ["FOO"].decode('string_escape') # since already in bytes... 
else: 
    foo = bytes(os.environ["FOO"], "utf-8").decode('unicode_escape') 
+0

你的Py3解決方案產生一個'str',而不是'bytes'對象,並且不必要地將字符串轉換爲'bytes'。替換第二行:'foo = os.environb [b'FOO']。decode('unicode-escape')。encode('latin-1')'使其從'os.environb'('以字節爲導向的環境視圖),解碼轉義,然後轉換回原始的'bytes'('latin-1'是一個1-1映射,將前256個Unicode序號映射爲它們的序數值作爲字節)。 – ShadowRanger

0

隨着zwer的回答我嘗試以下

從bash的第一(這是相同的二進制文字的ybakos給出)

export FOO='\x1b\xba\x94(\xae\xd0\xb2\xa6\xf2f\xf6\x1fI\xed\xbao$\xc6D\x08\xba\x81\x96v' 

然後我啓動了python shell(我有python 3.5.2)

>>> import os 
>>> # ybakos's original binary literal 
>>> foo = b'\x1b\xba\x94(\xae\xd0\xb2\xa6\xf2f\xf6\x1fI\xed\xbao$\xc6D\x08\xba\x81\x96v' 
>>> # ewer's python 3.x solution 
>>> FOO = bytes(os.environ["FOO"], "utf-8").decode('unicode_escape') 
>>> foo == FOO 
False 
>>> ^D 

foo == FOO的最後一行應該返回true,因此該解決方案似乎無法正常工作。

我注意到有一個os.envirnb字典,但我不知道將環境變量設置爲二進制文字,所以我嘗試了下面的替代方法,它使用base64編碼來獲取ASCII版本的二進制文字。

首先推出蟒蛇殼

>>> import os 
>>> import base64 
>>> foo = os.urandom(24) 
>>> foo 
b'{\xd9q\x90\x8b\xba\xecv\xb3\xcb\x1e<\xd7\xba\xf1\xb4\x99\xf056\x90U\x16\xae' 
>>> foo_base64 = base64.b64encode(foo) 
>>> foo_base64 
b'e9lxkIu67Hazyx4817rxtJnwNTaQVRau' 
>>> ^D 

然後在bash shell中

export FOO_BASE64='e9lxkIu67Hazyx4817rxtJnwNTaQVRau' 

然後回到在Python外殼

>>> import os 
>>> import base64 
>>> # the original binary value from the first python shell session 
>>> foo = b'{\xd9q\x90\x8b\xba\xecv\xb3\xcb\x1e<\xd7\xba\xf1\xb4\x99\xf056\x90U\x16\xae' 
>>> dec_foo = base64.b64decode(bytes(os.environ.get('FOO_BASE64'), "utf-8")) 
>>> # the values match! 
>>> foo == dec_foo 
True 
>>> ^D 

最後一行顯示的是2分的結果是相同!!

我們在做什麼,首先是從os.urandom()和Base64編碼得到一個二進制值。然後,我們使用Base64編碼值設置環境變量。注意:base64.b64encode()返回一個二進制值,但它只包含可打印的ASCII字符。

然後,在我們的程序中,我們從環境變量中讀取Base64編碼字符串值,將字符串轉換爲二進制形式,最後Base64將其解碼爲原始值。

1

還有一個選項,只需在Bash中將其設置爲二進制數據即可。這用途ANSI string quoting

export FOO=$'\x1b\xba\x94(\xae\xd0\xb2\xa6\xf2f\xf6\x1fI\xed\xbao$\xc6D\x08\xba\x81\x96v' 
+0

這是一個很好的方法,因爲它使讀取Python中的數據就像'os.environ ['FOO']'(Py2)或'os.environb [b'FOO']'(Py3)一樣簡單, Python中的數據作爲原始的'bytes'而不需要編碼或解碼。我完全忘了Bash的這個功能,所以感謝提醒! – ShadowRanger