Shellscript to monitor a log file if keyword triggers then run the snmptrap command - linux

Is there a way to monitor a log file using shell script like
tail -f /var/log/errorlog.txt then if something like down keyword appears, then generate SNMPTRAP to snmp manager and continues the monitoring
I have a SNMP script available to generate SNMPTrap and it looks like
snmptrap -v v2c -c community host "Error message"
Lets the say the script name is snmp.sh
My question is how to perform the below operation
tail the logs
if keyword[down] matches then use snmp.sh script to send alert
else leave
As per the suggestion i tried this
tail -F /data/log/test.log |
egrep -io 'got signal 15 | now exiting' |
while read -r line ;
do
case "$line" in
"got signal 15")
echo "hi"
;;
"now exiting")
echo "hi2"
;;
*)
esac
done
but the problem is tail is not working here with case statement, whenever the new log details added its not going to the case statement and echos the output
I could get the output if i use cat/less/more
Could you someone please tell what mistake i have done here ?
Thanks in advance

It sounds like the pattern you want is this:
tail -f /var/log/errorlog.txt | grep -e down -e unmounted | while read -r line
do
case "$line" in
down)
./snmp.sh …
;;
unmounted)
./snmp.sh …
;;
*)
echo "Unhandled keyword ${line}" >&2
exit 1
esac
done

try
tail -f /var/log/errorlog.txt | grep "down" | while read line; do snmp.sh; done

Related

getting first column of a matching line in bash

I am getting an output from a shell command, and want to incorporate the first column of a matching line into a second command. Here is what I have, and it works:
kubectl get pods -n system | while read string; do
if [[ "$string" == my-pod-* && "$string" == *Running* ]]; then
# echo $string
read -ra ADDR <<< "$string"
echo
echo "--- Reading logs for ${ADDR[0]} ---"
# desired output: kubectl -n system logs my-pod-123 --tail=5 -f
kubectl -n system logs ${ADDR[0]} --tail=5 -f
fi
done
the output from first command would look something like this:
name status namespace running
my-pod-123 Running system 4h31m #<<I want this one
another-pod-5 Running system 5h15m
my-pod-023 Terminating system 8h05m
given that the output will contain only one match, is there a shorter way to do this without looping like this? Thanks in advance for helping me improve my Bash skills as this seems very clumsy.
You may use awk like this:
name=$(kubectl get pods -n system | awk '/^my-pod.*Running/{print $1}')
[[ -n $name ]] && kubectl -n system logs "$name" --tail=5 -f
awk command will match pattern my-pod.*Running at the start of a line and if it is found then it will print first column. We store that in variable name.
If $name is not empty then we call kubectl -n system logs using that value.
How about grep?
wanted=$(kubectl get pods -n system | grep 'my-pod-.*Running')
Can do error checking at the same time:
if ! wanted=$(kubectl get pods -n system | grep 'my-pod-.*Running'); then
echo "Error: no running my-pods" >&2
fi

nohup script stopped after some time

I have a monitoring script running on my server which looks like
#!/bin/sh
tail -F /data/logs.txt | grep -E --line-buffered -io 'keyword1|keyword2' | while read -r line ; do
case "$line" in
"keyword1")
echo "hi"
;;
"keyword2")
echo "hi1"
;;
*)
esac
done
i have used -F in tail because if the new log file created it should follow the new file
I have ran that script in nohup to run indefinetly like below
nohup ./script.sh &
But the script getting stopped after a period of time
can someone help why it's happening ?
Thanks,

Unable to array values outside of function in shell script [duplicate]

Please explain to me why the very last echo statement is blank? I expect that XCODE is incremented in the while loop to a value of 1:
#!/bin/bash
OUTPUT="name1 ip ip status" # normally output of another command with multi line output
if [ -z "$OUTPUT" ]
then
echo "Status WARN: No messages from SMcli"
exit $STATE_WARNING
else
echo "$OUTPUT"|while read NAME IP1 IP2 STATUS
do
if [ "$STATUS" != "Optimal" ]
then
echo "CRIT: $NAME - $STATUS"
echo $((++XCODE))
else
echo "OK: $NAME - $STATUS"
fi
done
fi
echo $XCODE
I've tried using the following statement instead of the ++XCODE method
XCODE=`expr $XCODE + 1`
and it too won't print outside of the while statement. I think I'm missing something about variable scope here, but the ol' man page isn't showing it to me.
Because you're piping into the while loop, a sub-shell is created to run the while loop.
Now this child process has its own copy of the environment and can't pass any
variables back to its parent (as in any unix process).
Therefore you'll need to restructure so that you're not piping into the loop.
Alternatively you could run in a function, for example, and echo the value you
want returned from the sub-process.
http://tldp.org/LDP/abs/html/subshells.html#SUBSHELL
The problem is that processes put together with a pipe are executed in subshells (and therefore have their own environment). Whatever happens within the while does not affect anything outside of the pipe.
Your specific example can be solved by rewriting the pipe to
while ... do ... done <<< "$OUTPUT"
or perhaps
while ... do ... done < <(echo "$OUTPUT")
This should work as well (because echo and while are in same subshell):
#!/bin/bash
cat /tmp/randomFile | (while read line
do
LINE="$LINE $line"
done && echo $LINE )
One more option:
#!/bin/bash
cat /some/file | while read line
do
var="abc"
echo $var | xsel -i -p # redirect stdin to the X primary selection
done
var=$(xsel -o -p) # redirect back to stdout
echo $var
EDIT:
Here, xsel is a requirement (install it).
Alternatively, you can use xclip:
xclip -i -selection clipboard
instead of
xsel -i -p
I got around this when I was making my own little du:
ls -l | sed '/total/d ; s/ */\t/g' | cut -f 5 |
( SUM=0; while read SIZE; do SUM=$(($SUM+$SIZE)); done; echo "$(($SUM/1024/1024/1024))GB" )
The point is that I make a subshell with ( ) containing my SUM variable and the while, but I pipe into the whole ( ) instead of into the while itself, which avoids the gotcha.
#!/bin/bash
OUTPUT="name1 ip ip status"
+export XCODE=0;
if [ -z "$OUTPUT" ]
----
echo "CRIT: $NAME - $STATUS"
- echo $((++XCODE))
+ export XCODE=$(( $XCODE + 1 ))
else
echo $XCODE
see if those changes help
Another option is to output the results into a file from the subshell and then read it in the parent shell. something like
#!/bin/bash
EXPORTFILE=/tmp/exportfile${RANDOM}
cat /tmp/randomFile | while read line
do
LINE="$LINE $line"
echo $LINE > $EXPORTFILE
done
LINE=$(cat $EXPORTFILE)

Bash Script output is always 'ps' when piping to grep from ps regardless of PID results

given an array of pids and the code:
for i in ${listedPids[#]}
do
runningCheck="ps -u $USER | grep $i"
grepRes=(${runningCheck})
if [[ -n $grepRes ]]
then
echo $grepRes
echo $runningCheck
... code not related to the issue
fi
done
Regardless if those pids are active or not; I keep getting 'ps' from echo $grepRes while the output of echo $runningCheck shows up with the correct user name and pid. What am I missing?
Replace
"ps -u $USER | grep $i"
by
$(ps -u $USER | grep $i)
Command Substitution: Bash performs the expansion by executing your command and replacing the command substitution with the standard output of the
command, with any trailing newlines deleted.
I simplified your script and here's what it should look like.
for i in "${listedPids[#]}"
do
grepRes=$(ps --no-heading -p $i)
if [[ -n "$grepRes" ]]
then
echo "$grepRes"
... code not related to the issue
fi
done
An even shorter code could be written using while loop.
ps --noheading -p "${listedPids[#]}" | while read grepRes
do
echo "$grepRes"
... code not related to the issue
done
As alvits and l0b0 pointed out, I made a few syntax errors: grepRes=(${runningCheck}) when I just wanted to execute that line and not turn it to a list, and the fact pipes and redirects don't work in variables. In the end pgrep did the job as I just needed to continue looping till all the background processes ended.
Maybe you could try eval.
runningCheck1="ps -u $USER"
runningCheck2=" | grep $i"
echo $runningCheck1$runningCheck
eval $runningCheck1$runningCheck2

bash: loop through procces output and terminate the process

I need some help with the following:
I use linux to script commands sent to a device. I need to submit a grep logcat command to the device and then iterate its output as it is being generated and look for a particular string. Once this string is found I want my script to move to the following command.
in pseudocode
for line in "adb shell logcat | grep TestProccess"
do
if "TestProccess test service stopped" in line:
print line
print "TestService finished \n"
break
else:
print line
done
adb shell logcat | grep TestProcess | while read line
do
echo "$line"
if [ "$line" = "TestProces test service stopped" ]
then echo "TestService finished"
break
fi
done
adb shell logcat | grep -Fqm 1 "TestProcess test service stopped" && echo "Test Service finished"
The grep flags:
-F - treat the string literally, not as a regular expression
-q - don't print anything to standard output
-m 1 - stop after the first match
The command after && only executes if grep finds a match. As long as you "know" grep will eventually match and want to unconditionally continue once it returns, just leave off the && ...
You could use an until loop.
adb shell logcat | grep TestProccess | until read line && [[ "$line" =~ "TestProccess test service stopped" ]]; do
echo $line;
done && echo -n "$line\nTestService finished"

Resources