Bash script (OS X) check running process, quit if running, BUT start if not (On/Off) - macos

I looking to have a script, inside a .app (using Platypus or something) that can check a running process with something like pgrep and handle the output by running the process if it isn't already running but killing it if it is (pkill or something).
The kill would need to stop the process that the script started first time round plus the app that it ran from in the first place.
I know this isn't right but something like this:
#!/bin/bash
if pgrep 'process' &> /dev/null;
then 'command';
else pkill "command,app" || true;
fi

Related

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.

How can I return from a shell script and then reboot (to use with VirtualBox)?

I am using guestcontrol with Virtual Box with a Windows host and a Linux (RHEL7) guest. I want to do some config from the host to the guest by running a shell script on the guest (from a .bat on the host). This is fine and the script runs, however, it hangs when I call the reboot (I believe it is because nothing is returned). So when the following .sh is called:
#!/bin/bash
echo "here"
exit
The .bat file shows "here" and then exits (or if I use pause gives the correct message). However, when I add the reboot, the .bat never processes anything past where it calls the script. I think this would be because the guest never tells the host that the script is complete.
I have tried things like:
#!/bin/bash
{ sleep 1; reboot; } >/dev/null &
exit
or even:
#!/bin/bash
do_reboot(){
sleep 1
reboot
}
do_reboot() &
exit
but the .bat never gets past the line where it runs the .sh
How can I tell the host that the .sh script (on the guest) is complete so it can continue with the .bat script?
We need to make sure there are no sub processes running, so we want to do a no heads up using the nohup command. So the script simply becomes this:
#!/bin/bash
nohup reboot &> /tmp/nohup.out </dev/null &
exit
The stdin and stdout were causing the issues, so this just sends them into the void so that the script will not be waiting for any input from any other processes.
If you have any issues with this script, you could do something like:
#!/bin/bash
nohup /path/to/reboot_delay.sh &> /tmp/nohup.out </dev/null &
exit
And then in /path/to/reboot_delay.sh you would have:
#!/bin/bash
sleep 10 # or however many seconds you need to wait for something to happen
reboot
This way you could even allow some time for something to finish etc, yet the host machine (or ssh or wherever you are calling this from) would still know the script had finished and do what it needs to do.
I hope this can help people in future.

How can I tell if a script was run in the background and with nohup?

Ive got a script that takes a quite a long time to run, as it has to handle many thousands of files. I want to make this script as fool proof as possible. To this end, I want to check if the user ran the script using nohup and '&'. E.x.
me#myHost:/home/me/bin $ nohup doAlotOfStuff.sh &. I want to make 100% sure the script was run with nohup and '&', because its a very painful recovery process if the script dies in the middle for whatever reason.
How can I check those two key paramaters inside the script itself? and if they are missing, how can I stop the script before it gets any farther, and complain to the user that they ran the script wrong? Better yet, is there way I can force the script to run in nohup &?
Edit: the server enviornment is AIX 7.1
The ps utility can get the process state. The process state code will contain the character + when running in foreground. Absence of + means code is running in background.
However, it will be hard to tell whether the background script was invoked using nohup. It's also almost impossible to rely on the presence of nohup.out as output can be redirected by user elsewhere at will.
There are 2 ways to accomplish what you want to do. Either bail out and warn the user or automatically restart the script in background.
#!/bin/bash
local mypid=$$
if [[ $(ps -o stat= -p $mypid) =~ "+" ]]; then
echo Running in foreground.
exec nohup $0 "$#" &
exit
fi
# the rest of the script
...
In this code, if the process has a state code +, it will print a warning then restart the process in background. If the process was started in the background, it will just proceed to the rest of the code.
If you prefer to bailout and just warn the user, you can remove the exec line. Note that the exit is not needed after exec. I left it there just in case you choose to remove the exec line.
One good way to find if a script is logging to nohup, is to first check that the nohup.out exists, and then to echo to it and ensure that you can read it there. For example:
echo "complextag"
if ( $(cat nohup.out | grep "complextag" ) != "complextag" );then
# various commands complaining to the user, then exiting
fi
This works because if the script's stdout is going to nohup.out, where they should be going (or whatever out file you specified), then when you echo that phrase, it should be appended to the file nohup.out. If it doesn't appear there, then the script was nut run using nohup and you can scold them, perhaps by using a wall command on a temporary broadcast file. (if you want me to elaborate on that I can).
As for being run in the background, if it's not running you should know by checking nohup.

Stop script when gnome session ends

In Start Script when Gnome Starts Up it was asked how to automatically start a script on gnome login. But how to automatically stop a long running script on logout, that was started on login? In my case there are two processes when I login twice. Interestingly the process started first does not reside under gnome-session anymore.
I would wrap the binary that gets executed in a simple bash script that saves the pid of the started process in a temporary file. If this file already exists it skips the start of the application. Since the file is saved in the /tmp directory everything gets deleted once you restart your computer.
#!/bin/bash
binary="git-cola"
temp_file="/tmp/my_${binary}_instance.pid"
if [[ -f ${temp_file} ]]
then
echo "PID exists"
else
exec ${binary} &
echo $! > ${temp_file}
fi
With a little more effort you can check if the pid of the process is still running and restart it on the login again (for example if the process crashed or the other user closed it).
I actually don't use Gnome, so I can't tell you if there is a more elegant way to kill the process. Like a logout hook. But once you got the pid of the process saved you can kill it with kill -9 PID. (See man kill for more gentle ways to end the process).
This might not be the solution to stop the process. But to prevent it starting twice.

How do I write a watchdog daemon in bash?

I want a way to write a daemon in a shell script, which runs another application in a loop, restarting it if it dies.
When run using ./myscript.sh from an SSH session, it shall launch a new instance of the daemon, except if the daemon is already running.
When the SSH session ends, the daemon shall persist.
There shall be a parameter (./myscript -stop) that kills any existing daemon.
(Notes on edit - The original question specified that nohup and similar tools may not be used. This artificial requirement was an "XY question", and the accepted answer in fact uses all the tools the OP claimed were not possible to use.)
Based on clarifications in comments, what you actually want is a daemon process that keeps a child running, relaunching it whenever it exits. You want a way to type "./myscript.sh" in an ssh session and have the daemon started.
#!/usr/bin/env bash
PIDFILE=~/.mydaemon.pid
if [ x"$1" = x-daemon ]; then
if test -f "$PIDFILE"; then exit; fi
echo $$ > "$PIDFILE"
trap "rm '$PIDFILE'" EXIT SIGTERM
while true; do
#launch your app here
/usr/bin/server-or-whatever &
wait # needed for trap to work
done
elif [ x"$1" = x-stop ]; then
kill `cat "$PIDFILE"`
else
nohup "$0" -daemon
fi
Run the script: it will launch the daemon process for you with nohup. The daemon process is a loop that watches for the child to exit, and relaunches it when it does.
To control the daemon, there's a -stop argument the script can take that will kill the daemon. Look at examples in your system's init scripts for more complete examples with better error checking.
The pid of the most recently "backgrounded" process is stored in $!
$ cat &
[1] 7057
$ echo $!
7057
I am unaware of a fork command in bash. Are you sure bash is the right tool for this job?

Resources