I need to run a unix shell script (my_script) in background and monitor it from web interface.

I start the actual script from php like so:

$command = 'my_script';
$pid= exec("nohup {$command} > {$logFile} & echo $!");

Then $pid contains the pid of my process and I can find out if the process is still running by checking file_exists("/proc/{$pid}").

However, here's the problem: how do I find out when the process has terminated and how long it ran when it is terminated?

Also, is there a good way to find out when the process has started? I can record the timestamp in PHP before or after I make the exec call, but that will be somewhat inaccurate.


To clarify, PHP script can't wait for shell script to finish. The shell script needs to be run in the background. I can probably wrap three commands (record time started, run my_script, record time finished) into one shell with sh -c pass it to nohup, but I would prefer the whole sequence to be atomic, so that I do not end up with only start time recorded if something goes wrong.


You'll need to get rid of the intermediary shell and start it as your direct child, probably with something like proc_open (I'm no PHP expert). Then you'll get a SIGCHLD when the child terminates. You can install a signal handler for it (pcntl_signal most likely) and in it nonblockingly (WNOHANG) wait (pcntl_waitpid ) on your child's PID and if the wait succeeds, record the time and remove the signal handler.

file_exists("/proc/{$pid}") is unreliable if you don't control the wait calls (if pid isn't your child) because PIDs get recycled.

| improve this answer | |
  • Problem is, i need to run that script in the background. So my php script can't wait for that other script to finish. – Beowulfenator Jun 20 '15 at 21:36
  • I said you should wait in you signal handler. Signals are asynchronous. – PSkocik Jun 20 '15 at 21:38
  • proc_open won't block your script. Your script will go on and when the child process terminates, your script will get the SIGCHLD signal. You need to have a handler for that signal. In it you check whether it was truly the death of your child process by calling it with the target child's and the WNOHANG flag and if it was, you record the time of death and uninstall the handler (SIGCHLD generally means something's up with one of your child processes). – PSkocik Jun 20 '15 at 21:47
  • I trust you'll be able to search the documentation (php.net/manual ; I believe) for invocation-related details. – PSkocik Jun 20 '15 at 21:49
  • Do I get this correctly: PHP starts my_script as its child using proc_open, and then continues execution. At some point the child is terminated and this PHP script gets a signal and executes the proper handler. But then this means that PHP script can't stop until its child terminates (even though the waiting is non-blocking and it can do other stuff)? – Beowulfenator Jun 20 '15 at 21:49

This seems to call for at/batch since you are using a web front end. The results can either be emailed to the user or a que which gets poled by the user (using client side javascript or just plain user based checking).

| improve this answer | |

The easiest way to record a script's exit conditions is to make it record them.

trap 'date +"
    My name is $0. My PID is $$.
    My start time was '"$(date)."'
    The time is now %X on %x.
    My exit code is $?. Goodbye.
"   >/tell/somebody' EXIT
: now do some stuff

An EXIT trap should work in every exit scenario but one which is initiated by a SIGKILL.

If you cannot edit the script in question just wrap the script in a shell whose instructions you can control - such as with sh -c as you mentioned:

trap=': the trap' sh -c '
trap "$trap" 0;. "$0"'   \
    ./script/i/cant/edit \
    positional params    &

A similar thing might done w/ sh -s, but the value of $0 may not be as simply as controlled. With some shells you need to exec a new infile/replacement shell in order to alter it (I sometimes use symlinks and PATH=. w/ exec to change/drop all path components in a process name).

echo 'trap "$trap" EXIT'   |
cat - ./script/i/cant/edit | 
trap=': the trap' sh -s -- \
    positional params go here &
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.