Reputation: 157
So I've entered two lines of code into a Python shell to read from STDOUT
and write to STDIN
:
>>> writetoinput=open("/dev/stdin","w")
>>> readfromoutput=open("/dev/stdout")
and unexpected things happen when you do file operations on them.
First, I tried writing to STDIN
:
>>> writetoinput.write("banana?")
But then, when I called input()
, the terminal did not return "banana?"
and instead prompted for user input.
Then, I ran print("hi")
and tried reading from STDOUT
:
>>> readfromoutput.read()
Instead of printing "hi"
, the terminal hanged, and I had to do a Keyboard Interrupt.
Why does Python behave this way, especially with the fact that reading STDOUT
hangs the terminal?
Upvotes: -2
Views: 239
Reputation: 5478
This is not python behaviour, this is system behaviour. Those are not literal "files", they are special files that represent a more abstract concept (just like devices are unix "files").
Instead of hitting ctrl+c you should've hit ctrl+d to send end-of-file and then you'd see your output! Why?
Because unless redirected, stdin and stdout are just bound to the console (tty). All three are the same thing by default because both stdout and stderr are printed directly to console and stdin is always from the console:
➜ ll /dev/std*
lrwxrwxrwx 1 root root 15 cze 27 08:41 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 cze 27 08:41 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 cze 27 08:41 /dev/stdout -> /proc/self/fd/1
➜ ll /proc/self/fd
total 0
dr-x------ 2 ev ev 0 lip 11 16:14 ./
dr-xr-xr-x 9 ev ev 0 lip 11 16:14 ../
lrwx------ 1 ev ev 64 lip 11 16:14 0 -> /dev/pts/1
lrwx------ 1 ev ev 64 lip 11 16:14 1 -> /dev/pts/1
lrwx------ 1 ev ev 64 lip 11 16:14 2 -> /dev/pts/1
As you can see, the /dev/std* points always to current process' file descriptors 0, 1, 2.
In case of console, those 3 are just that console's tty.
So when you "open" stdout for reading, you're doing the same thing as stdin does - wait for all stuff until EOF is received.
>>> b = open("/dev/stdout")
>>> b.read()
this looks bad, right?
but see this
let's hit ctrl+d
"this looks bad, right?\nbut see this\nlet's hit ctrl+d\n"
>>>
>>>
>>> # same as
>>> sys.stdin.read()
see?
like this
'see?\nlike this\n'
How writing is done isn't clear to you because python usually skips the concept of flushing your buffer. When you close a file, the buffer gets flushed, so you don't need to do it manually. And when using print the flushing is not guaranteed (defaults to flush=False), but usually happens anyways.
>>> a = open("/dev/stdin",'w')
>>> a.write("this is nice")
12
>>> a.flush()
this is nice>>>
Now, with flushing, we can actually see what we did! sys.stdout flushes for me automatically, so when I do sys.stdout.write the content+saved bytes are on the same line, but it's the same.
Upvotes: 2
Reputation: 33352
especially with the fact that reading STDOUT hangs the terminal
It didn't "hang the terminal". It was trying to read input from the terminal, just like you told it to.
.read()
will read ALL of the available input. It doesn't stop at just one line, unlike the input()
function.
It was waiting until the input was completely exhausted. When reading from a unix interactive terminal, the way to signal "end of input" is to type Ctrl-D at the beginning of a line.
Upvotes: 1