I'm trying to get the PID of a background job with command substitution. The background job is started with setsid
. The problem is that the parent process is struck at the command substitution.
Here is an example script:
#!/bin/bash
if [ "$1" = "start" ]; then
while true; do date > "bg.date"; sleep 1; done &
echo $!
exit 0
fi
pid="$(setsid "$0" start)"
echo "pid=$pid"
./script start
works as expected (ie. exits immediately to bash prompt while background job is running).setsid ./script start
also works as expected../script
does not work as expected: it does not print the PID (unless the background job is killed manually).Command substitution is implemented via pipes. The read end waits for all writers to close, but you're keeping the write end open indefinitely as the stdout of your infinite loop.
You can redirect the loop to avoid this:
#!/bin/bash
if [ "$1" = "start" ]; then
while true; do date > "bg.date"; sleep 1; done > /dev/null &
echo $!
exit 0
fi
pid="$(setsid "$0" start)"
echo "pid=$pid"
If the re-entrant setsid
was part of an attempt to make the script not hang, you'll be pleased to know that this is unnecessary and you can rewrite it more robustly with a simple function.