How to execute an application in bash that is not a child and keeps running? - bash

I am writing a bash script and am checking whether the application is running. If it is not running it should be started in a separate process (not a child process). If it is running, the window should be maximized. I kind of made it but the new process terminates shortly after being started, probably because the script process ends.
#!/bin/bash
if (ps aux | grep App1 | grep -v grep > /dev/null)
then
echo App1 is running
wmctrl -x -r WMClassOfApp1 -b "add,maximized_vert,maximized_horz"
else
echo App1 is not running
sh -c /usr/bin/app1 & disown # This app should be started in a separate process and not terminate
fi
I probably have to add that I am calling this script from a udev rule. When I execute it in a terminal, it works fine. When I call it from the udev rule, the app1 terminates.

A bash script is not the right solution for this: best is to add this to crontab of your system.

Related

How do I kill background processes / jobs started by a bash script after it finishes executing?

So I want to start a docker image, then a Django back-end and finally an angular front-end, let them run as long as I need to do tests/develop and then kill them when I'm done. To do this I first tried starting them all in a script and have them run in a background, and have a second script do kill %n for both processes. This doesn't work because the background processes are in another context, so the second script cannot reference them.
Then I tried this:
#!/bin/bash
# Exit Angular, Django and kill docker_img
function clean_up()
{
echo "Exiting..."
kill %2
kill %1
docker stop docker_img
reset
exit
}
# Trigger cleanup on CTRL + C
trap clean_up SIGINT
# Start docker database
docker start docker_img
# Start django backend
cd ~/Projects/DjangoBackend
source venv/bin/activate
python src/manage.py runserver &
sleep 3
echo 'Done starting django, starting angular'
sleep 1
# Start angular front end
cd ~/Projects/AngularFront
npm start &
However, after npm start & runs, the trap stops working, so it effectively becomes useless. I'm guessing it could be because once my script is done running the trap is no longer active, but I don't know how to fix this. What can I do?
If you are looking to kill a process in unix/linux, one way of doing it is you can record their PID in a file using ps -ef command.
And then use kill -9 to kill the process.
Example:
$ ps -ef | grep <process_name> | awk -F ' ' '{print $2}' > pid.txt
$ kill -9 `cat pid.txt`
ps -ef command will give all the running processes, using grep and process name, you can get PID of the particular process
awk is used to extract only PID from above command
kill -9 will forcefully kill the process
The answer seems to have been pretty easy, all I had to do was add wait to the end of the script, which allows the script to wait until the processes are done executing. Since two of the processes are servers, they don't stop unless prompted, so it'll just wait until SIGINT is received, at that point it'll run the clean_up function and exit gracefully.
Additionally, one could use the same trap but with the EXIT trigger instead of SIGINT to clean up when the script exits on it's own due to the processes closing.

How can I improve this bash script?

I'm trying to write a bash script.
The script should check if the MC server is running. If it crashed or stopped it will start the server automatically.
I'll use crontab to run the script every minute. I think I can run it every second it won't stress the CPU too much. I also would like to know when was the server restarted. So I'm going to print the date to the "RestartLog" file.
This is what I have so far:
#!/bin/sh
ps auxw | grep start.sh | grep -v grep > /dev/null
if [ $? != 0 ]
then
cd /home/minecraft/minecraft/ && ./start.sh && echo "Server restarted on: $(date)" >> /home/minecraft/minecraft/RestartLog.txt > /dev/null
fi
I'm just started learning Bash and I'm not sure if this is the right way to do it.
The use of cron is possible, there are other (better) solutions (monit, supervisord etc.). But that is not the question; you asked for "the right way". The right way is difficult to define, but understanding the limits and problems in your code may help you.
Executing with normal cron will happen at most once per minute. That means that you minecraft server may be down 59 seconds before it is restarted.
#!/bin/sh
You should have the #! at the beginning of the line. Don't know if this is a cut/paste problem, but it is rather important. Also, you might want to use #!/bin/bash instead of #!/bin/sh to actually use bash.
ps auxw | grep start.sh | grep -v grep > /dev/null
Some may suggest to use ps -ef but that is a question of taste. You may even use ps -ef | grep [s]tart.sh to prevent using the second grep. The main problem however with this line is that that you are parsing the process-list for a fairly generic start.sh. This may be OK if you have a dedicated server for this, but if there are more users on the server, you run the risk that someone else runs a start.sh for something completely different.
if [ $? != 0 ]
then
There was already a comment about the use of $? and clean code.
cd /home/minecraft/minecraft/ && ./start.sh && echo "Server restarted on: $(date)" >> /home/minecraft/minecraft/RestartLog.txt > /dev/null
It is a good idea to keep a log of the restarts. In this line, you make the execution of the ./start.sh dependent on the fact that the cd succeeds. Also, the echo only gets executed after the ./start.sh exists.
So that leaves me with a question: does start.sh keep on running as long as the server runs (in that case: the ps-test is ok, but the && echo makes no sense, or does start.sh exit while leaving the minecraft-server in the background (in that case the ps-grep won't work correctly, but it makes sense to echo the log record only if start.sh exits correctly).
fi
(no remarks for the fi)
If start.sh blocks until the server exists/crashes, you'd be better off to simply restart it in an infinite loop without the involvement of cron. Simply type in a console (or put into another script):
#!/bin/bash
cd /home/minecraft/minecraft/
while sleep 3; do
echo "$(date) server (re)start" >> restart.log
./start.sh # blocks until server crashes
done
But if it doesn't block (i.e. if start.sh starts the server and then returns, but the server keeps running), you would need to implement a different check to verify if the server is actually still running, other than ps|grep start.sh
PS: To kill the infinite loop you have to Ctrl+C twice: Once to stop ./start.sh and once to exit from the immediate sleep.
You can use monit for this task. See docu. It is available on most linux distributions and has a straightforward config. Find some examples in this post
For your app it will look something like
check process minecraftserver
matching "start.sh"
start program = "/home/minecraft/minecraft/start.sh"
stop program = "/home/minecraft/minecraft/stop.sh"
I wrote this answer because sometimes the most efficient solution is already there and you don't have to code anything. Also follow the suggestions of William Pursell and use the init system of your OS (systemd,upstart,system-v,etc.) to host your scripts.
Find more:
Shell Script For Process Monitoring

How to run a shell script with the terminal closed, and stop the script at any time

What I usually do is pause my script, run it in the background and then disown it like
./script
^Z
bg
disown
However, I would like to be able to cancel my script at any time. If I have a script that runs indefinitely, I would like to be able to cancel it after a few hours or a day or whenever I feel like cancelling it.
Since you are having a bit of trouble following along, let's see if we can keep it simple for you. (this presumes you can write to /tmp, change as required). Let's start your script in the background and create a PID file containing the PID of its process.
$ ./script & echo $! > /tmp/scriptPID
You can check the contents of /tmp/scriptPID
$ cat /tmp/scriptPID
######
Where ###### is the PID number of the running ./script process. You can further confirm with pidof script (which will return the same ######). You can use ps aux | grep script to view the number as well.
When you are ready to kill the ./script process, you simply pass the number (e.g. ######) to kill. You can do that directly with:
$ kill $(</tmp/scriptPID)
(or with the other methods listed in my comment)
You can add rm /tmp/scriptPID to remove the pid file after killing the process.
Look things over and let me know if you have any further questions.

linux - running a process and tailing a file simultaneously

I want a run a long task on a remote machine (with python fabric using ssh).
It logs to a file on the remote machine.
What I want to do is to run that script and tail (actively display) the log file content until the script execution ends.
The problem with
python test.py & tail -f /tmp/out
is that it does not terminate when test.py exits.
Is there a simple linux trick I can use to do this or do I have to make a sophisticated script to continuously check the termination of the first process?
I would simply start the tail in background and the python process in foreground. When the python process finishes you can kill the tail, like this:
#!/bin/bash
touch /tmp/out # Make sure that the file exists
tail -f /tmp/out &
pid=$!
python test.py
kill "$pid"

restart a php script using shell script

i am using shell script to monitor the working of a php script. My aim is that this php script should not sleep / terminated and must always be running.The code i used is -
ps aux | grep -v grep | grep -q $file || ( nohup php -f $file -print > /var/log/file.log & )
now this idea would not work for cases if the php script got terminated(process status code T). Any idea to handle that case. can such processes be killed permanently and then restarted.
How about just restarting the php interpreter when it dies?
while true ; do php -f $file -print >> /var/log/file.log ; done
Of course, someone could send the script a SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU to cause it to hang, but perhaps that person has a really good reason. You can block them all except SIGSTOP, so maybe that's alright.
Or if the script does something like call read(2) on a device or socket that will never return, this won't really ensure the 'liveness' of your script. (But then you'd use non-blocking IO to prevent this situation, so that's covered.)
Oh yes, you could also stuff it into your /etc/inittab. But I'm not giving you more than a hint about this one, because I think it is probably a bad idea.
And there are many similar tools that already exist: daemontools and Linux Heartbeat are the first two to come to mind.
If the script is exiting after it's been terminater, or if it crashes out, and needs to be restarted, a simple shell script can take care of that.
#!/bin/bash
# runScript.sh - keep a php script running
php -q -f ./cli-script.php -- $#
exec $0 $#;
The exec $0 re-runs the shell script, with the parameters it was given.
To run in the background you can nohup runScript.sh or run it via init.d scripts, upstart, runit or supervisord, among others.

Resources