2

Consider the following example in Bash shell

$ echo 'test' | wc -c
5

Everything works as expected. Now let's change it to

$ echo 'test' >&0 | wc -c
test
0

Now, that 0 in the output makes prefect sense: echo has sent everything to stdin (which is traditionally writable) and nothing to stdout, so nothing gets piped over to wc. But how did the output appear in the console? Who printed that test line and when?

And finally, the third test (for platforms that support stdbuf)

$ stdbuf -i0 -o0 -e0 echo 'test' >&0 | wc -c
0
test

What happened here? Why did the order change?

1 Answer 1

3

The stdin of echo is connected to the terminal, so that's where the output goes when you do echo 'test' >&0. Usually, echo doesn't use its stdin, but it is there, the same way it is for e.g. cat. On the other hand, if you run echo foo | echo test >&0, you get an error for "Bad file descriptor", since the pipe connected to the stdin of the second echo is read-only for it.

In your other snippet, with stdbuf, I think what happens is that it's a race between wc noticing the pipe in its stdin is closed (you redirected the write side away, so there's no-one writing to the pipe), and echo writing to the terminal. It's not about the buffering (which really shouldn't matter since echo has to flush the buffer when finishing anyway), you can get the same with strace echo ... or env echo .... Anything on the left side that makes launching echo slower should have an effect. Also, remember that with just echo | wc, you're likely to run the shell's built-in implementation of echo, and with stdbuf, env or strace, an external echo runs. Builtins are faster.

In general, if you have two processes writing somewhere simultaneously, you can't make any assumptions about the order of the writes, unless they explicitly syncronize.

6
  • 1
    So, if I understood you correctly, in the first paragraph you are saying that everything written into stdin will also be displayed in the console (as opposed to being silently discarded). If so, is that formally specified somewhere? Commented Jan 31, 2021 at 21:10
  • @AnT, why would it be discarded? If stdin is connected to a terminal (probably the same one stdout and stderr are connected to, but it doesn't matter), and it's opened read-write (as you said yourself that it is), then why would any writes go anywhere else? It's the same terminal, right? I'm not even sure how they could get discarded -- how is the terminal driver supposed to know if the write comes from a process holding that fd at fd number 0 instead of fd number 1? The fd numbers can even be changed with dup2(), and anyway, that would break the abstraction. Commented Jan 31, 2021 at 21:17
  • 1
    @AnT, as for formal specification, I suppose you'll have to look at the documentation of the behaviour of the terminal device nodes on your OS. Commented Jan 31, 2021 at 21:20
  • @AnT, ah, that first comment could be seen a bit flippant, sorry. But I'm serious in that I can't see any way it would make a difference if the terminal is open on fd 0, fd 1, or some fd >= 3. POSIX says that fds 0, 1 and 2 should be open when a process is executed, or the environment is non-conformant and may cause trouble (meaning that it technically accepts that such a thing can happen, it doesn't say that they shall be open), and of course they're used by default for input and output, but other than that, I don't know anything that would make them special. Commented Feb 1, 2021 at 11:43
  • @AnT, implementation-wise, I fully expect a kernel to handle them just like any other fd, and to let userspace deal with the customs and their consequences. That would be the simple and straightforward implementation anyway. There's really no reason for the kernel to stop writes to stdin, and hey, it could be useful sometimes. stderr could also be read from, to get to the user without the usual redirections getting in the way (though opening /dev/tty might be better), and stty configures the terminal on stdin (that's an ioctl(), not write(), though). Commented Feb 1, 2021 at 11:54

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.