First time post, please forgive any missing information.
I have a script that is supposed to work with icinga. I need icinga to log into my Linux box and run a command like "script ". The script will then run a command to that hostname like sudo /etc/init.d/apache2 status then report back "running or unused" and an exit status of 0 or 2.
I'm wondering how I could add another command and have it one or the other run depending on what hostname it's given. Half of them need apache2 to be running and the other half need to have a process called dss to be running. I'd rather not have two separate scripts. Here is the working script and sorry it's sloppy but I haven't done any clean up and I'm not real good at bash yet.
so the user would run the script ./chkdss2 or
#!/bin/bash
ec=0
ec1=2
var3=run
var4=unused
for host in "$#"
do
var1=`ssh $host sudo /etc/init.d/dss status|awk '{print $6}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "$host is running"
echo $ec
else
echo "$host is not running"
echo $ec1
fi
done
There are a couple ways to test if a particular hostname is for apache or dss. You only need to have a list of hostnames for each case, and check if the received hostnames are included in said lists.
Method 1: using arrays
#!/bin/bash
# Method 1, using array lists of hosts
apachehosts=('ap1' 'ap2' 'ap3')
dsshosts=('dss1' 'dss2' 'dss3')
for host in "$#"
do
if printf '%s\n' "${apachehosts[#]}" | grep -Fxq "$host"
then
echo "$host: APACHE HOST"
elif printf '%s\n' "${dsshosts[#]}" | grep -Fxq "$host"
then
echo "$host: DSS HOST"
else
echo "ERROR, $host: unknown host"
fi
done
To modify the lists of hosts, simply add or remove values in the declaration of arrays apachehosts and dsshosts.
Method 2: using case
#!/bin/bash
# Method 2, using case
for host in "$#"
do
case "$host" in
'ap1'|'ap2'|'ap3')
echo "CASE, $host: APACHE HOST"
;;
'dss1'|'dss2'|'dss3')
echo "CASE, $host: DSS HOST"
;;
*)
echo "ERROR CASE, $host: unknown host"
;;
esac
done
Here, you edit the patterns in each case.
Method 3: using if
#!/bin/bash
# Method 3, using if
for host in "$#"
do
if [[ "$host" == 'ap1' || "$host" == 'ap2' || "$host" == 'ap3' ]]
then
echo "IF, $host: APACHE HOST"
elif [[ "$host" == 'dss1' || "$host" == 'dss2' || "$host" == 'dss3' ]]
then
echo "IF, $host: DSS HOST"
else
echo "IF, $host: unknown host"
fi
done
Here you modify the if conditions. I prefer the other methods, since this one is more complicated to edit, it is not as clear, especially if your list of hosts is long.
Method 4: condition on the hostnames
If you are lucky, there is some pattern to your hostnames. Ex. all apache servers start with letters ap, all your dss servers include dss in the name, ...
You can then simply use 2 if statements to decide which is which.
#!/bin/bash
# Method 4, patterns
for host in "$#"
do
if [[ $(echo "$host" | grep -c -e "^ap") -ne 0 ]]
then
echo "PATTERNS, $host: APACHE HOST"
elif [[ $(echo "$host" | grep -c -e "dss") -ne 0 ]]
then
echo "PATTERNS, $host: DSS host"
else
echo "PATTERNS, $host: unknown host"
fi
done
Note: hostname apdss1 would come out as an Apache server here. Previous methods would respond "unknown host". You patterns must be strict enough to avoid mismatches.
I had a similar task to get few report items using single ssh request.
I had to retrieve in singel ssh command:
Full hostname (FQDN)
Linux version
IP address of its Docker host if exist, or "none"
I got my script to work in 3 stage.
1. Get multiple lines of information from remote host
ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
'
Results:
2022-03-05:22:22:21
dudi-HP-Compaq-Elite-8300-MT
20
192.168.2.111 192.168.122.1 172.17.0.1
2. Process multiple lines of information from remote host
Read lines of information from remote host, into an array sshResultsArr.
readarray -t sshResultsArr < <(ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
Result:
dudi-HP-Compaq-Elite-8300-MT OS version: 20 has Docker IP: 172.17.0.1
3. Process each remote host in a loop
#!/bin/bash
for host in "$#"; do
readarray -t sshResultsArr < <(ssh -q $host <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
done
I was able to take a little bit from the answers I received and put together something that works well. Thank you all for your answers.
for host in "$#"
do
case "$host" in
('vho1uc1-primary'|'vho1uc2-backup'|'vho2uc1-primary'|'vho2uc2-backup'|'vho3uc1-primary'|'vho3uc2-backup'|'vho10uc1-primary')
var1=`ssh "$host" sudo /etc/init.d/apache2 status|awk '{print $4}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "Apache2 on $host is running"
echo "0"
else
echo "Apache2 on $host is not running"
echo "2"
fi
;;
*)
esac
done
The bash script is:
echo Updating hostname and IP address ...
echo ${config_template_ip}
echo "ssh-keygen -R ${config_template_ip} -f /home/testusr/.ssh/known_hosts"
echo ${config_template_ip}
The output is
Updating hostname and IP address ...
10.100.224.250
-f /home/testusr/.ssh/known_hosts
10.100.224.250
why didn't "ssh-keygen -R ${config_template_ip} " on STDOUT, and how to solve that?
I am trying to write a bash script where i will give an IP as an argument. If the IP is not valid I want to print to screen a message.If the IP is valid I print the hostname.
host $1 | cut -d' ' -f5
This is my code if the IP is valid. I don't know hot to compare the output if it's not valid to print the corresponding message
You can do it this way:
if host=$(host "$1" 2>/dev/null); then # ignore stderr
echo "$host"
else
echo "$1 is not a valid host"
fi
If you want to display the error output of host in the else part, then:
if host=$(host "$1" 2>&1); then # merge stdout and stderr
echo "$host"
else
echo "$1 is not a valid host, error=$host"
fi
I want to use fping to ping multiple ips contained in a file and output the failed ips into a file i.e.
hosts.txt
8.8.8.8
8.8.4.4
1.1.1.1
ping.sh
#!/bin/bash
HOSTS="/tmp/hosts.txt"
fping -q -c 2 < $HOSTS
if ip down
echo ip > /tmp/down.log
fi
So I would like to end up with 1.1.1.1 in the down.log file
It seems that parsing the data from fping is somewhat difficult. It allows the parsing of data for hosts that is alive but not dead. As a way round the issue and to allow for multiple host processing simultaneously with -f, all the hosts that are alive are placed in a variable called alive and then the hosts in the /tmp/hosts.txt file are looped through and grepped against the variable alive to decipher whether the host is alive or dead. A return code of 1 signifies that grep cannot find the host in alive and hence an addition to down.log.
alive=$(fping -c 1 -f ipsfile | awk -F: '{ print $1 }')
while read line
do
grep -q -o $line <<<$alive
if [[ "$?" == "1" ]]
then
echo $line >> down.log
fi
done < /tmp/hosts.txt
Here's one way to get the result you want. Note however; i didn't use fping anywhere in my script. If the usage of fping is crucial to you then i might have missed the point entirely.
#!/bin/bash
HOSTS="/tmp/hosts.txt"
declare -i DELAY=$1 # Amount of time in seconds to wait for a packet
declare -i REPEAT=$2 # Amount of times to retry pinging upon failure
# Read HOSTS line by line
while read -r line; do
c=0
while [[ $c < $REPEAT ]]; do
# If pinging an address does not return the word "0 received", we assume the ping has succeeded
if [[ -z $(ping -q -c $REPEAT -W $DELAY $line | grep "0 received") ]]; then
echo "Attempt[$(( c + 1))] $line : Success"
break;
fi
echo "Attempt[$(( c + 1))] $line : Failed"
(( c++ ))
done
# If we failed the pinging of an address equal to the REPEAT count, we assume address is down
if [[ $c == $REPEAT ]]; then
echo "$line : Failed" >> /tmp/down.log # Log the failed address
fi
done < $HOSTS
Usage: ./script [delay] [repeatCount] -- 'delay' is the total amount of seconds we wait for a response from a ping, 'repeatCount' is how many times we retry pinging upon failure before deciding the address is down.
Here we are reading the /tmp/hosts.txt line by line and evaluating each adress using ping. If pinging an address succeeds, we move on to the next one. If an address fails, we try again for as many times as the user has specified. If the address fails all of the pings, we log it in our /tmp/down.log.
The conditions for checking whether a ping failed/succeeded may not be accurate for your use-cases, so maybe you will have to edit that. Still, i hope this gets the general idea across.
Sorry for the trouble.. here is the code what works for a single server. I need help to loop it to multiple servers. Thanks in advance, Please help me out .
I need to know information of multiple servers like their:
Operating system info
Hostname and dns info
Network info
Who is online
Last logged in users and so on
logic is to pass the server names from a text file and display the same info for all the server in the file and write output to other file
Below are the different fucntions which fetch the details of a server. The same should be iterated for multiple servers..
#!/bin/bash
# grabsysinfo.sh - A simple menu driven shell script to to get information about your
# Linux server / desktop.
# Define variables
LSB=/usr/bin/lsb_release
# Purpose: Display pause prompt
# $1-> Message (optional)
function pause(){
local message="$#"
[ -z $message ] && message="Press [Enter] key to continue..."
read -p "$message" readEnterKey
}
# Purpose - Display a menu on screen
function show_menu(){
date
echo "---------------------------"
echo " Main Menu"
echo "---------------------------"
echo "1. Operating system info"
echo "2. Hostname and dns info"
echo "3. Network info"
echo "4. Who is online"
echo "5. Last logged in users"
echo "6. Free and used memory info"
echo "7. exit"
}
# Purpose - Display header message
# $1 - message
function write_header(){
local h="$#"
echo "---------------------------------------------------------------"
echo " ${h}"
echo "---------------------------------------------------------------"
}
# Purpose - Get info about your operating system
function os_info(){
write_header " System information "
echo "Operating system : $(uname)"
[ -x $LSB ] && $LSB -a || echo "$LSB command is not insalled (set \$LSB variable)"
#pause "Press [Enter] key to continue..."
pause
}
# Purpose - Get info about host such as dns, IP, and hostname
local dnsips=$(sed -e '/^$/d' /etc/resolv.conf | awk '{if (tolower($1)=="nameserver") print $2}')
write_header " Hostname and DNS information "
echo "Hostname : $(hostname -s)"
echo "DNS domain : $(hostname -d)"
echo "Fully qualified domain name : $(hostname -f)"
echo "Network address (IP) : $(hostname -i)"
echo "DNS name servers (DNS IP) : ${dnsips}"
pause
}
# Purpose - Network inferface and routing info
function net_info(){
devices=$(netstat -i | cut -d" " -f1 | egrep -v "^Kernel|Iface|lo")
write_header " Network information "
echo "Total network interfaces found : $(wc -w <<<${devices})"
echo "*** IP Addresses Information ***"
ip -4 address show
echo "***********************"
echo "*** Network routing ***"
echo "***********************"
netstat -nr
echo "**************************************"
echo "*** Interface traffic information ***"
echo "**************************************"
netstat -i
pause
}
# Purpose - Display a list of users currently logged on
# display a list of receltly loggged in users
function user_info(){
local cmd="$1"
case "$cmd" in
who) write_header " Who is online "; who -H; pause ;;
last) write_header " List of last logged in users "; last ; pause ;;
esac
}
# Purpose - Display used and free memory info
function mem_info(){
write_header " Free and used memory "
free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
ps auxf | sort -nr -k 4 | head -5
pause
}
# Purpose - Get input via the keyboard and make a decision using case..esac
function read_input(){
local c
read -p "Enter your choice [ 1 - 7 ] " c
case $c in
1) os_info ;;
2) host_info ;;
3) net_info ;;
4) user_info "who" ;;
5) user_info "last" ;;
6) mem_info ;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
}
# ignore CTRL+C, CTRL+Z and quit singles using the trap
trap '' SIGINT SIGQUIT SIGTSTP
First you need Key-Based SSH login to your remote servers (https://help.ubuntu.com/community/SSH/OpenSSH/Keys#Key-Based_SSH_Logins)
After that you use a loop like this:
function read_input(){
read -p "Enter your choice [ 1 - 7 ] " c
for server in $(cat your_server_file);
do
case $c in
1) os_info $server;;
2) host_info $server;;
3) net_info $server;;
4) user_info "who" $server;;
5) user_info "last" $server;;
6) mem_info $server;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
done
}
And in example your mem_info function
function mem_info(){
server=$1
write_header " Free and used memory "
ssh ssh_remote_user#server free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
ssh ssh_remote_user#server vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
ssh ssh_remote_user#server ps auxf | sort -nr -k 4 | head -5
pause
}
UPDATE
If you use sshpass you have to change a little bit.
Your your_server_file should look like this:
user1#password1|user1#server1
user2#password2|user2#server2
...
Your main function
function read_input(){
read -p "Enter your choice [ 1 - 7 ] " c
for line in $(cat your_server_file);
do
user_pass=$(echo $line | sed -e 's/\(.*\)|\(.*\)/\1/')
server=$(echo $line | sed -e 's/\(.*\)|\(.*\)/\2/')
case $c in
1) os_info $server $user;;
2) host_info $server $user;;
3) net_info $server $user;;
4) user_info "who" $server $user;;
5) user_info "last" $server $user;;
6) mem_info $server $user;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
done
}
And the mem_info function
function mem_info(){
server=$1
user_pass=$2
write_header " Free and used memory "
sshpass -p $user_pass ssh $server free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
sshpass -p $user_pass ssh $server vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
sshpass -p $user_pass ssh $server ps auxf | sort -nr -k 4 | head -5
pause
}
I did not quote anything. Please take care about special characters