Re: Surprising behaviour when reading from a named pipe and standard input

Harald van Dijk <[email protected]> Tue, 10 Feb 2026 02:00:18 +0000
Newsgroups org.kernel.vger.dash
Message-ID <[email protected]>
On 10/02/2026 01:11, Earnestly wrote:
> I came across this behavioural difference between dash and sh(bash),
> bash and zsh.
> 
> When attempting to read from a named pipe and stdin at the same time in
> a backgrounded process I appear to be losing stdin:
> 
>      #!/bin/dash --
> 
>      f() {
>          mkfifo pipe
> 
>          cat pipe - <&0 &
In both bash and dash, backgound commands have an implicit </dev/null 
redirection unless an explicit redirection is provided, but they 
disagree on exactly how that works.

In bash, <&0 suppresses the implicit </dev/null, meaning the outer 
environment's stdin gets used.

In dash, internally, <&0 is a no-op because redirecting stdin to itself 
shouldn't change anything. Because it is a no-op, it does not suppress 
the implicit </dev/null.

In dash, effectively, it is as if <&0 overrides rather than suppresses 
the implicit </dev/null: the implict </dev/null is performed, and then 
<&0 overrides that but at that point fd 0 is already /dev/null, so after 
that, it is still /dev/null.

I have mixed feelings on which behaviour makes more sense, but for 
better or worse this is something that portable shell scripts just need 
to avoid. You can make this work by temporarily duplicating stdin to a 
different fd and then back:

   { cat pipe - <&3 & } 3<&0

Cheers,
Harald van Dijk