Replacing IP with server name in fping output - bash

I have a txt with a list of IP that I would like to check using fping, and then translate IP into name.
My file (hosts.txt) looks like this:
192.168.1.1 serverA
192.168.1.2 serverB
192.168.1.3 serverC
and this is the script I have written:
#! /bin/bash
N_Hosts=$(wc hosts.txt | awk {'print $1'})
typeset Nodos[$N_Hosts]
i=0;
while read line
do
Nodos[$i]=$(echo $line | awk {'print $1'})
i=$i+1
done < hosts.txt
comando="fping "
comandoCompleto=$comando${Nodos[*]}
$comandoCompleto | sed 's/is alive/OK/g' | sed 's/is unreachable/down/g'
Its output is like:
192.168.1.1 OK
192.168.1.2 down
192.168.1.3 OK
And I would like it to be:
serverA OK
serverB down
serverC OK
Is it possible to change the output using sed or awk?

If you have two files, your hosts.txt and output.txt (output from script) then you can do:
awk 'NR==FNR{a[$1]=$2;next}{$1=a[$1]}1' hosts.txt output.txt

Entirely in awk (I think this requires gawk)
gawk '
{
name[$1] = $2
ips = ips " " $1
}
END {
while ((("fping" ips) | getline) != 0) {
if ($3 == "alive")
print name[$1] " OK"
else if ($3 == "unreachable")
print name[$1] " down"
}
}
' hosts.txt
or entirely with bash version 4
declare -a ips
declare -A names
while read ip name; do
ips+=($ip)
names[$ip]=$name
done < hosts.txt
fping "${ips[#]}" |
while read ip _ status; do
case $status in
alive) echo ${names[$ip]} OK ;;
unreachable) echo ${names[$ip]} down ;;
esac
done

GNU sed
sed -r 's#(\S+)\s+(\S+)#/\1/s/(\\S+)\\s+(\\S+)/\2 \\2/#' hosts.txt|sed -rf - output.txt
..output:
serverA OK
serverB down
serverC OK

It sounds like all you need is:
while read ip name
do
fping "$ip" |
awk -v n="$name" '{print n, (/alive/?"OK":"down")}'
done < hosts.txt

Related

Bash is redirecting output from command only after script has finished

Context
Got a daft script that checks a process is running on a group of hosts, like a watchdog, as I say it's a daft script so bear in mind it isn't 'perfect' by scripting standards
Problem
I've ran bash -x and can see that the script finishes its first check without actually redirecting the output of the command to the file which is very frustrating, it means each host is actually being evaluated to the last hosts output
Code
#!/bin/bash
FILE='OUTPUT'
for host in $(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {' print $2 ' })
do ssh -n -f $host -i <sshkey> 'ps ax | grep myprocess | wc -l' > $FILE 2> /dev/null
cat $FILE
if grep '1' $FILE ; then
echo "Process is NOT running on $host"
cat $FILE
else
cat $FILE
echo "ALL OK on $host"
fi
cat $FILE
done
Script traceback
++ cat /etc/hosts
++ awk '{ print $2 }'
++ grep 'webserver.[2][1-2][0-2][0-9]'
+ for host in '$(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {'\'' print $2 '\''})'
+ ssh -n -f webserver.2100 -i <omitted> 'ps ax | grep myprocess | wc -l'
+ cat OUTPUT
+ grep 1 OUTPUT
+ cat OUTPUT
+ echo 'ALL OK on webserver.2100'
ALL OK on webserver.2100
+ cat OUTPUT
+ printf 'webserver.2100 checked \n'
webserver.2100 checked
+ for host in '$(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {'\'' print $2 '\''})'
+ ssh -n -f webserver.2101 -i <omitted> 'ps ax | grep myprocess | wc -l'
+ cat OUTPUT
2
+ grep 1 OUTPUT
+ cat OUTPUT
2
+ echo 'ALL OK on webserver.2101'
ALL OK on webserver.2101
+ cat OUTPUT
2
+ printf 'webserver.2101 checked \n'
webserver.2101 checked
Issue
As you can see, it's registering nothing for the first host, then after it is done, it's piping the data into the file, then the second host is being evaluated for the previous hosts data...
I suspect its to do with redirection, but in my eyes this should work, it doesn't so it's frustrating.
I think you're assuming that ps ax | grep myprocess will always return at least one line (the grep process). I'm not sure that's true. I'd rewrite that like this:
awk '/webserver.[2][1-2][0-2][0-9]/ {print $2}' /etc/hosts | while IFS= read -r host; do
output=$( ssh -n -f "$host" -i "$sshkey" 'ps ax | grep "[m]yprocess"' )
if [[ -z "$output" ]]; then
echo "Process is NOT running on $host"
else
echo "ALL OK on $host"
fi
done
This trick ps ax | grep "[m]yprocess" effectively removes the grep process from the ps output:
the string "myprocess" matches the regular expression "[m]yprocess" (that's the running "myprocess" process), but
the string "[m]yprocess" does not match the regular expression "[m]yprocess" (that's the running "grep" process)

Bash while read to include if [duplicate]

I have a file which maps IP Address to hostname. Its format is similar to hosts file and contains a list of ipaddress to hostname mapping.
eg.
10.200.99.1 master1
10.200.99.2 master2
10.200.99.3 master3
10.200.99.4 slave1
10.200.99.5 slave2
10.200.99.6 slave3
...
...
...
I would like to obtain hostname from a given ipaddress using bash script.
How can i do so?
You can try that :
sh script.sh listofip
#!/bin/bash
echo "IP ?"
echo -n "(Value and press Enter) :"
read ip
while read line
do
#VARIABLES
file1=$line
mip=$(echo $file1 | awk '{print $1}')
name=$(echo $file1 | awk '{print $2}')
if [ "$mip" = "$ip" ]
then
echo "Machine name is " $name
fi
done < $1
results :
IP ?
(Value and press Enter) :10.200.99.2
Machine name is master2
In Bash 4, I would use an associative array; see http://mywiki.wooledge.org/BashFAQ/006#Associative_Arrays
For older versions of Bash, maybe use a simple wrapper such as
lookup () {
echo "$1" |
awk 'NR==FNR { a[$1] = $2; next }
$1 in a { print a[$1]; exit 0 }
END { exit 1 }' input.txt -
}
This is slightly inelegant in that it requires the file to exist in the current directory. You can embed the mapping file in the script itself, though that requires some modest refactoring (the here document will tie up standard input so you cannot pipe your input to the script which reads it).
lookup () {
awk -v q="$1" '$1 == q { print $2; exit 0 }
END { exit 1 }' <<'________HERE'
10.200.99.1 master1
10.200.99.2 master2
10.200.99.3 master3
10.200.99.4 slave1
10.200.99.5 slave2
10.200.99.6 slave3
________HERE
}
I got a much simpler solution
#!/bin/bash
### GET IP ADDRESS ###
echo "IP Address ?"
echo -n "(Value and press Enter) :"
read ip_address
### Find Hostname matching to IPADDRESS ###
grep $ip_address /etc/hosts | awk '{print $2}'

How to get hostname from IP address from file similar to /etc/hosts

I have a file which maps IP Address to hostname. Its format is similar to hosts file and contains a list of ipaddress to hostname mapping.
eg.
10.200.99.1 master1
10.200.99.2 master2
10.200.99.3 master3
10.200.99.4 slave1
10.200.99.5 slave2
10.200.99.6 slave3
...
...
...
I would like to obtain hostname from a given ipaddress using bash script.
How can i do so?
You can try that :
sh script.sh listofip
#!/bin/bash
echo "IP ?"
echo -n "(Value and press Enter) :"
read ip
while read line
do
#VARIABLES
file1=$line
mip=$(echo $file1 | awk '{print $1}')
name=$(echo $file1 | awk '{print $2}')
if [ "$mip" = "$ip" ]
then
echo "Machine name is " $name
fi
done < $1
results :
IP ?
(Value and press Enter) :10.200.99.2
Machine name is master2
In Bash 4, I would use an associative array; see http://mywiki.wooledge.org/BashFAQ/006#Associative_Arrays
For older versions of Bash, maybe use a simple wrapper such as
lookup () {
echo "$1" |
awk 'NR==FNR { a[$1] = $2; next }
$1 in a { print a[$1]; exit 0 }
END { exit 1 }' input.txt -
}
This is slightly inelegant in that it requires the file to exist in the current directory. You can embed the mapping file in the script itself, though that requires some modest refactoring (the here document will tie up standard input so you cannot pipe your input to the script which reads it).
lookup () {
awk -v q="$1" '$1 == q { print $2; exit 0 }
END { exit 1 }' <<'________HERE'
10.200.99.1 master1
10.200.99.2 master2
10.200.99.3 master3
10.200.99.4 slave1
10.200.99.5 slave2
10.200.99.6 slave3
________HERE
}
I got a much simpler solution
#!/bin/bash
### GET IP ADDRESS ###
echo "IP Address ?"
echo -n "(Value and press Enter) :"
read ip_address
### Find Hostname matching to IPADDRESS ###
grep $ip_address /etc/hosts | awk '{print $2}'

Get hostname mapped to IP Address from file similar to hosts file using BASH

I have a file similar to hosts file where IP Address is mapped to hostname.
Below is a snapshot of file
20.200.80.15 slave1
20.200.80.16 slave2
20.200.80.17 slave3
20.200.80.18 slave4
20.200.80.19 slave5
20.200.80.20 master1
I would like to retrive Hostname from IP Address from the above file using bash script i.e. if I supply ipaddress as 20.200.80.18 then i should get output as slave4
The script could be something like this:
#!/bin/bash
if [ $# -ne 1 ];then
echo "Usage: myscript.sh IP";
exit 1;
fi;
IP=$1
HOSTS_FILE=/root/hosts_test
grep -F "$IP " "$HOSTS_FILE" | awk '{ print $2 }'
exit 0;
And you call it like:
sh myscript.sh 20.200.80.16
It is important to use the -F option in grep (or use fgrep) so te dots are considered as litterals and as not regex wildcards.
I think something like this would work:
#!/bin/sh
ip=$1
file=$2
grep $ip $file | tr -s ' ' | cut -d ' ' -f2
and running the script like this:
getHost 20.20.20.20 /etc/ipfile

Building Dynamic Variable Names in KornShell

I did a search but did not find anything quite like what I am trying to do.
I have a list of Server Hostnames & IPs
Servera | IPa
Serverb | IPb
Servern | IPn
I want to cat this file and put each element into variables
Server_Var_1
IP_Var_1
Server_Var_2
IP_Var_2
Server_Var_n
IP_Var_n
What I currently have is the following KornShell (ksh):
Counter=0
cat hostfile|while read line; do
Server_Var_"$Counter"=echo $line | awk -F"|" '{print $1}'
IP_Var_"$Counter"=echo $line | awk -F"|" '{print $2}'
echo $Server_Var_[*] $IP_Var_[*]
done
Any help is appreciated.
$ cat hostfile
server1 | 192.168.1.101
server2 | 192.168.1.102
server3 | 192.168.1.103
$ cat foo
#!/bin/sh
counter=0
while IFS=" |" read name ip; do
eval Server_VAR_$counter=$name
eval IP_VAR_$counter=$ip
: $(( counter += 1 ))
done < hostfile
echo $Server_VAR_0:$IP_VAR_0
echo $Server_VAR_1:$IP_VAR_1
echo $Server_VAR_2:$IP_VAR_2
$ ./foo
server1:192.168.1.101
server2:192.168.1.102
server3:192.168.1.103
Here's a slight twist to the original question (which was perfectly answered by #William Pursell). So this bit of code will produce the same output, but uses an array of compound variables instead. Note that this is specific to ksh93.
$ cat read_hostvars
#!/bin/sh
counter=0
typeset -a Server
while IFS=" |" read name ip; do
Server[counter].name=$name
Server[counter].ip=$ip
(( counter++ ))
done < hostfile
for n in ${!Server[#]}; do
echo ${Server[n].name}:${Server[n].ip}
done

Resources