Is there a way that stdin can 'hop' over a process? For example, in the following command,

cat file | ssh host 'mkdir -p /some/directory && cat > /some/directory/file'

This will send the stdin from the first cat to mkdir and the second cat will recieve no stdin. I want the stdout from the first cat to hop over mkdir and only be sent to the second cat. I am aware that you can run something like:

cat file | ssh host 'cat > /tmp/file2 ; mkdir -p /some/directory && mv /tmp/file2 /some/directory/'

That only works when copying a file or

cat file | ssh host 'tee >(mkdir -p /some/directory) >/some/directory/file'

But that only works because the mkdir command does not use stdin. Is there a command that will execute a command that replicates this functionality? Something like:

cat file | ssh host 'stdinhop mkdir -p /some/directory | cat > /some/directory/file'

where stdinhop would not send its stdin to mkdir, but it redirect it to stdout so the second cat can read it?


You can redirect the first command's stdin from /dev/null:

anthony@Watt:~$ echo -e 'hello\nworld' | ssh localhost 'cat < /dev/null && cat -n'
     1  hello
     2  world

The lines are numbered, so the 2nd cat got them.

If not using ssh in there, you'd use a subshell: echo -e 'hello\nworld' | ( cat < /dev/null && cat -n )

  • @don_crissti true, I figured OP wanted to run a command that insists on reading STDIN. – derobert Mar 7 '15 at 20:29
  • @don_crissti - exactly. But, essentially, the { grouping; } is already happening here. There's a single fork point - ssh. It kind of serves the same purpose here, but is a little more like out | { { group; } ; { group; }; { group; }; } and so it still needs protecting from the shell's i/o init for every group. In the same way you can absorb the input into a group like that, you can also skip it by being explicit about redirections - or both could work. You could skip over an interval group, maybe, by redirecting /dev/null into the group's stdin. – mikeserv Mar 7 '15 at 22:58

What you want is already happening, actually. And certainly mkdir isn't your problem - it doesn't read stdin anyway. That pipe is inherited as stdin by all of the children of ssh - unless, that is, you are getting a pseudo terminal like ssh -t.

Barring that, then the problem is that the shell running those commands is one of ssh's children - and part of its job is to open 0,1,2 for each command group it runs. Your input, then, is just getting lost in the shuffle because it is on a common descriptor - the same descriptor that the shell reopens for every one of its children.

And so most simply, I think, you can just move the input to a descriptor that is other than one of those three defaults. For example, the following works for me:

echo hey there >file
cat file | ssh mikeserv@localhost '
               exec 3<&0
               mkdir -p .
               echo ho there
               cat <&3'

If I run the above it prints:

ho there
hey there

You might also find some utility in the -W option to ssh. man ssh says:

  • -W host :port - Requests that standard input and output on the client be forwarded to host on port over the secure channel. Implies -N, -T, ExitOnForwardFailure and ClearAllForwardings. Works with Protocol version 2 only

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.