在Python 3中,可以使用以下格式的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
重击3.2
答案 0 :(得分:3)
没有文件描述符(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
更有意思的是,没有标准的方法可以将打开模式从读取更改为写入,而您的程序将写入标准输入。答案是(至少在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。
答案 1 :(得分:2)
>
语法在调用python之前由外壳处理。它将stdout
连接到给定的文件,就像2>
对stderr
所做的操作和<
对stdin
所做的操作一样。
0
,1
和2
分别是分别为stdin
,stdout
和stderr
保留的文件描述符(这就是2>
是重定向stderr
的语法的原因。
因此0
是有效的文件描述符,但是它是您的stdin
,您将再次打开该文件进行写入。最终似乎写到了终端,因为stdin
就是要写的地方。
答案 2 :(得分:1)
文件句柄0
是标准输入。如果没有重定向,stdout,stderr和stdin都指向终端(因此它们的行为相同)。但是,使用重定向时,它们的行为将有所不同,因为它们将不再相同。
I.E。如果您执行python3 testio.py 2> testio.txt
,则stdout会进入该文件,但stdin仍然是终端。
这只是不检查的双重结果,即您只能读stdin,只写stdout和stderr。