open() 中的整数文件描述符“0”
Integer File Descriptor "0" in open()
在Python3中,可以open a file object using an "integer file descriptor"格式为:
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>”流是什么?
Python 3.6.5
Bash3.2
>
语法在调用 python 之前由 shell 处理。它将 stdout
连接到给定文件,就像 2>
连接 stderr
和 <
连接 stdin
.
综上所述,0
、1
和 2
是为 stdin
、stdout
和 stderr
保留的文件描述符分别(这就是为什么 2>
是重定向 stderr
的语法的原因)。
所以 0
是一个有效的文件描述符,但它是您的 stdin
,您再次打开它进行写入。这似乎最终写入了终端,因为那是stdin
要写入的地方。
文件句柄 0
是标准输入。在没有重定向的情况下,stdout、stderr 和 stdin 都指向终端(因此它们的行为相同)。但是,当使用重定向时,它们的行为会有所不同,因为它们将不再相同。
即如果你这样做 python3 testio.py 2> testio.txt
,然后 stdout 转到文件,但 stdin 仍然是终端。
这只是 没有检查 以查看您只读取 stdin,只写入 stdout 和 stderr 的副产品。
没有文件描述符 (FD) 号是特殊的。 FD 0 上的 stdin,FD 1 上的 stdout 和 FD 2 上的 stderr 只是一个约定。
当您登录时,关联的终端设备将"connected"到这些FD。当您 运行 命令时,除非您指示 shell 进行重定向,否则它会继承描述符。但是程序启动后,您可以close
、dup
或open
FDs 随心所欲。
回到你的问题:
stdout = open(0, "w")
stdout.write("Hello World") # Prints Hello World
stdout.close()
尽管有名称,open
在这种情况下不会打开任何东西。它从一个已经打开的低级别 FD 创建一个 Python 文件对象(带有缓冲区和所有高级内容),它实际上只是一个数字(内核中 table 打开文件的索引) .它有一个单独的函数:os.fdopen
更有趣的一点是,没有标准的方法可以将打开模式从读取更改为写入,并且您的程序将写入标准输入。答案是(至少在 Linux 上)这根本没有发生。正如你所看到的 lsof
,所有 3 个标准 FD 通常以 read/write 模式打开(由尾随 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。
在Python3中,可以open a file object using an "integer file descriptor"格式为:
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>”流是什么?
Python 3.6.5
Bash3.2
>
语法在调用 python 之前由 shell 处理。它将 stdout
连接到给定文件,就像 2>
连接 stderr
和 <
连接 stdin
.
综上所述,0
、1
和 2
是为 stdin
、stdout
和 stderr
保留的文件描述符分别(这就是为什么 2>
是重定向 stderr
的语法的原因)。
所以 0
是一个有效的文件描述符,但它是您的 stdin
,您再次打开它进行写入。这似乎最终写入了终端,因为那是stdin
要写入的地方。
文件句柄 0
是标准输入。在没有重定向的情况下,stdout、stderr 和 stdin 都指向终端(因此它们的行为相同)。但是,当使用重定向时,它们的行为会有所不同,因为它们将不再相同。
即如果你这样做 python3 testio.py 2> testio.txt
,然后 stdout 转到文件,但 stdin 仍然是终端。
这只是 没有检查 以查看您只读取 stdin,只写入 stdout 和 stderr 的副产品。
没有文件描述符 (FD) 号是特殊的。 FD 0 上的 stdin,FD 1 上的 stdout 和 FD 2 上的 stderr 只是一个约定。
当您登录时,关联的终端设备将"connected"到这些FD。当您 运行 命令时,除非您指示 shell 进行重定向,否则它会继承描述符。但是程序启动后,您可以close
、dup
或open
FDs 随心所欲。
回到你的问题:
stdout = open(0, "w")
stdout.write("Hello World") # Prints Hello World
stdout.close()
尽管有名称,open
在这种情况下不会打开任何东西。它从一个已经打开的低级别 FD 创建一个 Python 文件对象(带有缓冲区和所有高级内容),它实际上只是一个数字(内核中 table 打开文件的索引) .它有一个单独的函数:os.fdopen
更有趣的一点是,没有标准的方法可以将打开模式从读取更改为写入,并且您的程序将写入标准输入。答案是(至少在 Linux 上)这根本没有发生。正如你所看到的 lsof
,所有 3 个标准 FD 通常以 read/write 模式打开(由尾随 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。