I need to have a script execute (bash or perl or php, any will do) another command and then exit, while the other command still runs and exits on its own. I could schedule via at command, but was curious if there was a easier way.
#!/bin/sh
your_cmd &
echo "started your_cmd, now exiting!"
Similar constructs exists for perl and php, but in sh/bash its very easy to run another command in the background and proceed.
edit
A very good source for generic process manipulation are all the start scripts under /etc/init.d. They do all sorts of neat tricks such as keep track of pids, executing basic start/stop/restart commands etc.
To run a command in the background, you can append an '&' to the command.
If you need the program to last past your login session, you can use nohup.
See this similar stackoverflow discussion: how to run a command in the background ...
The usual way to run a command and have it keep running when you log out is to use nohup(1). nohup prevents the given command from receiving the HUP signal when the shell exits. You also need to run in the background with the ampersand (&) command suffix.
$ nohup some_command arg1 arg2 &
&?
#!/usr/bin/bash
# command1.sh: execute command2.sh and exit
command2.sh &
I'm not entirely sure if this is what you are looking for, but you can background a process executed in a shell by appending the ampersand (&) symbol as the last character of the command.
So if you have script, a.sh
and a.sh needs to spawn a seperate process, like say execute the script b.sh, you'd:
b.sh &
So long as you mentioned Perl:
fork || exec "ls";
...where "ls" is anything at all. Repeat for as many commands as you need to fire off.
Most answers are correct in showing..
mycmd &
camh's answer goes further to keep it alive with nohup.
Going further with advanced topics...
mycmd1 &
mycmd2 &
mycmd3 &
wait
"wait" will block processing until the backgrounded tasks are all completed. This can be useful if response times are significant such as for off-system data collection. It helps if you an be sure they will complete.
How do I subsequently foreground a process?
If it is your intent to foreground a process on a subsequent logon, look into screen or tmux.
screen -dmS MVS ./mvs
or (Minecraft example).
screen -dm java -Xmx4096M -Xms1024M -jar server.jar nogui
You can then re-attach to the terminal upon subsequent login.
screen -r
The login that launches these need not be interactive, you can use ssh remotely (plink, Ansible, etc.) to spawn these in a "drive by" manner.
Related
I have two websites using the Laravel framework. I need to use a command to process queues. For that I use nohup.
However I need to run two identical nohup commands to make it run in the background for the two different websites. The problem is that sometimes I need to stop only one command for maintenance. How do I identify which nohup command belongs to a particular website ? Can I use a name identifier in the nohup command ?
You could use php's -E cli argument, which lets you specify code to execute "after" the rest of the script completes, and this extra code could be just a PHP comment, allowing you to embed ID information:
sudo nohup php -E '//job #x' artisan etc...
^^^^^^^^---raw php code, no <?..?> required
Since it's just a comment, it won't actually DO anything, and you can format the comment to contain whatever ID information you want.
Witch $! you can get the PID of the last background process. Save it to a file like echo $! > processA.pid and then use that PID to stop the desired process.
I have a php script that leads up to running another expect script by passing it arguments.
$output = shell_exec("expect login_script.tcl '$user' '$host' '$port' '$password'");
Using shell_exec doesn't work as the script gets run in the background or 'within' the php script. I need it to run in the foreground, allowing user interactivity. Is there an elegant way to do this. Already it is getting messy by having to use different scripting languages. I tried wrapping the two scripts with a shell script that called the php script, assigned output the result as a variable (which was a command) and then ran sh on that. However I have the same problem again where the scripts are run in the background and any user interactivity creates a halt/freeze. Its ok in this situation if php 'quits' out when calling shell exec. Ie. php stops and expect gets run as if you called it. (the same as if i just copied the command that is output and pasted it into the terminal).
Update
I am having much more luck with the following command in php:
shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &");
However, can this be improved in order to not close the shell immediately after the secondary script (login_script) is finished?
Further Update
From reading the answers I think I need to clarify things as it looks like people are assuming a 'more complicated' issue.
the two processes do not need to communicate with each other, I should probably not have put the $output = shell_exec in the example and just shell_exec on its own as I believe this has led to the confusion.
The php script needs to only initiate the expect script with some cli parameters, e.g. my-script 'param1' 'param2' and can be thought of as completely 'asynchronous'. This is much like the behaviour of launcher programs like 'launchy' or 'synapse' they can launch other programs but need not affect them. Nor do they wait for the secondary program to quit/finish.
I made the mistake of saying 'shell_exec' doesn't work for me. What I should have said was that 'I have so far not succeeded with using shell_exec', but shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &"); is 'working' but still trying to find the right quote combination to allow passing arguments to the expect script.
Task managing is an interesting but difficult job.
Because your user can move during a task (and leads it to an unexpected result, such as session freezes, or an incomplete work from the process), you need to execute it in background. If you need to interact between your user and your process, you'll need to create a way to communicate.
The easiest way (I think) is to use a file, shared between your user session and the task.
If you have a lot of users simultaneously and communicates a lot between user and processes, you can mount a partition in memory to optimize the read/write operations.
In your fstab, a line like :
tmpfs /memory tmpfs defaults,uid=www-data,gid=www-data,size=128M 0 0
Or, in a script, you could do :
#!/bin/sh
mkfs -t ext2 -q /dev/ram1 65536
[ ! -d /memory ] && mkdir -p /memory
mount /dev/ram1 /memory
chmod -R 777 /memory
You'll need to take care of a lot of things :
file access (to avoid concurrency between your webapp and your processes)
time (to avoid zombies or useless long-running scripts)
security (such operations must be carefully designed)
resources management (to avoid that 10000 processes runs simuntaneouly)
...
I think what you're looking for is the proc_open() command. It gives you access to the stdin/stdout streams of the background process. You can pass your own stdin/stdout streams to the new process in the $descriptorSpec parameter, which will let your background process talk to the user.
Your 'foreground' application will have to wait around until the background process has died. I haven't actuallly done this with PHP, but I'm guessing you'll have to watch the $pipes to see when they get closed -- then you'll know the background process is finished and you can delete the process resource and continue on with whatever the foreground process needs to do.
In the end, I managed to get it working by by adding a third quotation mark type: ` (I believe it is called a 'tack'?) which allowed me to pass arguments to the next script from the first script
The command I needed in my php script was:
$command = `gnome-terminal -e 'bash -c "expect ~/commands/login_script.tcl \"$user\" \"$host\" \"$port\" \"$password\"; exec bash"' &`;
shell_exec($command);
It took a while to get all the quotes right as swapping the type of quotes around can lead to it not working.
Here is a video demonstrating the end result
Use:
pcntl_exec("command", array("parameter1", "parameter2"));
For example, I have a script that starts the mysql command using the parameters in the current php project that looks like:
pcntl_exec("/usr/bin/mysql", array(
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));
This doesn't rely on gnome terminal or anything, it replaces PHP with the program you call.
You do need to know the full path of the command, which is a pain because it can vary by platform, but you can use the env command command which is available at /usr/bin/env on most systems to find the command for you. The above example above becomes:
pcntl_exec("/usr/bin/env", array(
"mysql",
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));
In a apcahe server i want to run a PHP scripts as cron which starts a php file in background and exits just after starting of the file and doesn't wait for the script to complete as that script will take around 60 minutes to complete.how this can be done?
You should know that there is no threads in PHP.
But you can execute programs and detach them easily if you're running on Unix/linux system.
$command = "/usr/bin/php '/path/to/your/php/to/execute.php'";
exec("{$command} > /dev/null 2>&1 & echo -n \$!");
May do the job. Let's explain a bit :
exec($command);
Executes /usr/bin/php '/path/to/your/php/to/execute.php' : your script is launched but Apache will awaits the end of the execution before executing next code.
> /dev/null
will redirect standard output (ie. your echo, print etc) to a virtual file (all outputs written in it are lost).
2>&1
will redirect error output to standard output, writting in the same virtual and non-existing file. This avoids having logs into your apache2/error.log for example.
&
is the most important thing in your case : it will detach your execution of $command : so exec() will immediatly release your php code execution.
echo -n \$!
will give PID of your detached execution as response : it will be returned by exec() and makes you able to work with it (such as, put this pid into a database and kill it after some time to avoid zombies).
You need to use "&" symbol to run program as background proccess.
$ php -f file.php &
Thats will run this command in background.
You may wright sh script
#!/bin/bash
php -f file.php &
And run this script from crontab.
This may not be the best solution to your specific problem. But for the record, there is Threads in PHP.
https://github.com/krakjoe/pthreads
I'm assuming you know how to use threads, this is very young code that I wrote myself, but if you have experience with threads and mutex and the like you should be able to solve your problem using this extension.
This is clearly a shameless plug of my own project, and if the user doesn't have the access required to install extensions then it won't help him, but many people find stackoverflow and it will solve other problems no doubt ...
I maintain a game server and unruly players frequently crash the application. My moderation team needs the ability to restart the server process, but allowing ssh access would be impractical/insecure, so im using shell exec to pass the needed commands to restart the server process from a web based interface. The problem is, the shell session doesnt detatch properly and thus php maintains its session untill it finally times out and closes the session/stops the server process.
Here's how I'm calling shell_exec:
$command='nohup java -jar foobar_server.jar';
shell_exec($command);
shell_exec will wait until the command you've executed returns (e.g. drops back to a shell prompt). If you want to run that as a background task, so shelL_exec returns immediately, then do
$command='nohup java -jar foobar_server.jar &';
^--- run in background
Of course, that assumes you're doing this on a unix/linux host. For windows, it'd be somewhat different.
If you try this you'd see it won't work. To fully detach in PHP you must also do stdout redirection else shell_exec will hang even with '&'.
This is what you'd really want:
shell_exec('java -jar foobar_server.jar >/dev/null 2>&1 &');
But to take this one step further, I would get rid of the web interface and make this a one-minute interval cronjob which first checks if the process is running, and if it's not start a new instance:
#!/bin/bash
if ! pidof foobar_server.jar; then
java -jar foobar_server.jar >/tmp/foobar_server.log 2>&1 &;
fi
And have that run every minute, if it finds a running process it does nothing, else it starts a new instance. Worst case scenerio after a server crash is 59 seconds downtime.
Cheers
I want initiate one php page as background process from another php page.
Use popen():
$command = 'php somefile.php';
pclose(popen($command,'r'));
This launches somefile.php as a background process.
This is a technique I used to get around restrictions applied by my webhost (who limited cronjobs to 15 minutes of execution time, so my backup scripts would always timeout).
exec( 'php somefile.php | /dev/null &' );
The breakdown of this line is:
exec() - PHP reference Runs the specified command, as if from the Linux Command Line.
php somefile.php: Invokes PHP to open, and run, somefile.php. This is the same behaviour as what would happen if that file was accessed through a web browser.
| ("pipe") - Sends the output of the proceeding command to a specified target. In this instance, it would "pipe" the content which would normally be read by the web browser accessing the file.
/dev/null - A blackhole. No, not kidding. It is a place where you send output if you just want it to disappear.
& - Appending this character to the end of a Linux command means "Do not wait - Send this to the background and continue."
So, in summary, the provided code will execute a PHP script, return no output, and not wait for it to finish before continuing onto the next line.
(And, as always, if any of these assumptions on my part are in error, I would love to be corrected by more knowledgeable members of the community.)
You have to make sure, that the background process is not terminated when the processing of the page finished. If you are on a Linux system, you could try to use the nohup command:
$command = 'nohup php somefile.php';
pclose(popen($command,'r'));
If it still gets terminated, you could try the "daemon" command.