In Python 3, it is possible to open a file object using an \"integer file descriptor\" with the format:
stdout = open(1, \"w\")
stdout.write(\"Hello World\")
File handle 0
is stdin. Without redirection stdout, stderr, and stdin are all pointing to the terminal (so will all act the same). However when redirection is used, they will behave differently, because they will no longer be the same.
I.E. If you do python3 testio.py 2> testio.txt
, then stdout goes to the file, but stdin is still the terminal.
This is just a bi-product of there being no checking to see that you only read stdin, and only write stdout, and stderr.
No file descriptor (FD) number is special. stdin on FD 0, stdout on FD 1 and stderr on FD 2 is just a convention.
When you log in, the associated terminal device will be "connected" to these FDs. When you run a command, it inherits the descriptors unless you instruct the shell to make redirections. But once the program starts, you can close
, dup
, or open
FDs as you like.
Back to your question:
stdout = open(0, "w")
stdout.write("Hello World") # Prints Hello World
stdout.close()
Despite the name, open
does not open anything in this case. It creates a Python file object (with buffers and all high level stuff) from an already open low-level FD which is really just a number (an index to a table of open files in the kernel). There was a separate function for it: os.fdopen
Little bit more interesting is that there is no standard way to change the open mode from read to write and your program writes to std input. The answer is (at least on Linux) that this is not happening at all. As you can see with lsof
, all 3 standard FDs are normally open in read/write mode (marked by trailing u
), e.g.:
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
So your program just writes to the FD 0 which is connected to the terminal.
>
syntax is handled by the shell before python is invoked. It connects stdout
to the given file, as 2>
does for stderr
and <
does for stdin
.
All that said, 0
, 1
, and 2
are file descriptors reserved for stdin
, stdout
, and stderr
respectively (which is why 2>
is the syntax to redirect stderr
).
So 0
is a valid file descriptor, but one that is your stdin
, which you're opening again for writing. This ends up writing to the terminal it seems, since that's where stdin
was going to write.