Bash script seemingly stops working after a few hours - bash

So, this script runs for a few hours, but suddenly stops doing its job. According to top it's still running, but it no longer seems to do anything.
WANSTAT=1
LTESTAT=1
tail -f /var/log/messages | grep --line-buffered mwan3 | while read -r INPUT ; do
if [[ "$INPUT" == *"notice mwan3track[]: Interface wan (eth1) is offline" ]]; then
WANSTAT=0
echo "WAN offline"
elif [[ "$INPUT" == *"notice mwan3track[]: Interface lte (3g-lte) is offline" ]]; then
LTESTAT=0
echo "LTE offline"
elif [[ "$INPUT" == *"ifup interface wan (eth1)" ]]; then
WANSTAT=1
elif [[ "$INPUT" == *"ifup interface lte (3g-lte)" ]]; then
LTESTAT=1
fi
if [ $WANSTAT -eq 0 ] && [ $LTESTAT -eq 0 ]; then
echo "All red\n"
elif [ $WANSTAT -eq 0 ]; then
echo "WAN red, LTE green\n"
elif [ $LTESTAT -eq 0 ]; then
echo "LTE red, WAN green\n"
else
echo "All green\n"
fi
done

After a few hours, the logging system closes /var/log/messages, renames it, and opens a new file with the same name. tail -f, however, continues to watch the original file, which is no longer written to.
Use tail -F instead to ensure that you continue to watch the file named /var/log/messages, regardless of which file that actually is.

Related

How to Run some script forever without causing cpu fan overspeed in Linux

I want to apply dark theme depending on if it is "AM" or "PM". So I have created a bash script with "while loop" (So that it runs forever).
But running this script causes speed up in cpu fan. (that happens when our pc struggles to do something highly computational or playing game or anything heavy).
My script is just a simple line. So how can I run this script without causing high fan speeding?
#!/bin/bash
isNightThemeApplied=0
isDayThemeApplied=0
while [[ 1 -le 1 ]]
do
if [[ `date +%r` == *"AM"* ]]
then
if [[ isNightThemeApplied -eq 0 ]]
then
echo "Applying Night Theme..."
lookandfeeltool -a 'org.kde.breezedark.desktop'
isNightThemeApplied=1
isDayThemeApplied=0
echo "Night Theme Applied Successfully"
fi
else
if [[ isDayThemeApplied -eq 0 ]]
then
echo "Applying Day Theme..."
lookandfeeltool -a 'org.kde.breeze.desktop'
isDayThemeApplied=1
isNightThemeApplied=0
echo "Day Theme Applied Successfully"
fi
fi
done
You could do something like this that uses a while loop every 30 minutes so hardly resource hungry, no need to echo anything in my opinion, just put this in your start up script and run it.
#!/usr/bin/env bash
a=$(date +%p)
b="PM"
c="AM"
theme_change () {
if [[ "$a" == "$b" ]] ; then
lookandfeeltool -a 'org.kde.breezedark.desktop'
elif [[ "$a" == "$c" ]] ; then
lookandfeeltool -a 'org.kde.breeze.desktop'
fi
}
while true; do
theme_change;
sleep 1800;
done

Why range of my variable is limited into "tail -f scope"?

I have application which register OnLine or Offline status which is stored in my test.log file. Status can be changed every second or minute or at all during many hours. Once per 15 minutes I need to send actual status to external machine [my.ip.address]. In below example let's assume that I need to just echo actual status.
I wrote below script which is watching my test.log and stores actual status in FLAG variable. However I cannot send it (or echo) to my external machine [my.ip.address] cause FLAG is not saved properly. Do you have any idea what's wrong in below example?
#!/usr/bin/env bash
FLAG="OffLine"
FLAG_tmp=$FLAG
tail -f /my/path/test.log | while read line
do
if [[ $line == *"OnLine"* ]]; then
FLAG_tmp="OnLine"
fi
if [[ $line == *"OffLine"* ]]; then
FLAG_tmp="OffLine"
fi
if [ "$FLAG" != "$FLAG_tmp" ];then
FLAG=$FLAG_tmp
echo $FLAG # it works, now FLAG stores actual true status
fi
done &
# till this line I suppose that everything went well but here (I mean out of
# tail -f scope) $FLAG stores only OffLine - even if I change it to OnLine 4 lines before.
while :
do
#(echo $FLAG > /dev/udp/[my.ip.address]/[port])
echo "$FLAG" # for debug purpose - just echo actual status.
# However it is always OffLine! WHY?
#sleep 15*60 # wait 15 minutes
sleep 2 # for debug, wait only 2 sec
done
EDIT:
Thanks guys for your answers, but I still don't get a solution.
#123: I corrected my code basing on your example, but it seems to not working.
#!/usr/bin/env bash
FLAG="OffLine"
FLAG_tmp=$FLAG
while read line
do
if [[ $line == *"OnLine"* ]]; then
FLAG_tmp="OnLine"
fi
if [[ $line == *"OffLine"* ]]; then
FLAG_tmp="OffLine"
fi
if [ "$FLAG" != "$FLAG_tmp" ];then
FLAG=$FLAG_tmp
#echo $FLAG
fi
done & < <(tail -f /c/vagrant_data/iso/rpos/log/rpos.log)
while :
do
echo "$FLAG"
sleep 2
done
#chepner: Do you have some exact proposals how can I solve this problem?
I think you are making it overly complicated. If you just want to send yourself the last state of OffLine or OnLine you might try something like this:
#!/bin/bash
while :
do
FLAG="$(egrep 'OffLine|OnLine' test.log | tail -1)"
if [ $(echo "$FLAG" | grep OffLine) ]
then
FLAG=OffLine
else
FLAG=OnLine
fi
echo $FLAG
sleep 2
done
Or, if you really want to keep the two processes,
#!/bin/bash
echo OffLine > status
tail -f test.log | while read line
do
if [[ "$line" =~ "OffLine" ]]
then
echo OffLine > status
elif [[ "$line" =~ "OnLine" ]]
then
echo OnLine > status
fi
done &
while :
do
cat status > /dev/udp/[my.ip.address]/[port])
sleep 15*60
done

Bash For Loop With If & Elif Logic Broken

I've been playing with bash scripting for 40'ish days with 0 experience so forgive me if my code looks like crap. I have a script that will take the configured NTP servers out of the /etc/ntp.conf file (/root/ntp.conf for testing)
NTPSRVCounter=1
echo "--- NTP Configuration ---"
echo " "
while read -r line; do
if [ $NTPSRVCounter == 1 ] ; then
echo "Primary NTP: $line"
SEDConfiguredNTP1="$(echo $line | sed 's/\./\\./g')"
((NTPSRVCounter++))
echo " "
else
SEDConfiguredNTP2="$(echo $line | sed 's/\./\\./g')"
echo "Secondary NTP: $line"
echo ""
fi
done < <(grep -o -P '(?<=server ).*(?= iburst)' /root/ntp.conf)
And asks you if you want to change it with a case statement:
echo "Do you wish to change it? [Y/n]"
NTPSRVCounter2=1
read opt
case $opt in
Y|y) read -p "Enter in your primary NTP server: " -e -i '0.debian.pool.ntp.org' UserInputNTP1
read -p "Enter in your secondary NTP serer: " -e -i '1.debian.pool.ntp.org' UserInputNTP2
for NTP in "$UserInputNTP1" "$UserInputNTP2" ; do
is_fqdn "$NTP"
if [[ $? == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $? == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi
done
;;
N|n) return 0
;;
*) echo "I don't know what happened, but, eh, you're not supposed to be here."
;;
esac
The problem is with the "elif" statement and the function "is_fqdn" on the second run of the function. If I put "bash -x" on the script and run it, I see "is_fqdn" returning 0 on both runs of the function, but the elif statement "$?" is coming up as 1 instead of 0.
The two functions used are below. Have to validate NTP addresses as either valid domain names or I.P. addresses, right? :)
is_fqdn() {
hostname=$1
if [[ "$hostname" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
valid_ip "$hostname"
elif [[ "$hostname" == *"."* && "$hostname" != "localhost." && "$hostname" != "localhost" ]] ; then
return 0
else
return 1
fi
host $hostname > /dev/null 2>&1 || return 1
}
valid_ip(){
local stat=1
local ip=$1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS="."
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return "$stat"
}
The condition in your if sets the value of $?, and that is what's used by the condition in the elif part, not the return value of is_fqdn. You need to save the value if you want to use it in multiple places:
is_fqdn "$NTP"
is_fqdn_rv=$?
if [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi

BASH Syntax Error - [: missing `]'

I am new to Bash programming and probably being really silly.
Basically I am writing a piece of script that will ping an IP Address I pass in, it will take from it packets transmitted and return an error or a pass message depending on the number of packets lost.
However whenever I run the script from my terminal I keep getting message -
./ipGatewayCheck.sh: line 13: [: missing]'`
This is my code:
#!/bin/bash
healthy_status=0
warning_status=10
critical_status=100
for gateway in $#
do
RESULT=`ping -q -c 10 $gateway | grep 'packets transmitted' | awk '{print $6}' | tr -d "%"`
echo "$RESULT"
if [ $RESULT -eq $healthy_status ]; then
echo "No Issue - IP Address is pinging"
elif [ $RESULT -ge $warning_status && -le $critical_status ]; then
echo "Warning - Issue with packet loss on this IP Address"
elif [ $RESULT -eq $critical_status ]; then
echo "Critical - 100% packet loss on this IP Address"
fi
done
Any help would be greatly appreciated.
You need to use [[ and ]] in order to use && inside square brackets:
if [[ "$RESULT" -eq "$healthy_status" ]]; then
echo "No Issue - IP Address is pinging"
elif [[ "$RESULT" -ge "$warning_status" && "$RESULT" -le "$critical_status" ]]; then
echo "Warning - Issue with packet loss on this IP Address"
elif [[ "$RESULT" -eq "$critical_status" ]]; then
echo "Critical - 100% packet loss on this IP Address"
fi
Alternatively you can also use (( and )) in BASH:
if (( RESULT == healthy_status )); then
echo "No Issue - IP Address is pinging"
elif (( RESULT == warning_status && RESULT < critical_status )); then
echo "Warning - Issue with packet loss on this IP Address"
elif (( RESULT == critical_status )); then
echo "Critical - 100% packet loss on this IP Address"
fi
As diagnosed by anubhava in his answer, the problem is that the && operator terminates the test command leaving you with a [ without a matching ] and the error message you get.
There's an alternative fix — more traditional shell coding and portable to shells other than Bash.
If you wish to use [, you have to use either the -a conjunction (instead of &&), or use two separate tests:
elif [ "$RESULT" -ge $warning_status -a "$RESULT" -le "$critical_status" ]; then
elif [ "$RESULT" -ge $warning_status ] && [ "$RESULT" -le "$critical_status" ]; then
Note that I had to add the second "$RESULT"; I also enclosed the variables inside double quotes to make sure there are no mishaps.

Check if output file is generated and populated with expected logs - BASH

A process (in background) should create a file (e.g. result.txt) and populate it with 5 log lines.
I need to check: 1) if the file exists and 2) checks if all the logs (5 lines) are stored
If these conditions are not satisfy within xxx seconds, the process failed and print "FAILED" in terminal, otherwise print "SUCCEED".
I think I need to use a while loop, but I don't know how to implement these conditions
N.B: the lines are appended into the file (asynchronously) and I don't have to check the compliance of logs, just to check if all are stored
This one checks the log and waits 2 seconds before failing:
#!/bin/sh
log_success() {
[[ $(tail -n "$2" "$1" 2> /dev/null | wc -l) -eq "$2" ]]
}
log_success 'file.log' 5 || sleep 2
if log_success 'file.log' 5; then
echo "success"
else
echo "fail"
fi
Well here's my draft for that:
FILE=/path/to/something
for (( ;; )); do
if [[ -e $FILE ]] && WC=$(wc -l < "$FILE") && [[ WC -ge 5 ]]; then
: # Valid.
fi
done
Or
FILE=/path/to/something
for (( ;; )); do
if [[ ! -e $FILE ]]; then
: # File doesn't exist. Do something.
elif WC=$(wc -l < "$FILE") && [[ WC -ge 5 ]]; then
: # Valid.
else
: # File doesn't contain 5 or more lines or is unreadable. Invalid.
fi
done
This one could still have problems with race conditions though.

Resources