Does this bash script using grep look correct? - bash

I am having some strange rebooting issues and I think it is due to an error in my shell script.
#!/bin/bash
if ps -a | grep -q gridcoin
then
echo nothing
else
sudo reboot -h now
fi
The script is supposed to work like this:
Run the ps -a command so that all processes are listed. Pipe the results to grep and have grep check to see if any of the processes have the word "gridcoin" in them. If gridcoin is running, do nothing. If gridcoin is not one of the running processes, reboot the system.
I have a cron job that runs this script once every five minutes; however, my system keeps rebooting about every five minutes even when I know for a fact that gridcoin is running.
Please take a look at the code and see if it looks right before I start trying to herd other code cats.
Respectfully,
chadrick

I see at least two problems here. First, ps -a will not show processes that don't have a controlling terminal (so, basically, non-interactive processes); you want ps -ax to show all processes.
Second, depending on the timing, the grep -q gridcoin command may be listed as a running process, and of course it finds itself, meaning that it mistakes itself for the gridcoin process. If you have the pgrep program available, replace both ps and grep with it, since it automatically avoids listing itself. Unfortunately, it doesn't have a -q option like grep, so you have to redirect its output to /dev/null:
if pgrep gridcoin >/dev/null
If pgrep is not available, there are two standardish idioms to prevent grep from finding itself:
if ps -ax | grep -q '[g]ridcoin' # Adding brackets prevents it from matching itself
if ps -ax | grep gridcoin | grep -vq grep # Remove grep processes from consideration
Also, as David C. Rankin pointed out, rebooting the entire system to restart one process is overkill; just restart that one process.

Related

Shell script returning non zero value after killing process

I am trying to kill a process using a shell script.Looks shell itself is getting killed in this process. Also I am seeing non zero return value of the script in terminal.
I am running it on Amazon Linux 2 with sudo.
#!/bin/bash
kill -9 $(ps -ef | grep myapp | grep -v grep | awk '{print $2}')
I am executing like:
sudo ./myscript.sh
"echo $?" after executing is returning 137 instead of zero. Can someone please help to understand what is going wrong.
Another observation:
if i directly run kill command in my terminal, i.e below command,
kill -9 $(ps -ef | grep myapp | grep -v grep | awk '{print $2}')
I see echo $? is returning zero.
Update:
Problem is solved. Name of process I am trying to kill is overlapping with name of my script. Hence grep is returning both the pid's. Both the process are getting killed. Also learnt that better way of doing this by using pkill or using pidof() to get pid.
If you want the exit code of your last-run command to be the exit code for the script, your script must end with exit $? as the last line. Any function before that must also end with the $? so the chain flows to that final line. Otherwise some other exit is taking place.
If the script is being killed along side the application or script you are trying to kill, then your ps and grep work is likely including both in the results. Look at the output of the ps and grep while the script is running. You could add a line prior to your kill line which just shows the output of the ps and greps so you can see what is actually getting killed.
Finally (and I don't think this is the case) if you are trying to end the script after the kill, manually run an exit (again likely using exit $? for the reason stated above) where appropriate within the script.
Hope that helps you get where you are going.

Cron job won't start again after I stopped it?

I wrote a script to run constantly on startup. If for whatever reason the script were to fail, I wrote a second script to check if it has failed, and if so, run the first script again. I then set this second script as a cronjob to run every minute so that it is constantly checking if the first script is alive.
So to test this, I reboot my system. I can see in htop that the first script is running from start up as expected. Good. I kill the process to test the second script. Sure enough, the second script starts the first script again. Still good. I then kill this process, but the second script won't run again now. It still updates a txt file when I manually start the first script, but the second script just doesn't start the first script like it's supposed to. Is it because I killed the cronjob? Restarting the cron service doesn't fix anything though, so I don't know why my second script isn't running again at all.
First script:
#!/bin/bash
stamp=$(date +%Y%m%d-%H%M)
timeout 10d tcpdump -i eth0 -s 96 -z gzip -C 10 -w /home/user/Documents/${stamp}
Second script:
#!/bin/bash
echo "not running" > /home/working.txt
if (( $(ps -ef | grep -v grep | grep tcpdump.sh | wc -l) > 0 ))
then
echo "tcpdump is running!!!" > /home/working.txt
else
/usr/local/bin/tcpdump.sh start
fi
Any help?
You would probably be better off running a simple for loop as the main script, and that kicks off the tcpdump script in the background, so something like:
#!/bin/bash
while true; do
if ps -ef | grep -v grep | grep -q tcpdump; then
: tcpdump running OK
else
# tcpdump not running - start it off
nohup /usr/local/bin/firstscript.sh start &
fi
sleep 30
done
This checks that "tcpdump.sh" is in the output of the "ps -ef" command - if it is, then do nothing (note that you must have an actual command between the "then" and "else" - the ":" command, which just takes it s arguments and ignores them, is sufficient). If it isn't running, start the first script in the background. Then sleep 30 seconds and check again. (Yes, I could have inverted the test so that I didn't need an empty "then" arm, but it would have made the code less obvious)
You put this script as the one which starts at boot time.
Edit: Do you really want to check for "tcpdump.sh"? Is that what the first script is actually called? Assuming that you actually want to check for the tcpdump program, you could use:
if pgrep tcpdump; then

xargs and kill not working together to kill specific processes

I have a Docker container running Red Hat 6.8 and I have several Java processes running. On other machines with the same OS, I have used a command similar to the following to find and kill all Java processes:
ps -ef | grep 'java' | grep -v 'grep' | awk '{print $2}' | xargs kill -9
However, on this machine, it gives me the following error:
xargs: kill: No such file or directory
Taking off the "| xargs kill -9" does work and shows me the PIDs of the processes I want to kill but for some reason, the command will not work all together.
Does anyone have any ideas why?
The immediate problem is that xargs can't find the kill command. It needs to be in your PATH, probably in /bin and/or /usr/bin. You wouldn't notice it was missing when you run the kill command directly from the shell, because most shells have a kill builtin.
Also, I agree with the comments by other users about the overall idea. There are less hacky ways to do this (killall, pkill, anything that doesn't involve grep that's relying on luck to avoid matching the wrong part of the `ps output...)
That's the top result in Google about this specific issue, if not the only one, so I just wanted to note it here after two years: kill is bundled in util-linux package (in RHEL) or procps package (in Debian) along with bunch of other utilities. Installing that package in the container solves the issue.

bash: test if a process is running with a certain option

I would to know if it's possible to detect if amarok is playing music or not, in bash.
I have tested
#! /bin/bash
if [ "$(pidof amarok --play)" ]
then
echo amarok is playing music!
else
echo amarok is not playing!
fi
But I have this error:
pidof: invalid options on command line!
pidof thinks that --play is its option, and that is of course an error.
It would be better to check if --play is inside the commandline that was used to start amarok:
grep -- --play /proc/$(pidof amarok)/cmdline
Another option is to grep output of ps aux:
ps aux | grep [a]marok.*--play
In the both cases we suppose that there only one amarok running in the system.
Update 1.
To check if any music is playing at the moment,
you can so:
grep RUNNING /proc/asound/card*/pcm*/sub*/status

Using grep with ps -ax to kill numerous applications at once (Mac)

I'm very new to shell scripting. I recently covered a tutorial of using bash with grep.
About 5 minutes ago there was, as it happened, a practical application for this function as my browser appeared to have crashed. I wanted to, for practice, use the shell to find the process and then kill it.
I typed ps -ax | grep Chrome
But many lines appeared with lots of numbers on the left (are these "job numbers" or "process numbers"?)
Is there a way to Kill all "jobs" where Chrome exists in the name of the process? Rather than kill each one individually?
I do not recommend using killall.
And you should NOT use -9 at first.
I recommend a simple pkill:
pkill Chrome
You can use killall:
killall Chrome
Edit: Removed "-9" since it should be used as a last resource (was: killall -9 Chrome).
I like my solution better. Because adds a kind of wildcard to it. I did this:
mkdir ~/.bin
echo "ps -ef | grep -i $1 | grep -v grep | awk '{print $2}' | xargs kill -9" > ~/.bin/k
echo "alias k='/Users/YOUR_USER_HERE/.bin/k $1'" >> ~/.profile
chmod +x ~/.bin/k
Now to kill stuff you type:
k Chrome
or
k chrome
or
k chr
Just be careful with system processes or not to be killed processes.
Like if you have Calculator running and another one called Tabulator also running. If you type
k ulator it will kill'em both.
Also remember that this will kill ALL instances of the program(s) that match the variable after the command k.
Because of this, you can create two aliases inside your profile file and make 2 files inside .bin one with the command grep -i and the other without it. The one without the -i flag will be case and name sensitive.

Resources