Wednesday, March 2, 2011

php doing multiple commands without hanging

For some reason, running multiple commands (for programs that take long) while redirecting one of their outputs to a file, in the background, hanged my browser in php. My command was something like this:

command.sh somefile.txt &> output.txt && some_other_command.sh somefile2.txt &
And my php code looked like this:
exec($command); //$command being the above string in single quotes


If run in the shell (command line) though, it works without any problem, correctly being run in the background.

I have no idea what the reasons are, but there are three points that you have to be careful with when running multiple commands like this:

  1. The exec() function. Even after correcting the code (no. 2 and 3), it would still hang when using it.
    The solution is to use popen()/pclose(), and fread().
    E.g. instead of:
    exec($command)
    do something like:
    $handle = popen($command, "r");
    fread($handle, 4);
    pclose($handle);

  2. The "&&" string. The program correctly returned status 0 (you can check that with "echo $?" in your shell). But this makes it hang too.
    The solution is to use ";" instead.
  3. The output redirection... have no idea why.
    The solution is to use the "tee" command to output to a file better.
So, the above code corrected would look like this:

command.sh somefile.txt |tee output.txt ; some_other_command.sh somefile2.txt &

And the php code would look something like:
$command = 'command.sh somefile.txt |tee output.txt ; some_other_command.sh somefile2.txt &'
$handle = popen($command, "r");
fread($handle, 4);
pclose($handle);


Although running the command in a sub-shell environment makes it easier to read (and maybe necessary).
I mean, instead of running it like:
command.sh somefile.txt |tee output.txt ; some_other_command.sh somefile2.txt &
You run it like:
(command.sh somefile.txt |tee output.txt ; some_other_command.sh somefile2.txt) &
So you can clearly see what the expression is like, and that it will be run as a background process.




My real command, included sending an e-mail, whose contents were also made with php.
Just in case anyone is interested...
$command = "(nohub nice -n 15 command.sh somefile.txt |tee output_log.txt ; mail -a $mail_header -s $mail_subject $mail_address <<EOF
$mail_contents
EOF

) &";
$handle = popen($command, "r");
fread($handle, 4);
pclose($handle);


Remember to use double quotation ("") in strings where you want php variables replaced ('$stuff' will return just the string '$stuff', while "$stuff" will return the actual contents of that string). It makes the code easier to read.
The beauty of this, is that sends you an e-mail after the program is done! And, as running in the background, it allows the user to just close the browser window without interrupting the program.

No comments:

Post a Comment