Bash script issue checking command output - linux

I have a bash script that I want to check the output a Linux command
The command is: sudo supervisorctl status
The normal output looks like this:
0: tuxtunnel RUNNING pid 563, uptime 11 days, 5:04:19
1: util_pkt_logger STOPPED Oct 11 01:20 PM
2: watchdog EXITED Oct 11 12:03 PM
My first attempt of the bash script reads this output from the command and puts each line into an array, unfortunately when I go to check to see if a string is contained in this result, it seems to try and execute the check as a command. My script looks like this
echo "its stopped"
x=$(sudo supervisorctl status)
SAVEIFS=$IFS
IFS=$'\n'
x=(${x})
IFS=$SAVEIFS
for(( i=0; i<${#x[#]}; i++ ))
do
echo "$i: ${x[$i]}"
if [$x[$i]] =~"STOPPED" #check if array contains this string
then
echo "its stopped"
fi
done
exit 0
When I try to perform the check that is when things go haywire, I am new to bash scripts, so any help would be appreciated. I am trying to see if the line contains the word STOPPED

Rather than reading the entire output of supervisorctl into a single variable and then manipulating the IFS variable to break the lines up, try reading one line at a time. Also, instead of matching STOPPED anywhere on the line, only look for it in the status column.
Try this:
#!/bin/bash
while read line; do
echo ${line}
fields=( ${line} )
if [ ${fields[2]} == "STOPPED" ]; then
echo "It's stopped."
fi
done < $(sudo supervisorctl status)

You do not need to go for a while loop. You can use awk to solve this.
#!/bin/bash
sudo supervisorctl status | awk '{if ($6 == "STOPPED") print $2" is Stopped";}'

gawk utility we can use .Please refer URL
https://unix.stackexchange.com/questions/94047/shell-script-to-print-rows-if-there-is-a-value-in-column-2
cat testout
0: tuxtunnel RUNNING pid 563, uptime 11 days, 5:04:19
1: util_pkt_logger STOPPED Oct 11 01:20 PM
2: watchdog EXITED Oct 11 12:03 PM
3: TEST_log STOPPED OCT 1 11:11AM
gawk '$3=="STOPPED" {print $0}' testout
1: util_pkt_logger STOPPED Oct 11 01:20 PM
3: TEST_log STOPPED OCT 1 11:11AM

This was a brackets issue. This fixed it:
if [[ "${x[$i]}" =~ "STOPPED" ]] thanks to Gordon Davisson

Related

Need to restart apache if apache connection exceeds X amount

I'm creating a bash script in which whenever my apache exceeds a fixed amount of numbers then it restart itself on next cronjob. I've created something but it is not running properly.
#!/bin/bash
RESTART="systemctl restart httpd"
COUNT="ps aux | grep httpd | wc -l"
SERVICE="httpd"
LOGFILE="/opt/httpd/autostart-apache2.log"
if COUNT > 45
then
echo "starting apache at $(date)" >> $LOGFILE
$RESTART >> $LOGFILE
else
echo "apache is running at $(date)"
fi
The error it is throwing is
line 10: COUNT: command not found
apache is running at Sat Sep 10 23:34:30 IST 2022
Can anyone help me on how to store the value of the output of ps aux | grep httpd | wc -l as a number and compare it with another number.
RESTART="systemctl restart httpd" is a variable assignment, although it might work for your use case, you should really use a function instead. See the Complex page for more info.
COUNT="ps aux | grep httpd | wc -l" is a variable assignment as well use Command Substitution, like what you did with $(date), on a side note grep has the -c option, there is no need for wc.
COUNT > 45 You're executing the COUNT word/string but since there is nothing in your script/path/function/executable with the same name (COUNT is a variable name in your script), thus you get the error: line 10: COUNT: command not found
> is a form of redirection if not used in Arithmetic Expression., it truncates a file or create it if it does not exists. Like in your code > 45 created a file named 45. Open the file for writing is the proper term word for it according to the bash manual.
Here is how I would write it.
#!/usr/bin/env bash
service="httpd"
count="$(ps aux | grep -c "$service")"
logfile="/opt/httpd/autostart-apache2.log"
restart(){ systemctl restart "$service" ; }
if (( count > 45 )); then
echo "starting apache at $(date)" >> "$logfile"
restart >> "$logfile" 2>&1
else
echo "apache is running at $(date)"
fi
(( count > 45 )) is a form of test in bash for comparing/testing numbers. The $ can be omitted inside it.

Bash script to write all occurrences of application crash to a text file

I can't find how to structure my while loop properly to log to a text file all crashes of a given Linux application. I would like to get a prompt so I can input the application name and then a loop to watch the pid of the application. If the pid is null I wanted to log the timestamp in a text file and continue the loop. If still in null at the second iteration, don't log anything, keep monitoring until there are other crashes and other logs... and so on until the script stops with CTRL+C.
I've tried multiple variations of this script without luck. I think I need tips on how to think of a "loop structure" to achieve whatever goals...
read -p "What is the name of the application you want to monitor?" appname
pidofapp=`ps -elf | grep "$appname" | grep -v grep | awk '{print $4}'`
pidofappcheck=`ps -elf | grep "$appname" | grep -v grep | awk '{print $4}'`
while :
do
if [[ ! -z "$pidofappcheck" ]] ; then
pidwasnull=true
pidofappcheck=`ps -elf | grep "$appname" | grep -v grep | awk '{print $4}'`
if [[ "$pidofapp" == "$pidofappcheck" ]] ; then
printf "Still monitoring...\n"
sleep 5
elif [[ "$pidwasnull" == true ]] ; then
continue
fi
echo "FAILURE: Crash occurred at: "$(date)" - Crashes will be logged in the monitoring tool directory under results.txt"
date >> ./results.txt
fi
done
As it is right now, the script will echo:
What is the name of the application you want to monitor?running
Still monitoring...
FAILURE: Crash occurred at: Wed May 22 01:44:53 EDT 2019 - Crashes will be logged in the monitoring tool directory under results.txt
Still monitoring...
FAILURE: Crash occurred at: Wed May 22 01:44:58 EDT 2019 - Crashes will be logged in the monitoring tool directory under results.txt
Thanks in advance for any help.
Try something like this
#!/bin/bash
getpidofapp() {
# pid=$(ps -elf | grep "$1" | grep -v grep | awk '{print $4}' | head -1)
pid=$(pgrep "$1" | head -1)
test -n "${pid}" || { echo "Is ${appname} running?"; exit 1; }
}
read -rp "What is the name of the application you want to monitor?" appname
app_pid=$(getpidofapp "${appname}")
while : ; do
lastpid=$(getpidofapp "${appname}")
if [[ "${app_pid}" == "${lastpid}" ]] ; then
printf "Still monitoring...\n"
else
crashtxt="Crashes will be logged in the monitoring tool directory under results.txt"
echo "FAILURE: Crash occurred at: $(date) ${crashtxt}"
date >> ./results.txt
fi
sleep 5
done
So I have been able to find a solution based on what #Walter A wrote. Here is what I've used. It's working as expected so far.
#!/bin/bash
read -rp "What is the name of the application you want to monitor?" appname
app_pid=$(pidof "$appname")
#echo "First PID of "$appname" is "$app_pid""
while : ; do
lastpid=$(pidof "$appname")
if [[ "${app_pid}" == "${lastpid}" ]] ; then
printf "Still monitoring...\n"
else
crashtxt="Crashes will be logged in the monitoring tool directory under results.txt"
echo "FAILURE: Crash occurred at: $(date) ${crashtxt}"
date >> ./results.txt
app_pid="$lastpid"
fi
sleep 5
done
So this script will basically check the PID of the given app until you CTRL+C. If the PID of the app changes while the script is running. It will output the timestamps of when it occurred in a "results.txt" file and it will keep checking it until you press CTRL+C. Therefore I am going to use this to log all crash occurrences of my apps. Thanks a lot #Walter A

Error when using shutdown command in Bash

read -p 'Want to use the timer (y/n) ? ' jwb2
if [[ $jwb2 =~ ^[Yy]$ ]]; then
echo -n "Now Days "
date +"%A and hour %T"
read -p 'How many hours [24hrs] :' jwb3
echo Process the command
sudo bash -c "Shutdown -h $jwb3"
fi
and running the script now,
me#linux:$./main.sh
Want to use the timer (y/n) ? y
Now Days Thursday and hour 16:09:49
How many hours [24hrs] :18:00
Process the command
bash: Shutdown: command not found
Why am I getting this error?
Use shutdown instead Shutdown.

bash script not running as expected from cron vs. shell.

I have a script I got from this website and modified to suit my needs. Orginal post: Linux Script to check if process is running & act on the result
When running the script from cron, it always creates a new process. If I run it from shell it runs normally. Can anyone help me debug the issue ?
Script
[root#server2 ~]# cat /root/full-migrate.sh
#!/bin/bash
case "$(pidof perl | wc -w)" in
0) echo "Restarting iu-maildirtoimap: $(date)" >> /var/log/iu-maildirtoimap.txt
/usr/local/bin/iu-maildirtoimap -i currentuser.txt -D imap.gmail.com:993 -d -n7 -I&
;;
1) echo "Everything seems okay: $(date)" >> /var/log/iu-maildirtoimap.txt
;;
*) echo "Removed double iu-maildirtoimap: $(date)" >> /var/log/iu-maildirtoimap.txt
kill -9 $(pidof perl | awk '{print $1}')
;;
esac
crontab job
[root#server2 ~]# crontab -l
*/1 * * * * /bin/bash /root/full-migrate.sh
From the logfile:
Removed double iu-maildirtoimap: Tue Dec 30 02:32:37 GMT 2014
Removed double iu-maildirtoimap: Tue Dec 30 02:32:38 GMT 2014
Removed double iu-maildirtoimap: Tue Dec 30 02:32:39 GMT 2014
Everything seems okay: Tue Dec 30 02:32:39 GMT 2014
Restarting iu-maildirtoimap: Tue Dec 30 02:33:01 GMT 2014
Restarting iu-maildirtoimap: Tue Dec 30 02:34:01 GMT 2014
Restarting iu-maildirtoimap: Tue Dec 30 02:35:01 GMT 2014
The first 4 entries are me manually running "/bin/bash /root/full-migrate.sh"
The last 3 are from the crontab.
Any suggestions on how to debug this issue ?
At the time of writing:
[root#server2 ~]# $(pidof perl | wc -w)
bash: 13: command not found
[root#server2 ~]# $(pidof perl | awk '{print $1}')
bash: 26370: command not found
Your test from the command line is not valid, because you are basically executing the process id, which will give you a command not found.
From the command line you will need to test this way:
$ pidof perl | wc -l
without the $()
The issue you are most likely having is that cron cannot find pidof in the path. So you will need to figure out where pidof resides on your system:
$ which pidof
and then put that full path in your cron job and it should work.

bash script - can't get for loop working

Background Info:
I'm trying to follow the example posted here: http://www.cyberciti.biz/faq/bash-for-loop/
I would like loop 9 times using a control variable called "i".
Problem Description
My code looks like this:
for i in {0..8..1}
do
echo "i is $i"
tmpdate=$(date -d "$i days" "+%b %d")
echo $tmpdate
done
When I run this code, the debug prints show me:
"i is {0..8..1}"
instead of being a value between 0 and 8.
What I've Checked So Far:
I've tried to check my version of bash to make sure it supports this type of syntax. I'm running version 4,2,25(1)
I also tried using C like syntax where you do for (i=0;i<=8;i++) but that doesn't work either.
Any suggestions would be appreciated.
Thanks.
EDIT 1
I've also tried the following code:
for i in {0..8};
do
echo "i is $i"
tmpdate=$(date -d "$i days" "+%b %d")
echo $tmpdate
done
And...
for i in {0..8}
do
echo "i is $i"
tmpdate=$(date -d "$i days" "+%b %d")
echo $tmpdate
done
They all fail with the same results.
I also tried:
#!/bin/bash
for ((i=0;i<9;i++));
do
echo "i is $i"
tmpdate=$(date -d "$i days" "+%b %d")
echo $tmpdate
done
And that gives me the error:
test.sh: 4: test.sh: Syntax error: Bad for loop variable
FYI. I'm running on ubuntu 12
EDIT 2
Ok... so i think Weberick tipped me off to the issue...
To execute the script, I was running "sh test.sh"
when in the code I had defined it as a BASH script! My bad!
But here's the thing. Ultimately, I need it to work in both bash and sh.
so now that I'm being careful to make sure that I invoke the script the right way... I've noticed the following results:
when defined as a bash script and i execute using bash, the C-style version works!
when defined as an sh script and i execute using sh, the C-style version fails
me#devbox:~/tmp/test$ sh test.sh
test.sh: 5: test.sh: Syntax error: Bad for loop variable
when defined as an sh script and i execute using sh the NON c style version ( aka for i in {n ..x}), I get the "i is {0..8}" output.
PS. The ";" doesn't make a difference if you have the do on the next line...just FYI.
Ubuntu's default shell is dash, which doesn't recognise either of the bashisms (brace expansion, C-style for loop) you tried. Try running your script using bash explicitly:
bash myscript.sh
or by setting the shebang to #!/bin/bash. Make sure NOT to run the script with sh myscript.sh.
dash should work if you use seq:
for i in $(seq 0 1 8); do
echo "$i"
done
Just {0..8} should work in bash, the default increment is 1. If you want to use a C-style for loop in bash:
for ((i=0;i<9;i++)); do
echo "$i"
done
I'm confident that
#!/bin/bash
for ((i=0;i<9;i++))
do
echo "i is $i"
tmpdate=$(date -d "$i days" "+%b %d")
echo $tmpdate
done
work on Ubuntu 12.04
If you still have an error, can you please try running
chmod +x test.sh
then
./test.sh
And the result is
i is 0
Apr 04
i is 1
Apr 05
i is 2
Apr 06
i is 3
Apr 07
i is 4
Apr 08
i is 5
Apr 09
i is 6
Apr 10
i is 7
Apr 11
i is 8
Apr 12
I'm no expert at bash but according to tdlp you need a ; after the for statement. There are many ways to to a range. This is one of them.
#!/bin/bash
for i in `seq 1 8`; do
echo $i
done
The site you quote says
Bash v4.0+ has inbuilt support for setting up a step value using {START..END..INCREMENT} syntax:
So you can just use {0..8..1} when you have a bash version greater than 4.0, which I guess is not the case (try bash --version in your terminal). Instead of {0..8..1} you can also use {0..8}.
If you have an older version you can use instead of {START..END..INCREMENT} the command $(seq START INCREMENT END) in the for loop.

Resources