Cannot exit bash script at the end of the for cycle - bash

I wrote a simple IP scanner based on ping (see below), but it has a problem.
#!/bin/bash
counter = 0
for ip in 192.168.44.{1..254}; do
ping -c 1 -W 1 $ip | grep "64 bytes" &
let counter++
if [[ "$counter" -eq 254 ]];
then
exit 0;
fi
done
First of all, the for cycle appears to be launching multiple threads and the only output to the terminal are the ping answers. However, when the script finishes pinging all the machines in the network, it never exits, as you can see in the next screenshot:
and I have to press Enter to finally end it.
I've also tried to place an exit 0 after the done statement, but it still does not work. How can I make the script exit when the for cycle ends?
Note: I've found this implementation to be the fastest to find the existing machines in a LAN, but if anyone has a suggestion of a more appropriate code, I would appreciate it.

Assuming that you do not want to use a dedicated network scanning tools, You can use bash or xargs to iterate over all addresses in parallel:
Bash:
#! /bin/bash -x
for ip in 192.168.44.{1..254}; do
ping -c 1 -W 1 $ip | grep "64 bytes" &
done
# Wait for all children to finish
wait
Or with xargs, with the advantage that you can control the number of parallel addresses being pinged (20 in this example) - to avoid overloading your server with large number of concurrent process.
echo 192.168.44.{1..254} | xargs --max-args=1 -P20 ping -c 1 -W 1

You can try this:
#!/bin/bash
for ip in 192.168.44.{1..254}; do
ping -c 1 -W 1 $ip | grep "64 bytes" &
done
wait

If CTRLc is acceptable:
parallel -j0 --lb ping ::: 192.168.1.{1..250}

Related

Scanning LAN using ping and Gnu Parallel

I am trying to scan my LAN using ping, invoking using Gnu Parallel. The code ideally will simply report those IP addresses which are up and strip out any verbose reporting. The original code (without parallel) which works well is:
for ip in $(seq 1 254) ; do ping -t5 -c 1 192.168.0.$ip > /dev/null ; [ $? -eq 0 ] && echo "192.168.0.$ip UP" & done
However it is annoying with all the job completed messages (set +m is not helpful). Running sequentially takes too long to poll each IP address.
The Parallel code so far which works (take out the --dry-run to execute) is:
seq 1 254 | parallel --dry-run ping -t5 -c 1 192.168.0.{}
but trying to do
seq 1 254 | parallel --dry-run ping -t5 -c 1 192.168.0.{} ';' [ $? -eq 0 ] && echo "192.168.0.{} UP"
or variations of that, fail to achieve the objective. Can anyone help with the test part here?
Cracked it - hope this is helpful to others.
seq 1 254 | parallel ' ping -t5 -c 1 192.168.0.{} >/dev/null && echo 192.168.0.{} UP ' 2>/dev/null
From the Gnu documentation, a parallel timeout rather than ping timeout seems to be more efficient
seq 1 254 | parallel --timeout 2 -j64 -keep-order ' ping -c 1 192.168.0.{} >/dev/null && echo 192.168.0.{} UP ' 2>/dev/null

Bash Script to check for host

I have a complicated script request that I am trying to figure out. Basically, I need a script that will check for certain conditions and depending on the outcome will run certain commands.
So, I need it to check if $hostip is up and running. If it is running, I need it to check and see if $domain has same IP address as $domainip. If they match, script then ends. If they don't match, I need to run command "shutdown $hostip". Now, if it fails to find $domain, ie internet is down, then I need it to sleep for 6 hours and then try again. I want it to try 3 times and if still can't find domain after 18 hours, then run "shutdown $hostip".
The goal above is to shutdown a server if the domain does not match the set IP or the internet is disconnected for 18 hours.
I also need script to check the other side of things as well. So, if $hostip is not online, but $domain and $domainip do match, then power on server.
These are my variables I have so far.
domain=google.com
domainip=216.58.194.46
hostip=192.168.1.1
gatewayip=$(ping -q -c 1 -t 1 $domain | grep PING | sed -e "s/).*//" | sed -e "s/.*(//")
So there are two parts to this.
First, you need to check if the hosts is up. You can do this with ping as you have done:
ping -q -c 1 "$domain" >/dev/null 2>&1
which will set its exit code to true or false as expected if the host is up or down. Note I've removed the -t option as it was causing the ping to fail.
Second, you need to check that $domain resolves to $domainip. You can do this with several tools - host is straightforward:
host -t a $domain | grep -q "$domain has address $domainip"
Putting that together you get something like:
domain=google.com
domainip=216.58.194.46
hostip=192.168.1.1
for i in {1..3}; do
sleep 6h
if ping -q -c 1 "$domain" 2>/dev/null; then
exit 0
fi
if host -t a $domain | grep -q "$domain has address $domainip"; then
exit 0
fi
done
shutdown $hostip

sshpass exit in automation

I have total of 6 IP addresses and out of the 6 only 2 IP addresses are valid. I wrote a shell script to use sshpass to test each IP.
The issue is when script reaches IP that is working it log's in the system (Cisco switch) and stays there and not continuing with the loop to test the remaining IPs. If i type "exit" on the system than it continues with the loop.
After a successful login how can script automatically get out, from logged system, and continue with testing remaining IP?
/usr/bin/sshpass -p $ADMINPASS ssh -oStrictHostKeyChecking=no -oCheckHostIP=no -t $ADMINLOGIN#$IP exit
i can use the exit status to figure out which IP worked and which on didn't work.
Test first if IP is alive, and then 'ssh' on it, could help you.I don't know if you are using a loop or not, but loop can be a good choice.Should look like : for f in ip-1 ip-2 ip-3 ip-4 ip-5 ip-6; do ping -c 1 -w 3 $f; if [ $? -eq 0 ]; then echo OK; ssh_pass $f your_command; else echo " IP is NOK"; fi; done
You can then also add 'exit' command, depending on what you test : 'exit 0' if it is OK, after you 'ssh' command, 'exit 1' if NOK.

Modify shell script to monitor/ping multiple ip addresses

Alright so I need to constantly monitor multiple routers and computers, to make sure they remain online. I have found a great script here that will notify me via growl(so i can get instant notifications on my phone) if a single ip cannot be pinged. I have been attempting to modify the script to ping multiple addresses, with little luck. I'm having trouble trying to figure out how to ping a down server while the script keeps watching the online servers. any help would be greatly appreciated. I haven't done much shell scripting so this is quite new to me.
Thanks
#!/bin/sh
#Growl my Router alive!
#2010 by zionthelion73 [at] gmail . com
#use it for free
#redistribute or modify but keep these comments
#not for commercial purposes
iconpath="/path/to/router/icon/file/internet.png"
# path must be absolute or in "./path" form but relative to growlnotify position
# document icon is used, not document content
# Put the IP address of your router here
localip=192.168.1.1
clear
echo 'Router avaiability notification with Growl'
#variable
avaiable=false
com="################"
#comment prefix for logging porpouse
while true;
do
if $avaiable
then
echo "$com 1) $localip avaiable $com"
echo "1"
while ping -c 1 -t 2 $localip
do
sleep 5
done
growlnotify -s -I $iconpath -m "$localip is offline"
avaiable=false
else
echo "$com 2) $localip not avaiable $com"
#try to ping the router untill it come back and notify it
while !(ping -c 1 -t 2 $localip)
do
echo "$com trying.... $com"
sleep 5
done
echo "$com found $localip $com"
growlnotify -s -I $iconpath -m "$localip is online"
avaiable=true
fi
sleep 5
done
The simplest approach is to wrap this script with another one that creates N processes. Assume your script is called "watchip", then put into another script the text
watchip 10.0.1.1 &
watchip 10.0.1.2 &
watchip 10.0.1.3 &
etc
and set localip to $1 inside watchip.
I don't think it's necessary to run multiple scripts. Here is a general script to monitor a list of IP addresses and note changes in ping success...
#!/bin/bash
set 10.0.0.1 10.0.0.2 # etc
trap exit 2
while true; do
i=1
for ipnumber in "$#"; do
statusname=up$i
laststatus=${!statusname:-0}
ping -c 1 -t 2 $ipnumber > /dev/null
ok=$?
eval $statusname=$ok
if [ ${!statusname} -ne $laststatus ]; then
echo status changed for $ipnumber
if [ $ok -eq 0 ]; then
echo now it is up
else
echo now it is down
fi
fi
i=$(($i + 1))
done
sleep 5
done
Change localip=192.168.1.1 to:
localip=$1
This allows the IP address to be passed in as a command-line argument. Then you can run multiple copies of the script passing in different IP addresses. You could then create a master script to run multiple copies of the monitoring script. Assuming the script you posted is monitor.sh:
#!/bin/sh
monitor.sh 192.168.1.1 &
monitor.sh 192.168.2.2 &
monitor.sh 192.168.3.3 &
wait
Keep two arrays. One with available IPs; the other with unavailable ones. When their status changes, move them to the other array. No need for multiple background processes.
I've omitted the logging stuff. You can add it back in. This is untested code.
available=(192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4)
unavailable=()
while true
do
for index in ${!available[#]}
do
if ! ping -c 1 -t 2 ${available[index]}
then
growlnotify -s -I $iconpath -m "${available[index]} is offline"
unavailable+=(${available[index]})
unset "available[index]"
fi
done
for index in ${!unavailable[#]}
do
if ping -c 1 -t 2 ${unavailable[index]}
then
growlnotify -s -I $iconpath -m "${unavailable[index]} is back online"
available+=(${unavailable[index]})
unset "unavailable[index]"
fi
done
done

Making bash script to check connectivity and change connection if necessary. Help me improve it?

My connection is flaky, however I have a backup one. I made some bash script to check for connectivity and change connection if the present one is dead. Please help me improve them.
The scripts almost works, except for not waiting long enough to receive an IP (it cycles to next step in the until loop too quick). Here goes:
#!/bin/bash
# Invoke this script with paths to your connection specific scripts, for example
# ./gotnet.sh ./connection.sh ./connection2.sh
until [ -z "$1" ] # Try different connections until we are online...
do
if eval "ping -c 1 google.com"
then
echo "we are online!" && break
else
$1 # Runs (next) connection-script.
echo
fi
shift
done
echo # Extra line feed.
exit 0
And here is an example of the slave scripts:
#!/bin/bash
ifconfig wlan0 down
ifconfig wlan0 up
iwconfig wlan0 key 1234567890
iwconfig wlan0 essid example
sleep 1
dhclient -1 -nw wlan0
sleep 3
exit 0
Here's one way to do it:
#!/bin/bash
while true; do
if ! [ "`ping -c 1 google.com; echo $?`" ]; then #if ping exits nonzero...
./connection_script1.sh #run the first script
sleep 10 #give it a few seconds to complete
fi
if ! [ "`ping -c 1 google.com; echo $?`" ]; then #if ping *still* exits nonzero...
./connection_script2.sh #run the second script
sleep 10 #give it a few seconds to complete
fi
sleep 300 #check again in five minutes
done
Adjust the sleep times and ping count to your preference. This script never exits so you would most likely want to run it with the following command:
./connection_daemon.sh 2>&1 > /dev/null & disown
Have you tried omitting the -nw option from the dhclient command?
Also, remove the eval and quotes from your if they aren't necessary. Do it like this:
if ping -c 1 google.com > /dev/null 2>&1
Trying using ConnectTimeout ${timeout} somewhere.

Resources