CPU warning bash script - bash

Here is my try to make a script that will sleep:
echo "JOB RUN AT $(date)"
echo "======================================="
echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''
sensors
echo ''
echo ''
stop=0
while(true)
do
sleep 1.5
str=$(sensors | grep "Core $i:")
newstr=${str:14:2}
if [ ${newstr} -ge $1 ]
then
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
echo $(date) >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo ' WARNING: TEMPERATURE CORE' $i 'EXCEEDED' $1 '=>' $newstr >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
fi
if [ ${newstr} -ge $2 ]
then
echo '============================'
echo ''
echo 'CRITICAL: TEMPERATURE CORE' $i 'EXCEEDED' $2 '=>' $newstr
echo ''
echo '============================'
/sbin/pm-suspend
echo 'Sleeping....'
exit
else
echo ' Temperature Core '$i' OK at =>' $newstr
echo ''
fi
done
echo 'Both CPU Cores are within limits'
echo ''
When I run the script, it loops every 1.5 seconds but the newStr is not displayed. Its empty. The basic idea of the script is to make the PC 'sleep' when the temperature hits a certain level.

This worked for me:
#!/bin/bash
# PURPOSE: Script to check temperature of CPU cores and report/shutdown if specified temperatures exceeded
#
# AUTHOR: feedback[AT]HaveTheKnowHow[DOT]com
# Expects two arguments:
# 1. Warning temperature
# 2. Critical shutdown temperature
# eg. using ./CPUTempShutdown.sh 30 40
# will warn when temperature of one or more cores hit 30degrees and shutdown when either hits 40degrees.
# NOTES:
# Change the strings ">>/home/xybrek" as required
# Substitute string "myemail#myaddress.com" with your own email address in the string which starts "/usr/sbin/ssmtp myemail#myaddress.com"
# Assumes output from sensors command is as follows:
#
# coretemp-isa-0000
# Adapter: ISA adapter
# Core 0: +35.0 C (high = +78.0 C, crit = +100.0 C)
#
# coretemp-isa-0001
# Adapter: ISA adapter
# Core 1: +35.0 C (high = +78.0 C, crit = +100.0 C)
#
# if not then modify the commands str=$(sensors | grep "Core $i:") & newstr=${str:14:2} below accordingly
echo "JOB RUN AT $(date)"
echo "======================================="
echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''
sensors
echo ''
echo ''
stop=0
while true;
do
sleep 1.5
for i in 0 1
do
str=$(sensors | grep "Core $i:")
newstr=${str:17:2}
if [[ ${newstr} -ge $1 ]]
then
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
echo $(date) >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo ' WARNING: TEMPERATURE CORE' $i 'EXCEEDED' $1 '=>' $newstr >>/home/xybrek/Desktop/CPUWarning.Log
echo '' >>/home/xybrek/Desktop/CPUWarning.Log
echo '============================' >>/home/xybrek/Desktop/CPUWarning.Log
fi
if [[ ${newstr} -ge $2 ]]
then
echo '============================'
echo ''
echo 'CRITICAL: TEMPERATURE CORE' $i 'EXCEEDED' $2 '=>' $newstr
echo ''
echo '============================'
sudo pm-suspend
echo 'Sleeping....'
#exit
else
echo ' Temperature Core '$i' OK at =>' $newstr
echo ''
fi
done
done
echo 'Both CPU Cores are within limits'
echo ''

$i is undefined, as of your code shown.
If $i is empty, $str will be empty. $newstr is a substring of $str, with wrong indices btw.
So $newstr will be empty.
Console tests:
str#s131-i:~> str=$(sensors | grep "Core 0:")
str#s131-i:~> echo $str
Core 0: +33.0°C (high = +74.0°C, crit = +100.0°C)
str#s131-i:~> newstr=${str:14:2}
str#s131-i:~> echo $newstr
+3
str#s131-i:~> str=$(sensors | grep "Core :")
str#s131-i:~> echo $str
str#s131-i:~>
Edit one more comment:
This script is not very robust. If the parameters are missing it will put your system to sleep. I would rather use some scripting language for this, if you deploy to several systems use one that does this job without extra libraries or tools. The bash syntax is a bit ...well hm...

Related

**UPDATE Issues with .SH file running Correctly

I am trying to use this script to be able to shut down my ESXi server based on network connectivity. I found this script online, on the vmcommunity and no one seems to be having the same issues that I am. When I run this script It returns syntax error: unexpected word (expecting "in"). However the in is there
allInterfaces=$(esxcfg-nics -l | grep vmnic | awk '{print $1}' | awk '$1=$1' OFS=" " RS=)
while [ $# -gt 0 ];
do
case "$1" in
-v) verbose=1;;
-t) downCycles=$2; shift;;
-i) shift; break;;
--) shift; break;;
-*) errorLog "wrong parameter:" "$#" ;;
*) break;;
esac
done
shift
Any advice would be extremely helpful. Below if the full script that I am trying to use.
#!/bin/bash
verbose=0
downCycles=3
stateCounter="/tmp/auto-shutdown.counter"
log() {
logger "auto-shutdown: $1"
if [ $verbose -gt 0 ]; then
echo "$1"
fi
}
errorLog() {
logger "auto-shutdown error: $1"
echo -e >&2 "\n$1\n"
echo -e >&2 "auto-shutdown.sh: shutdown vmware ESXi if network interfaces are down for a number of cycles"
echo -e >&2 "-------------------------------------------------------------------------------------------------"
echo -e >&2 "usage: $0 [-v] [-t cycles] [-i vmnic# vmnic# ...]\n"
echo -e >&2 " -v: verbose\n"
echo -e >&2 " vmnic#: selected vmnic interfaces to monitor"
echo -e >&2 " defaults to all available interfaces\n"
echo -e >&2 " cycles: the down condition is reached, if all selected vmnic interfaces"
echo -e >&2 " have been down for <cycles> consecutive executions of this script\n"
echo -e >&2 "(c) 2011-10-22 by Ralf Lueders, support#lrconsult.com"
echo -e >&2 "-------------------------------------------------------------------------------------------------\n"
exit 1
}
if [ ! -e $stateCounter ]; then
echo 0 > $stateCounter
fi
allInterfaces=$(esxcfg-nics -l | grep vmnic | awk '{print $1}' | awk '$1=$1' OFS=" " RS=)
while [ $# -gt 0 ];
do
case "$1" in
-v) verbose=1;;
-t) downCycles=$2; shift;;
-i) shift; break;;
--) shift; break;;
-*) errorLog "wrong parameter:" "$#" ;;
*) break;;
esac
done
shift
selectedInterfaces=$*
nosi=0
for interface in $selectedInterfaces; do
if [ "$(expr "$allInterfaces" : ".*$interface.*")" -eq 0 ]; then
errorLog "$0 error: interface $interface does not exist"
fi
nosi=$( $nosi + 1 )
done
if [ ${#selectedInterfaces} -eq 0 ]; then
selectedInterfaces=$allInterfaces
fi
if [ $verbose -gt 0 ]; then
echo "monitoring interface(s) $selectedInterfaces ..."
fi
downState=1
for interface in $selectedInterfaces; do
state=$(esxcfg-nics -l | grep "$interface" | awk '{print tolower($4)}')
if [ "$state" = "up" ]; then
downState=0
fi
done
count=$(cat $stateCounter)
if [ "$count" -eq "$downCycles" ]; then
log "initiating system shutdown..."
echo 0 > $stateCounter
/sbin/shutdown.sh
/sbin/poweroff
else
if [ $downState -eq 1 ]; then
count=$( $count + 1 )
countDown=$( "$downCycles - $count" )
log "the interface(s) $selectedInterfaces have now been down for $count cycles, $countDown cycles left before system shutdown."
else
count=0
fi
fi
echo $count > $stateCounter
I have used Charles' suggestions and I am no longer getting errors in ShellCheck. However I am still getting the same error I encountered before where it say that I am missing an in that is clearly there. Anyone see anything else that could be edited to solve this issue. I am really not familiar with shell scripting at all, so any information would be helpful.

Bash script that kill process when cpu is higher than x%

I premise that i'm at the very first arms about this.
I'm trying to create a script that, when twice in a row, detects a % of cpu in use higher than 70%, it kills all the screens and python processes.
For how the script is currently, I do not get errors but I know that it does not work as it should.
Could someone help me?
#!/bin/bash
clear
a=0
b=2
now=$(date +"%T")
echo [$now] Start
while :
do ###i take this 3 line online to check the cpu usage %
cores=$(nproc)
load=$(awk '{print $3}'< /proc/loadavg)
usage=$(echo | awk -v c="${cores}" -v l="${load}" '{print l*100/c}' | awk -F. '{print $1}')
if [[ ${usage} -ge 70 ]];
then
let "a += 1"
if [[ "$a" -eq "$b" ]];
then
echo
echo ============================================
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
echo
let "a=0"
echo pkill screen ###this 2 command is what i need to do
echo pkill python ###when the cpu is higher than 70%
echo
echo "processi chiusi"
echo ============================================
sleep 15
else
echo
echo ============================================
echo
echo
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
echo
echo ============================================
sleep 15
fi
else
echo
echo
echo
echo ============================================
echo
now=$(date +"%T")
echo -e "\e[33m[$now]\e[39m" CPU usage "\e[33m[$usage]\e[39m"
let "a=0"
echo
echo "contatore: "
echo "[$a]"
echo ============================================
sleep 15
fi
done

BASH - Timed Input - Show countdown

I have a bash script that asks the user for their details.
I'm setting a limit to how long we wait for the input. I've found this and it appears to what I want.
timelimit=5
echo -e " You have $timelimit seconds\n Enter your name quickly: \c"
name=""
read -t $timelimit name
#read -t $timelimit name <&1
# for bash versions bellow 3.x
if [ ! -z "$name" ]
then
echo -e "\n Your name is $name"
else
echo -e "\n TIME OUT\n You failed to enter your name"
fi
It shows "You have 5 seconds..." any way to update the output so it shows 4,3,2,1 etc as it counts down ?
Thanks
I have tried most of these answers and none of them worked perfectly for me.
Been playing with this for a local developer deployment script.
This solves a few of the issues noted, like including printed output, etc.
Also wrapped as a function for portability. I'm keen to see any improvements.
Here is my solution:
#!/bin/bash
# set -euo pipefail
READTIMEOUT=5
function read_yn {
MESSAGE=$1
TIMEOUTREPLY=$2
NORMALREPLY="Y"
if [ -z "${TIMEOUTREPLY}" ]; then
TIMEOUTREPLY="Y"
fi
TIMEOUTREPLY_UC=$( echo $TIMEOUTREPLY | awk '{print toupper($0)}' )
TIMEOUTREPLY_LC=$( echo $TIMEOUTREPLY | awk '{print tolower($0)}' )
if [ "${TIMEOUTREPLY_UC}" == "Y" ]; then
NORMALREPLY="N"
fi
NORMALREPLY_UC=$( echo $NORMALREPLY | awk '{print toupper($0)}' )
NORMALREPLY_LC=$( echo $NORMALREPLY | awk '{print tolower($0)}' )
for (( i=$READTIMEOUT; i>=0; i--)); do
printf "\r${MESSAGE} [${NORMALREPLY_UC}${NORMALREPLY_LC}/${TIMEOUTREPLY_UC}${TIMEOUTREPLY_LC}] ('${TIMEOUTREPLY_UC}' in ${i}s) "
read -s -n 1 -t 1 waitreadyn
if [ $? -eq 0 ]
then
break
fi
done
yn=""
if [ -z $waitreadyn ]; then
echo -e "\nNo input entered: Defaulting to '${TIMEOUTREPLY_UC}'"
yn="${TIMEOUTREPLY_UC}"
else
echo -e "\n${waitreadyn}"
yn="${waitreadyn}"
fi
}
read_yn "TESTING" "y"
GIST: https://gist.github.com/djravine/7a66478c37974940e8c39764d59d35fa
LIVE DEMO: https://repl.it/#DJRavine/read-input-with-visible-countdownsh
This should work and shouldn't overwrite input, bit more long winded than the other solutions.
#!/bin/bash
abend()
{
stty sane
exit
#Resets stty and then exits script
}
DoAction(){
stty -echo
#Turn off echo
tput sc
#Save cursor position
echo -ne "\033[0K\r"
# Remove previous line
tput cuu1
#Go to previous line
tput el
#clear to end of line
echo "You have $(($time-$count)) seconds"
#Echo timer
echo -n "$Keys"
#Echo currently typed text
stty echo
#turn echo on
tput rc
#return cursor
}
main()
{
trap abend SIGINT # Trap ctrl-c to return terminal to normal
stty -icanon time 0 min 0 -echo
#turn of echo and set read time to nothing
keypress=''
time=5
echo "You have $time seconds"
while Keys=$Keys$keypress; do
sleep 0.05
read keypress && break
((clock = clock + 1 ))
if [[ clock -eq 20 ]];then
((count++))
clock=0
DoAction $Keys
fi
[[ $count -eq $time ]] && echo "you have run out of time" && abend
done
stty sane
echo Your username was $Keys
echo "Thanks for using this script."
exit 0
}
main
This seems to work:
$ cat test.sh
total=5 # total wait time in seconds
count=0 # counter
while [ ${count} -lt ${total} ] ; do
tlimit=$(( $total - $count ))
echo -e "\rYou have ${tlimit} seconds to enter your name: \c"
read -t 1 name
test ! -z "$name" && { break ; }
count=$((count+1))
done
if [ ! -z "$name" ] ; then
echo -e "\nyour name is $name"
else
echo -e "\ntime out"
fi
#!/bin/bash
timelimit=6
name=""
for (( i = 1 ; i <= $timelimit; i++ )); do
echo -ne "\rYou have $(expr $timelimit - $i) seconds. Enter your name quickly: \c"
[ ! -z "$name" ] && { break ; }
read -t 1 name
done
if [ -z "$name" ]; then
echo -e "\n TIME OUT\n You failed to enter your name"
else
echo -e "\n Your name is $name"
fi
this should work
This works fine and fast for me:
#!/bin/bash
#Sets starttimestamp
starttime=$(date +%s)
#Sets timeout
timeout=5
#sets successflag default to false
success=false
#Save Cursorposition
echo -n -e "\033[s"
#While time not up
while [ $(($starttime+$timeout)) -gt $(date +%s) ] ; do
#Return to saved Cursorpositon
echo -n -e "\033[u"
#Display time left
echo "$(((starttime+timeout)-$(date +%s))) seconds left"
#Ask for 1 char then go on in loop make it look like an ongoing input by adding the user variable to the prompt
if read -p foo="Username: $user" -n 1 -t 1 c ; then
#If user hits return in time c will be empty then break out of loop and set success true
if [[ $c == "" ]] ; then
success=true
break
fi
# Append latest character to user variable
user=${user}${c}
unset c
fi
done
if $success ; then
echo "Yiha!"
else
echo "Too late!"
fi

Setting Receive Packet Steering (RPS) for 32 cores

I am not sure that I used the correct commands for setting the RPS for a 32 cores machine. This is what I used: echo 1f > /sys/class/net/eth0/queues/rx-0/rps_cpus
Should it be "echo 1f..." or "echo f..." or anything else?
Pinterest engineers just say:
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
But there are another their talk:
echo ffff > /sys/class/net/eth0/queues/rx-0/rps_cpus
Can't see the actual difference from kernel point of view but you can try both
Reproducing from the Performance Tuning Guide for Red Hat Enterprise Linux 7:
The rps_cpus files use comma-delimited CPU bitmaps. Therefore, to
allow a CPU to handle interrupts for the receive queue on an
interface, set the value of their positions in the bitmap to 1. For
example, to handle interrupts with CPUs 0, 1, 2, and 3, set the value
of rps_cpus to 00001111 (1+2+4+8), or f (the hexadecimal value for
15).
So for quad-core cpus...
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
and for cpus with >4 cores...
echo ff+ > /sys/class/net/eth0/queues/rx-0/rps_cpus
where ff+ is a regex for appending extra f(s) for each set of additional 4 cores
You might want to try using binary calculator and nproc:
echo "obase=16;2^$(nproc)-1" | bc > /sys/class/net/eth0/queues/rx-0/rps_cpus
That formula will configure RPS for any number of cores.
I have seen also <flags>,<flags>,<flags> notation. My machine refuses to accept that.
Other than this I also see that after reboot the values got reset to 0. I bypass it by defining enabling and starting the service that corrects the value to ff (that is what I wanted it to be).
I used this
# Input
NIC_NAME="em1";
if [[ "$1" != "" ]]; then
NIC_NAME="$1";
fi
# Tuna Install
#echo "`date '+%Y-%m-%d %H:%M:%S'` - Install numactl" ;
#yum install -y tuna ;
# Tuna Config
echo "`date '+%Y-%m-%d %H:%M:%S'` - Tuna Info: " ;
tuna --irqs=${NIC_NAME}-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-txrx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-tx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-rx-\* --cpus=0-3 --move --spread ;
tuna --irqs=${NIC_NAME}-\* --show_irqs ;
# Install
#echo "`date '+%Y-%m-%d %H:%M:%S'` - Install numactl" ;
#yum install -y numactl ;
#echo "";
# Numa Info
echo "`date '+%Y-%m-%d %H:%M:%S'` - Numa Info: " ;
numactl --hardware | grep "^node . cpus" ;
echo "";
# Numa Mask
echo "`date '+%Y-%m-%d %H:%M:%S'` - Numa Mask: " ;
NUMA_COUNT=$(numactl --hardware | grep "^node . cpus\:" | wc -l);
NUMA_MASK=("");
i=0;
while [ $i -lt ${NUMA_COUNT} ]; do
NUMA_MASK[$i]=$(numactl --hardware | grep "^node $i cpus\:" | awk -F':' '{ print $2}' | sed 's/ /\+2\^/g' | awk '{print "obase=16;0" $0}' | bc | rev | sed -e 's/\([0-F][0-F][0-F][0-F][0-F][0-F][0-F][0-F]\)/\1,/g' | rev);
echo " NUMA_MASK[$i]: ${NUMA_MASK[$i]}";
let i++;
done
echo "";
# Set RPS/XPS
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set RPS/XPS: " ;
QUEUE_RX_COUNT=0;
QUEUE_TX_COUNT=0;
i=0;
while [ $i -lt 16 ]; do
let NUMA_ID=(i % NUMA_COUNT);
QUEUE_RX_RPS="/sys/class/net/${NIC_NAME}/queues/rx-$i/rps_cpus";
QUEUE_TX_XPS="/sys/class/net/${NIC_NAME}/queues/tx-$i/xps_cpus";
if [[ -e "${QUEUE_RX_RPS}" && "${NUMA_MASK[$NUMA_ID]}" != "" ]]; then
echo ${NUMA_MASK[$NUMA_ID]} > "${QUEUE_RX_RPS}" ;
NUMA_MASK_ID=$(cat "${QUEUE_RX_RPS}");
echo " ${QUEUE_RX_RPS}: $NUMA_MASK_ID" ;
let QUEUE_RX_COUNT++;
fi;
if [[ -e "${QUEUE_TX_XPS}" && "${NUMA_MASK[$NUMA_ID]}" != "" ]]; then
echo ${NUMA_MASK[$NUMA_ID]} > "${QUEUE_TX_XPS}" ;
NUMA_MASK_ID=$(cat "${QUEUE_TX_XPS}");
echo " ${QUEUE_TX_XPS}: $NUMA_MASK_ID" ;
let QUEUE_TX_COUNT++;
fi;
let i++;
done
echo "";
# Set Sock Rps Flow
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set Sock Rps Flow: " ;
SOCK_RX_FLOW_ENTRIES="/proc/sys/net/core/rps_sock_flow_entries" ;
SOCK_RX_FLOW_COUNT=32768 ;
echo "${SOCK_RX_FLOW_COUNT}" > ${SOCK_RX_FLOW_ENTRIES} ;
SOCK_RX_FLOW_COUNT=$(cat ${SOCK_RX_FLOW_ENTRIES}) ;
echo " ${SOCK_RX_FLOW_ENTRIES}: ${SOCK_RX_FLOW_COUNT}" ;
echo "";
# Set Queue Rps Flow
echo "`date '+%Y-%m-%d %H:%M:%S'` - Set Queue Rps Flow: " ;
let SET_QUEUE_RX_FLOW_COUNT=(SOCK_RX_FLOW_COUNT / QUEUE_RX_COUNT);
i=0;
while [ $i -lt 16 ]; do
QUEUE_RX_FLOW="/sys/class/net/${NIC_NAME}/queues/rx-$i/rps_flow_cnt";
if [[ -e "${QUEUE_RX_FLOW}" && ${SET_QUEUE_RX_FLOW_COUNT} -gt 0 ]]; then
echo ${SET_QUEUE_RX_FLOW_COUNT} > "${QUEUE_RX_FLOW}" ;
GET_QUEUE_RX_FLOW_COUNT=$(cat "${QUEUE_RX_FLOW}");
echo " ${QUEUE_RX_FLOW}: ${GET_QUEUE_RX_FLOW_COUNT}" ;
fi;
let i++;
done
echo "";

Shell-Removing File Extensions through Args

I wish to remove the file extensions in a folder by getting the extension type as argument.
Below is my code and it is not working as i expected.
if [ $# -ne 1 ]
then
echo -e "\nUsage: $0 Ext"
echo -e "\nExt - Refers to the extension you want to remove"
echo -e "\nExample1: $0 .txt\nExample2: $0 .doc\nExample3: $0 .pdf\n"
exit 1
fi
ext=$1
for i in *$ext
do
echo $i
filename=${i%\$ext}
echo $i
done
Your code is almost correct, but you need to remove the escape and echo the filename. Code below also shows the use of basename:
for i in *$ext
do
echo $i
filename1=${i%$ext}
filename2=$(basename $i $ext)
echo $filename1
echo $filename2
done
You can replace extension using this script
#!/bin/bash
if [ $# -ne 1 ]
then
echo -e "\nUsage: $0 Ext"
echo -e "\nExt - Refers to the extension you want to remove"
echo -e "\nExample1: $0 .txt\nExample2: $0 .doc\nExample3: $0 .pdf\n"
exit 1
fi
ext=$1
for i in *$ext
do
echo $i
new_name=`echo $i | sed 's/.'$ext'//g'`
echo $new_name
done
You can use the below code :
#!/bin/bash
if [ $# -ne 1 ]
then
echo -e "\nUsage: $0 Ext"
echo -e "\nExt - Refers to the extension you want to remove"
echo -e "\nExample1: $0 .txt\nExample2: $0 .doc\nExample3: $0 .pdf\n"
exit 1
fi
ext=$1
for i in *$ext
do
echo $i
new_name=`echo $i |rev|cut -d'.' -f2-|rev
echo $new_name
done

Resources