1

This command does not terminate

echo `bash -c 'tail -f /dev/null & echo hello world'`

despite the fact that

bash -c 'tail -f /dev/null & echo hello world'

correctly returns "hello world"

I am trying to background a command inside a bash script that is evaluated inside backticks. I actually need to run eval and not echo, for for this example I'm using echo. The script in question emulates an ssh-agent which outputs typically a number of export statements. However, inside the script I need to background a job.

I have tried to use disown, nohup or $() instead of backticks. It seems that the backticks always wait for the termination of all child processes. Is there a way to circumvent this? I particularly would be interested in receiving the PID of the backgrounded command.

0

2 Answers 2

2

In:

echo `shell code`

Which is the deprecated form of:

echo $(shell code)

shell code is evaluated in a subshell and its whole output, stripped of the trailing newline characters and, since you forgot to quote it, subject to split+glob is passed as argument to echo.

To do that, the shell makes the stdout of that subshell a pipe, and at the other end of the pipe, the shell reads the output until end-of-file, that is, until all processes that have their stdout (or any other fd) open on that pipe either close those fds or terminate.

In:

echo "$(sleep 10 & echo done)"

Even though sleep 10 is run asynchronously and its termination is not waited for by the subshell, the process running sleep still has its stdout (fd 1) open on the pipe and it will remain so until it exits, so the shell will have to wait until sleep terminates to know that there's no more output to be read.

If you change it to:

echo "$(sleep 10 > /dev/null & echo done)"

You'll see it returns instantly while sleep carries on running in background as sleep in that case doesn't have any fd open onto the pipe.

6
  • I can't undestand why 'echo bash -c 'tail -f /dev/null & echo hello world'' does not terminate as TO claims
    – gapsf
    Commented Jul 30, 2022 at 19:00
  • @gapsf, same thing, tail has its stdout on the pipe. Commented Jul 30, 2022 at 19:10
  • @ Stéphane Chazelas So it prints 'hellow world' and 'tail -f /dev/null' runs forever? Or commands splited and just tail runs?
    – gapsf
    Commented Jul 30, 2022 at 19:21
  • Thanks for your answer the funny thing is that I tried this and my non-reduced version still has the problem. Btw I would disagree with deprecation (backticks are just the old posix way which work fine if you won't nest.)
    – till
    Commented Jul 31, 2022 at 8:20
  • 1
    @till, they are nestable alright, they're just very painful to use properly (with quotes), causes hard to spot/debug problems with backslash inside and there are portability issues as well. Commented Jul 31, 2022 at 8:23
1

I particularly would be interested in receiving the PID of the backgrounded command.

My guess you want pid of tail, not a bash.

You don't have to use bash -c just

tail -f /dev/null & echo $!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .