[英]Integer File Descriptor "0" in open()
在 Python 3 中,可以使用以下格式的“整數文件描述符”打開文件對象:
stdout = open(1, "w")
stdout.write("Hello World") # Prints Hello World
stdout.close()
不過,有趣的是,我發現0
也是一個有效的流。
如果我把它放在文件testio.py
:
stdout = open(0, "w")
stdout.write("Foo Bar\n")
stdout.close()
然后運行該代碼,輸出為:
bash-3.2$ python3 testio.py
Foo Bar
這似乎就像stdout
。 然而...
bash-3.2$ python3 testio.py > testio.txt
Foo Bar
bash-3.2$ cat testio.txt
所以看起來這實際上不是stdout
,而是別的東西。 它似乎也不是stderr
:
bash-3.2$ python3 testio.py 2> testio.txt
Foo Bar
bash-3.2$ cat testio.txt
但是,我確實發現可以使用0>
重定向輸出:
bash-3.2$ python3 testio.py 0> testio.txt
bash-3.2$ cat testio.txt
Foo Bar
所以我的問題是, open(0, "w")
到底到期了什么? 正在重定向的“0>”流是什么?
蟒蛇 3.6.5
重擊 3.2
沒有文件描述符 (FD) 編號是特殊的。 FD 0 上的 stdin、FD 1 上的 stdout 和 FD 2 上的 stderr 只是一個約定。
當您登錄時,關聯的終端設備將“連接”到這些 FD。 當您運行命令時,它會繼承描述符,除非您指示 shell 進行重定向。 但是一旦程序啟動,您可以根據需要close
、 dup
或open
FD。
回到你的問題:
stdout = open(0, "w")
stdout.write("Hello World") # Prints Hello World
stdout.close()
盡管有這個名字,但在這種情況下open
不會打開任何東西。 它從一個已經打開的低級 FD 創建一個 Python 文件對象(帶有緩沖區和所有高級別的東西),它實際上只是一個數字(內核中打開文件表的索引)。 有一個單獨的函數: os.fdopen
更有趣的是,沒有標准方法可以將打開模式從讀取更改為寫入,並且您的程序寫入 std 輸入。 答案是(至少在 Linux 上)這根本沒有發生。 正如您在lsof
中看到的那樣,所有 3 個標准 FD 通常都以讀/寫模式打開(由尾隨u
標記),例如:
cmd 32154 user 0u CHR 136,7 0t0 10 /dev/pts/7 cmd 32154 user 1u CHR 136,7 0t0 10 /dev/pts/7 cmd 32154 user 2u CHR 136,7 0t0 10 /dev/pts/7
所以你的程序只是寫入連接到終端的 FD 0。
>
語法在調用 python 之前由 shell 處理。 它將stdout
連接到給定的文件,就像2>
對stderr
和<
對stdin
。
所有這一切, 0
、 1
和2
是分別為stdin
、 stdout
和stderr
保留的文件描述符(這就是為什么2>
是重定向stderr
的語法)。
所以0
是一個有效的文件描述符,但它是你的stdin
,你再次打開它進行寫入。 這似乎最終會寫入終端,因為那是stdin
將要寫入的地方。
文件句柄0
是標准輸入。 如果沒有重定向,stdout、stderr 和 stdin 都指向終端(因此它們的行為都相同)。 然而,當使用重定向時,它們的行為會有所不同,因為它們將不再相同。
IE 如果您執行python3 testio.py 2> testio.txt
,則 stdout 轉到文件,但 stdin 仍然是終端。
這只是沒有檢查您是否只讀取 stdin、只寫入 stdout 和 stderr 的副產品。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.