How to get the pid to the last background app

processps

Following from this question: How to get the pid of the last executed command in shell script?

The thread there is good and clear, but what if the command actually doesn't require a '&' at the end in order to background itself? Is it then possible to get it's PID ?

Nota bene: I do NOT want to use ps and grep; I am asking because theoretically, just after running a command, the PID of that process supposed to be find-able.

An example of an app that backgrounds itself — this is not the one I need, I need a generic solution for things like any stuff which go background by itself (some forcing it with no "foreground" option at all) — but for testing a solution this will work just fine:

my-app script:

#!/bin/bash

(
sleep 10
echo test
sleep 5
) &

as you can see the '&' is inside the script and not outside, so, starting it won't require &:

./my-app ; echo $! | od -c ; jobs | od -c
0000000  \n
0000001
0000000

$! is null, and jobs returns nothing. Still, after 10 seconds, a "test" message will appear; also:

ps x | grep my-app | grep -v grep        
14986 pts/5    S      0:00 /bin/bash ./my-app

Update, after some comments saying that bash jobs don't apply here; I'm hoping for a solution and my hope is not limited to bash 🙂

Best Answer

To background itself, that application forks a child process and exits the parent. The shell knows of the parent process as that's the one it has forked itself before executing the command itself, but it has no visibility on the children or grand-children that that process may have spawned.

A simpler example of such a backgrounding command would be:

$ sh -c 'ps -j; sleep 10 &'
  PID  PGID   SID TTY          TIME CMD
 6562  6562 14469 pts/13   00:00:00 sh
 6563  6562 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

My zsh knows about that sh process and its process group.

However, all it sees is that 6562 process exiting. It has no way to know that 6562 process has spawned a 6563 one.

$ ps -j
  PID  PGID   SID TTY          TIME CMD
 6564  6562 14469 pts/13   00:00:00 sleep
 6565  6565 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

However, you can see the process running sleep is also in that 6562 process group (though, there's nothing stopping commands start new process groups, or even sessions (as daemons typically do)).

Those process groups are only created when the shell is interactive though.

Another thing you could do is:

cmd | cat &
wait

If the processes that cmd spawns don't close their stdout, then cat won't die until they have all died.

Related Question