Looping script, redirect to file - linux

So I have this BASH script and what i want to do is, reach out to the servers. Check the used % of a directory. If it is higher than my set threshold (90) then print that server name to another file on the server where the script has been run from.
What it is doing is printing the first server name twice in to the file so it looks like
server1
server2
Here is my script ... I don't see why it would be going around in a loop to that first server twice
#!/bin/bash
SERVERS="server1
server2"
for i in $SERVERS; do
ssh $SERVERS "
df -h | grep var | awk '{print \$4}' | sed 's/%//g' > /home/user/space.txt
RESULTS=\$(grep -E "1[5-9]" /home/user/space.txt)
THRESHOLD=90
if [[ \$RESULTS -lt \$THRESHOLD ]]; then
exit 1;
elif [[ \$RESULTS -gt \$THRESHOLD ]]; then
hostname;
fi
" >> /home/user/problem.txt
done

Try this,
#!/bin/bash
SERVERS="server1
server2"
for i in $SERVERS; do
ssh "$i" "
df -h | grep var | awk '{print \$4}' | sed 's/%//g' > /home/user/space.txt
RESULTS=\$(grep -E "1[5-9]" /home/user/space.txt)
THRESHOLD=90
if [[ \$RESULTS -lt \$THRESHOLD ]]; then
exit 1;
elif [[ \$RESULTS -gt \$THRESHOLD ]]; then
hostname;
fi
" >> /home/user/problem.txt
done

Related

Problem with bash script that show volume level

I trying to make script that shows volume level of active volume sink. Here is code
#!/bin/bash
active_sink=$(pacmd list-sinks |awk '/* index:/{print $3}')
muted=$(pactl list sinks | perl -000ne 'if(/#${active_sink}/){/(Mute:.*)/; print "$1\n"}' | cut -f2 -d':' | cut -f2 -d' ')
vol=$(pactl list sinks | perl -000ne 'if(/#${active_sink}/){/(Volume:.*)/; print "$1\n"}' | cut -f1 -d'%' | tail -c 3
)
if [[ $muted = "no" ]]; then
if [[ $vol -ge 65 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-high.svg
echo "$vol%"
elif [[ $vol -ge 40 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-medium.svg
echo "$vol%"
elif
[[ $vol -ge 0 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-low.svg
echo "$vol%"
fi
else
echo ~/.config/tint2/executors/icons/audio-volume-muted.svg
echo "muted"
fi
I can't get this script to work, always get "muted".
I finally makes this thing to work, thanks #markp-fuso.
The problem was with perl and ${active_sink}.
Final code that work with corrected muted and vol
#!/bin/bash
active_sink=$(pacmd list-sinks | awk '/* index:/{print $3}')
muted=$(pactl list sinks | grep -A14 -P "(\#|№)$active_sink" | awk '/Mute:/{print $2}')
vol=$(pactl list sinks | grep -A14 -P "(\#|№)$active_sink" | awk '/Volume: front-left:/{print $5}' | cut -f1 -d'%')
if [[ $muted = "no" ]]; then
if [[ $vol -ge 65 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-high.svg
echo "$vol%"
elif [[ $vol -ge 40 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-medium.svg
echo "$vol%"
elif
[[ $vol -ge 0 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-low.svg
echo "$vol%"
fi
else
echo ~/.config/tint2/executors/icons/audio-volume-muted.svg
echo "muted"
fi

sed is not working for commenting a line in a file using bash script

I have created a bash script that is used to modify the ulimit of open files in the RHEL server.
so i have reading the lines in the file /etc/security/limits.conf and if the soft/hard limit of the open files are less than 10000 for '*' domain i am commenting the line and adding a new line with soft/hard limit as 10000.
The Script is working as designed but the sed command to comment a line in the script is not working.
Please find the full script below :-
#!/bin/sh
#This script would be called by '' to set ulimit values for open files in unix servers.
#
configfile=/etc/security/limits.conf
help(){
echo "usage: $0 <LimitValue>"
echo -e "where\t--LimitValue= No of files you want all the users to open"
exit 1
}
modifyulimit()
{
grep '*\s*hard\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
grep '*\s*soft\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
}
deleteEofTag(){
sed -i "/\b\(End of file\)\b/d" $configfile
}
addEofTag()
{
echo "#################End of file###################" >> $configfile
}
#-------------Execution of the script starts here ----------------------
if [ $# -ne 1 ];
then
help
else
modifyulimit $1
deleteEofTag
addEofTag
fi
The command sed -i -e 's/$line/#$line/g' $configfile when executed from the terminal is working absolutely fine and it is commenting the line but it is not working when i am executing it from the unix shell script.
interpolation does not work in single quote
use double quote and try
sed -i -e 's/$line/#$line/g'
sed -i -e "s/$line/#$line/g"
also you might try:
sed -i -e s/${line}/#${line}/g
as this will tell the script to take the value of the variable instead of variable as such.

Shell Script ssh $SERVER >> EOF

I have a handy script here that can return accounts that will expire in 7 Days or have expired. I wanted to allow this to run on multiple hosts with out putting the script on each individual host, I added the for loop and the ssh $SERVER >> EOF part but it will just run the commands off they system that is running the script.
I believe the error is with ssh $SERVER >> EOF but I am unsure as the syntax looks correct.
#!/bin/bash
for SERVER in `cat /lists/testlist`
do
echo $SERVER
ssh $SERVER >> EOF
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
totalaccounts=`sudo cat /tmp/expirelist.txt | wc -l`
for((i=1; i<=$totalaccounts; i++ ))
do
tuserval=`sudo head -n $i /tmp/expirelist.txt | tail -n 1`
username=`sudo echo $tuserval | cut -f1 -d:`
userexp=`sudo echo $tuserval | cut -f2 -d:`
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=`date +"%s"`
if [[ $userexpireinseconds -ge $todaystime ]] ;
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]];
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done
Here documents are started by << EOF (or, better, << 'EOF' to prevent the body of the here document being expanded by the (local) shell) and the end marker must be in column 1.
What you're doing is running ssh and appending standard output to a file EOF (>> is an output redirection; << is an input redirection). It is then (locally) running sudo, etc. It probably fails to execute the local file EOF (not executable, one hopes), and likely doesn't find any other command for that either.
I think what you're after is this (where I've now replaced the back-ticks in the script with $(...) notation, and marginally optimized the server list generation for use with Bash):
#!/bin/bash
for SERVER in $(</lists/testlist)
do
echo $SERVER
ssh $SERVER << 'EOF'
sudo cat /etc/shadow | cut -d: -f1,8 | sed '/:$/d' > /tmp/expirelist.txt
totalaccounts=$(sudo cat /tmp/expirelist.txt | wc -l)
for ((i=1; i<=$totalaccounts; i++))
do
tuserval=$(sudo head -n $i /tmp/expirelist.txt | tail -n 1)
username=$(sudo echo $tuserval | cut -f1 -d:)
userexp=$(sudo echo $tuserval | cut -f2 -d:)
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=$(date +"%s")
if [[ $userexpireinseconds -ge $todaystime ]]
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]]
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done
Very close, but the differences really matter! Note, in particular, that the end marker EOF is in column 1 and not indented at all.

Checking if domain is active on server

I am trying to check if a domain is active on the server. So far I get errors.
list=/root/domainlist.txt
for i in $(cat $list)
do
echo "checking " $i
$ip = host $i |grep -o -m 100 '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
if [[ $ip == "xx.xx.xx.xx" ]]; then
$i >> /root/activedomains.txt
fi
done
Output:
activedomains: line 4: =: command not found
This is the current error I get.
No spaces before and after the =
No dollar sign in the assignment
You probably want the result of the command, so enclose it in $( )
ip=$(host $i |grep -o -m 100 '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}')
write to the file like this
echo "$i" >> /root/activedomains.txt
You have a syntax error with the line
$ip = host $i |grep -o -m 100 '...'
you shoud use instead :
ip=$(host $i |grep -o -m 100 '...')
A better way using boolean logic (no need grep there, if host $ip failed, it will return FALSE):
list=/root/domainlist.txt
while read ip; do
echo "checking $ip"
host "$ip" &>/dev/null && echo "$ip" >> /root/activedomains.txt
done < "$list"
It's the equivalent of
list=/root/domainlist.txt
while read ip; do
echo "checking $ip"
if host "$ip" &>/dev/null; then
echo "$ip" >> /root/activedomains.txt
fi
done < "$list"
For starters you shouldn't assign to $ip to ip ... but it's possible there are more errors.
My guess would be you wanted (line 4/5):
ip=$(host $i |grep -o -m 100 '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}')
Also read user000001's answer. The missing echo when getting the output is another issue.

Replace IPs with Hostnames in a log

I am looking for a bash script that reads a log and replaces IP addresses with a hostname. Does anyone have any idea of how to do this?
Following script should work. You can use it like this:
save it to ip_to_hostname.sh and then:
./ip_to_hostname.sh your_logfile > resolved_ip
#!/bin/bash
logFile=$1
while read line
do
for word in $line
do
# if word is ip address change to hostname
if [[ $word =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
# check if ip address is correct
OIFS=$IFS
IFS="."
ip=($word)
IFS=$OIFS
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
then
echo -n `host $word | cut -d' ' -f 5`
echo -n " "
else
echo -n "$word"
echo -n " "
fi
# else print word
else
echo -n $word
echo -n " "
fi
done
# new line
echo
done < "$logFile"
Talking about IPv4: You may generate a list of sed-commands from your hosts file:
sed -rn 's/^(([0-9]{1,3}\.){3}([0-9]{1,3}))[ \t]([^ \t]+)[ \t].*/s#\1#\4#/p' /etc/hosts > hosts.sed
Then apply it on your logfile:
sed -f hosts.sed LOGFILE
Of course your hostsfilenames have to be listed in the hostfile.
Another, inverse approach would be to use logresolve.
From the manpage:
NAME
logresolve - Resolve IP-addresses to hostnames in Apache log files
SYNOPSIS
logresolve [ -s filename ] [ -c ] < access_log > access_log.new
SUMMARY
logresolve is a post-processing program to resolve IP-addresses in Apache's access logfiles. To minimize
impact on your nameserver, logresolve has its very own internal hash-table cache. This means that each
IP number will only be looked up the first time it is found in the log file.
Takes an Apache log file on standard input. The IP addresses must be the first thing on each line and
must be separated from the remainder of the line by a space.
So you could use REGEX's to extract all IPs, put them 2 times into a new file, once into the first column, and convert it with logresolve. Then use this table for generating such a sedfile as above.
The resolving can be done like this:
ip=72.30.38.140
hostname=nslookup $ip | grep name
hostname=${hostname#*name = }
hostname=${hostname%.}
This way IPs do not have to be in /etc/hosts.
The script itself depends on how your log looks like. Can you post an example?
This is the modified version of wisent's script I ended up using:
#!/bin/bash
logFile=$1
while read line
do
for word in $line
do
# if word is ip address change to hostname
if [[ $word =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\:[0-9]{1,5}$ ]]
then
port=$(echo "$word" | sed -e "s/.*://")
word=$(echo "$word" | sed -e "s/:.*//")
OIFS=$IFS
IFS="."
ip=($word)
IFS=$OIFS
# check if ip address is correct and not 192.168.*
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 && ${ip[0]}${ip[1]} -ne 192168 ]]
then
host=$(host $word | cut -d' ' -f 5)
if [[ $host =~ ^[0-9]{1,3}\(.*\)$ ]] # check for resolver errors
then
# if the resolver failed
echo -n "$word"
echo -n ":$port"
echo -n " "
else
# if the resolver worked
host=$(echo "$host'" | sed -e "s/\.'//" | sed ':a;N;$!ba;s/.*\n//g') # clean up cut's output
echo -n "$host"
echo -n ":$port"
echo -n " "
fi
else
# if the ip address isn't correct
echo -n "$word"
echo -n ":$port"
echo -n " "
fi
# else print word
else
echo -n $word
echo -n " "
fi
done
# new line
echo
done < "$logFile"
I added this to my .bashrc some time ago...
function resolve-hostname-from-ip()
{
if [ ! $1 ]
then
echo -e "${red}Please provide an ip address...${no_color}"
return 1
fi
echo "" | traceroute $1|grep " 1 "|cut -d ' ' -f4|cut -d '.' -f1
}
I have pre-defined terminal colors, so you can omit those if you like. =D
[root#somehostname ~ 08:50 AM] $ resolve-hostname-from-ip 111.22.33.444
someotherhostname
I have tested this on RHEL and SUSE successfully. I haven't tested it on IP's outside of my domain though, so I'm not 100% sure it will work in all cases...hope this helps =)

Resources