How to pass the standard input of a shell script to a background command
In a shell script, I am trying to start a background command that has the same stdin as that of the shell script.
#!/bin/sh
# ...
the-program &
However, the-program
above will not have access to the same standard input as that of the shell script. According to my shell’s manual (dash(1)):
If the shell is not interactive, the standard input of an asynchronous command is set to
/dev/null
.
I have tried the-program & <&0
but it does not seem to have the intended effect; the standard input of the-program
is still /dev/null
.
I thought about creating a new file descriptor by duplicating the standard input of the shell script and somehow pass that new file descriptor to the background process. However, the background process must then somehow redirect that new file descriptor to its standard input (replacing /dev/null
). I have no idea if this idea is even possible, and I do not know how to implement it in POSIX sh.
Yes, that’s an annoying requirement of the POSIX sh
specification that commands started asynchronously by non-interative shell invocations (when the monitor
option IOW job control is not enabled) have their stdin redirected to /dev/null.
If job control is disabled (see
set
,-m
), the standard input for an asynchronous list, before any explicit redirections are performed, shall be considered to be assigned to a file that has the same properties as/dev/null
. This shall not happen if job control is enabled. In all cases, explicit redirection of standard input shall override this activity.
The usual work around is to do:
{ cmd <&3 3<&- & } 3<&0
Which sounds like what you were thinking of.
Example:
$ sh -c 'readlink /proc/self/fd/0 & wait' < /
/dev/null
$ sh -c '{ readlink /proc/self/fd/0 <&3 3<&- & } 3<&0; wait' < /
/
Other option is to use zsh
which ignores that requirement even in sh
emulation:
$ zsh -c 'readlink /proc/self/fd/0 & wait' < /
/
$ zsh --emulate sh -c 'readlink /proc/self/fd/0 & wait' < /
/