These do not do the same:
$ seq 1000000 | (ssh localhost sleep 1; wc -l) 675173 $ seq 1000000 | (ssh localhost sleep 1 </dev/null; wc -l) 1000000
What is the rationale for
ssh reading stdin?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
ssh always reads stdin unless you tell it not to with the
-n option (or the
The reason is so that you can do things like
tar cf - somedir | ssh otherhost "tar xf -"
And it always does this because ssh has no way of knowing if your remote command accepts input or not.
Likely what is happening in your first command is that seq fills up the network and pipe buffers (seq -> ssh -> sleep), and since sleep isn't reading anything, it gets blocked waiting for more reads, and then sleep exits, causing those full buffers to be dumped, and then seq is unblocked, feeding the remainder to wc.
Note that you would get similar results with
seq 1000000 | ( cat | cat | sleep 1; wc -l)
In your second command, it is still reading stdin, but you've externally assigned /dev/null to stdin.
Unix input/output is based on unidirectional communication primitives: pushing data with
write¹, pulling data with
read¹, and querying the availability of data with
select. It is not the same model as, for example, is common on the web, where the consumer of data sends a request “please give me some data” and the producer replies with the data, or the consumer sends a request “how much data can you give me?” and the producer replies with a size. A data consumer calls
read to retrieve whatever data is available, and this doesn't necessarily need to involve the producer (e.g. pipes have a buffer and reading from the buffer doesn't have to involve the write end of the pipe). A data consumer can call
select to know whether data is available, and this doesn't involve the producer at all.
The SSH server can know whether the application running on the server is actively trying to read from its standard input: the SSH server can call
select to know whether writing data would block. But if the application tries reading intermittently, the SSH server might not call
select at the right time, so it could miss that the application is trying to read data. And the SSH server has no way to know whether or when the application asks there's data available on its standard input by calling
select. The only way the SSH server can provide data to the application when it wants is to provide data to the application when it's available.
This requires the client to transmit the data to the server. So the client reads its standard input and forwards data as soon as it's available.
Once the client has read some data from its standard input, it can't un-read it. If the server-side application doesn't end up consuming the data, it's lost.
As a consequence, when you're calling
ssh, you need to decide on the client side whether you want standard input to be routed through the SSH connection or not. It's not something the server can tell you.
See also SSH connections running in the background don't exit if multiple connections have been started by the same shell which explores a scenario that's similar, but more complex, involving terminals.
¹ and friends.