Search code examples
bashpid

bash getting background process id gives parent pid


Creating a bash script with this command:

cat <<"END"> z
#! /bin/bash

sleep 20 && exit 1 &
ret=$!

ps $ret | grep $ret
END

and then running it gives:

7230 pts/39   S+     0:00 /bin/bash ./z

I was expecting to see sleep 20 ... which is the child process. If I remove the && exit 1 it does return the child process.

Whats the reason? How can I get the child process id in above statement?


Solution

  • You already get the right information about the child process. Only in your case, ps doesn't know or want to show a proper COMMAND name for your chained sub-process you start in the background - what probably confused you.

    Looks like this is the case with the chained commands (.. && ..., thus it has nothing to do with exit 1 could be also echo 5 etc.) where the process group leader name is showed as cmd name instead.

    From the (ps man page)

    `cmd | COMMAND`: simple name of executable
    
    # Process state codes
    `S`: interruptible sleep (waiting for an event to complete)
    `+`: is in the foreground process group
    

    See the S+ in your ps | grep output.

    So, you can adapt your script a bit to confirm that you actually capture(d) the right information about the child process, like so:

    cat <<"END"> z
    #! /bin/bash
    
    sleep 20 && exit 1 &
    ret=$!
    
    echo $ret
    
    jobs -l
    
    # display parent and child process info
    # -j Jobs format
    ps -j  $$ $ret 
    END
    

    Output of echo $ret:

    30274
    

    Output of jobs -l:

    [1]+ 30274 Running                 sleep 20 && exit 1 &
    

    Output of ps -j $$ $ret:

    PID   PGID   SID   TTY    STAT    TIME COMMAND
    30273 30273 21804 pts/0    S+     0:00 /bin/bash ./z
    30274 30273 21804 pts/0    S+     0:00 /bin/bash ./z
    

    Note that both the parent and child have the same PGID, whereas the pid 30274 of the child process displayed by jobs -l and ps ... matches.

    Further, if you change sleep 20 && exit 1 & as bash -c 'sleep 20 && exit 1' & you would get a proper command name for the child this time, as follows (cf. output order above):

    30384
    
    [1]+ 30384 Running                 bash -c 'sleep 20 && exit 1' &
    
    PID    PGID  SID   TTY    STAT    TIME COMMAND
    30383 30383 21804 pts/0    S+     0:00 /bin/bash ./z
    30384 30383 21804 pts/0    S+     0:00 bash -c sleep 20 && exit 1
    

    Last but not least, in your original version instead of ps $ret | grep $ret you could also try

    pstree -s $ret
    

    From pstree man page

    -s: Show parent processes of the specified process.

    Which will provide you with an output similar to that one below, which would also confirm that you get the right process info for sleep 20 && exit 1 &:

    systemd───systemd───gnome-terminal-───bash───bash───sleep