Is it possible, in portable shell, without using a named pipe, to start a background process and have that process's stdin be a pipe which is open on file descriptor 3 (or some other number greater than 2) in the parent shell? Another way to put it is that I want to do in portable shell what popen("some-program", "w")
does in C.
Concretely, do what this snippet does, without using mkfifo
:
mkfifo fifo
some-program < fifo &
exec 3> fifo
rm fifo
Note: "bash" tag added primarily for visibility. I understand that this is possible using the "coprocess" extension in bash, ksh, or zsh; I am looking for a technique that works in an environment where only the facilities of XPG Issue 6 (POSIX.1-2001) Shell and Utilities are available. In addition, answers that use a named pipe (via mkfifo
most obviously) will not be accepted, as will answers that require root
privileges.
Answers that use any of the following are discouraged, but I'll listen to an argument that it's not possible to do it without one or more of them:
c99
)vi
)uucp
)I'll also listen to an answer that makes a convincing argument that this is impossible within the restrictions above.
(Why no named pipes? Because they don't behave quite the same as normal pipes, particularly with the older, buggier OSes where "just use #!/bin/bash
" isn't an option. Also, exposing the pipe in the file system, however briefly, means you cannot completely exclude the possibility of some unrelated process opening the pipe.)
Does it have to be backgrounded per se, and can you tolerate a different parent process?
#! /bin/sh
if [ -z "$REINVOKED" ]; then
# First time we're running.
# Save our stdout and launch some-program on a pipe connected to
# our second invocation. (A new shell will replace this one.)
exec 4>&1
REINVOKED=true
export REINVOKED
exec /bin/sh -c "$0 | some-program" # <- WARNING
exit 1
fi
# Second invocation.
#
exec 3>&1 # dup the pipe (our stdout) to fd3
exec 1>&4 # restore stdout from inherited fd4
exec 4>&- # close fd4
echo "READY" # goes to stdout
echo "READY" >&3 # goes to some-program
...
That dodgy environment variable usage to detect a second invocation of the script could be more robustly reimplemented as separate scripts. The WARNING line is where you will need to watch future revisions for command injection (CWE-78).
The processes ancestry will look like this:
/bin/sh -c "/rather/dodgy.sh | some-program"
|
+- /bin/sh -c /rather/dodgy.sh
|
+- some-program
All in the same process group, and presumably spawned from your interactive shell (-bash
?).