3

I am trying to understand the "oneliner" in this comment by @sysfault:

/bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &

I tried the following variations...

Different $$ inside and out:

/bin/bash -c 'echo $$ && exec sleep 5' ; echo $$
14408
29700

Same pid (but in background):

$ /bin/bash -c 'echo $$ && exec sleep 5' & echo $! 
[1] 8309
8309
$ 8309

[ 1 ]+  Done  /bin/bash -c 'echo $$ && exec sleep 5'

Different pid for $$ & $! :

/bin/bash -c 'echo $$ && exec sleep 5 & echo $!'                                 
6504
6503

Kill did not work: /bin/bash -c 'echo $$ && (sleep 15 ; echo done)'
19063 Killed $ done (echo showed up after the kill)

Same pid with access to the pid of the foreground process:

$ /bin/bash -c 'echo > tmp.pid ; sleep 10 ; echo $$ ; echo done ; echo $$;'      
28415 (instantly)
28415 (10 seconds later)
done
28415
$ cat tmp.pid 
28415

With this command I was able to kill the pid in another window before the sleep finished - preventing the last three echos from happening:

$ /bin/bash -c 'echo $$ ; sleep 30 ; echo $$ ; echo done ; echo $$;'               
23236
Killed

Context: Ultimately I want to start bash processes via php exec(), and wait for the result before continuing and save the pid so i can clean up in case the manual cancel button is pressed. There are 2 expensive processes i will deal with: one rsync and one git commit & push.

What is the best way to reliably get the pid of a foreground bash script that includes multiple commands (with ; > | or &&) ?

gotjosh
  • 133
  • 4
  • 1
    Consider using `proc_open()`, `proc_get_status()` and `proc_close()` instead. – Michael Hampton Feb 06 '18 at 20:46
  • This comment was really helpful for the php part of the question, Thanks! I consider to make a separate question rather than get this one moved as @glenn-jackman suggested. – gotjosh Feb 10 '18 at 13:04

1 Answers1

7

$$ is the PID of the current shell. When you use $$ in the bash -c script body, you get the pid of that spawned shell

$ echo $$; bash -c 'echo $$'; echo $$
6872
6987
6872

$! is the PID of the last backgrounded process

$ sleep 5 & echo $!; sleep 5 & echo $!; echo ===; pgrep -l sleep
[1] 7118
7118
[2] 7119
7119
===
7118 sleep
7119 sleep

When you do bash -c 'echo $$' & echo $!, you get the same pid printed twice because, for your current shell, $! is the pid of the backgrounded bash process, and inside the script body, $$ is the current pid of that same backgrounded bash process.

When you do /bin/bash -c 'echo $$ && exec sleep 5 & echo $!', you get two different pids: $$ is the pid of the bash process and $! is the pid of the sleep process.

  • I find this odd because you're using exec so it should be the same PID (the sleep process replacing the bash process)
  • However you're using exec ... & so bash must first fork a subshell to run the backgrounded task, and then exec replaces that subshell with sleep.

The answer to your actual question is best answered by a php person, which I am not. You should flag this question to a moderator and request it be moved to Stack Overflow where more php people are bound to hang out.

glenn jackman
  • 4,320
  • 16
  • 19
  • I consider to post a separate question, but I posted this one here consciously, as I want to more deeply understand the details that you outlined. So, Thanks! – gotjosh Feb 10 '18 at 13:06