Problems with past arguments in script

I have a question is there any possibility for maken a script that you can see if computers are on in your network
when you run the script for ex. ./ping.sh 54 62 62 , a script when you give as argument the last digit of the ip adres of the computers

my network is 192.168.129.0

This is what i already have but i want to give extra parameters to the script
for example
parameter 1: xx-yy: this parameter ensures that all computers be test in the range of xx-yy eg. 61-67, test all the 7 computers with the last digit

parameter 2: -t , ensures that each number count with 200 eg. -t 17 test the ip adress 217 , -t 17-19 test all the adresses 217 to 219

for ip in 192.168.1.{1..10}; do  # for loop and the {} operator
    ping -c 1 -t 1 192.168.1.1 > /dev/null 2> /dev/null  # ping and discard output
    if [ $? -eq 0 ]; then  # check the exit code
        echo "${ip} is up" # display the output
    else
        echo "${ip} is down"
    fi
done

I'd change to:

IP_PRE=192.168.1
[ -z "$1" ] && echo "Usage: ${0##*/} 15 30-37 42 .."

for num in "${@}";do
# Parse all the arguments
	if [ "-" = "$(echo $num|tr -d [[:digit:]])" ]
	then	# Its a range, as it contains a '-'
		range_start=${num/-*}
		range_end=${num/*-}
		range=$(seq $range_start 1 $range_end)
	else	# It has no range, its a single number
		range=$num
	fi
	# Parse all the numbers filled in range
	for r in $range;do
		ping -c1 $IP_PRE.$r 2>/dev/zero 1>/dev/zero && \
			echo "$IP_PRE.$r is up" || \
			echo "$IP_PRE.$r is down"
	done
done

Untested, have fun :slight_smile:

Also, sounds quite familiar like: Script with ping

hth

1 Like

Thank you but how do i implement the paramters xx-yy and -t ?

Usage:

./test.sh 15 30-37 42 ...

Will/should test:

192.168.1.15
192.168.1.30
192.168.1.31
...
192.168.1.37
192.168.1.42

Or did i misunderstand something?
Btw, updated the code block and added a 'usage' message if you dont pass an argument.

thanks and the paremeter -t that counts for ex 200 by ./test.sh -t 17

192.168.1.217

what do you mean with update the code block and added a usage message ?

I would try something like:

#!/bin/ksh
# Print Usage message and exit.
Usage() {
	printf 'Usage:\t%s [-t] lastIP\n\t%s [-t] LOWlastIP-HIGHlastIP\n' \
		"$IAm" "$IAm" >&2
	exit 1
}

BaseIP='192.168.1.'	# All but last component of desired IP address
IAm=${0##*/}		# Last component of script name for diagnostics
addon=0			# Default add-on if -t option is not present

# Parse options...
while getopts 't' opt
do      case "$opt" in
	(t)     addon=200;;
	(?)     Usage;;
	esac
done
shift $((OPTIND - 1))

# Process operand...
if [ $# -ne 1 ]
then	printf '%s: 1 operand required; found %d\n' "$IAm" $# >&2
	Usage
fi
# Verifying that the operand is in the correct format is left as an exercise
# for the reader.
low=$((${1%%-*} + addon))	# Set low end of last component of IP address.
high=$((${1##*-} + addon))	# Set high end...

# Loop through the requested IP addresses...
last="$low"
while [ "$last" -le "$high" ]
do	ip="$BaseIP$last"
	# ping, discard otuput, check exit status, and print results
	if ping -c 1 -t 1 "$ip" > /dev/null 2> /dev/null
	then	echo "${ip} is up"
	else	echo "${ip} is down"
	fi
	last=$((last + 1))
done

Although written and tested using the Korn shell, this script only uses POSIX standard shell parameter expansion and looping constructs. So it should work with any shell that tries to conform to the standard.

Well if you want to ping ip 217, then you'll pass 217.. or 1-222, it'll be among it.

EDIT:
Saying/Asking: I'm not getting why there should be a need to increment passed numbers by (say) 200 with a -t toggle.
As that increasing requires an extra argument, why not pass the wanted number directly, its even 1 char less to type?

1 Like

Thank you

So, did a bit additional fun, it now parses ip addr to figure out the base_ip dynamicly.
Also, output is a bit changed:

localping 1-20
Pinging 192.168.10.1... is up
Pinging 192.168.10.2... is down

You're welcome, enjoy :slight_smile:

#!/bin/bash
#
#	Variables
#
	[ -z "$1" ] && echo "Usage: ${0##*/} 15 30-37 42 .."
	TMP=~/.cache/tmp.$$
#
# 	Prepare Base IP
#
	# IPv6? -- dont work, not needed, but fun anyway.
	[ "-6" = "$1" ] && \
		filter=6 && \
		shift || filter=" "
	# Get Ip
	ip addr|grep inet"$filter" |grep -ve 127 -ve " ::"|awk '{print $2}' > $TMP
	while IFS="." read A B C igno; do IP_PRE="$A.$B.$C"; done<$TMP
#
#	Ping arguments
#
	for num in "${@}";do	# Parse all the arguments
		# Its a range, as it contains a '-'
		if [ "-" = "$(echo $num|tr -d [[:digit:]])" ]
		then	# So lets get the start and end range
			range_start=${num/-*}
			range_end=${num/*-}
			# Lets fil lthe variable with the range of IP's
			range=$(seq $range_start 1 $range_end)
		else	# It has no range, its a single number
			range=$num
		fi

		# Parse all the numbers of range, and use them for the ping command
		for r in $range;do
			# Let the user know what we're doing now...
			printf "%s" "Pinging $IP_PRE.$r... "
			# Execute the command and append the missing text according to exit status
			ping -c 1 $IP_PRE.$r 2>/dev/zero  1>/dev/zero  && \
				echo "is up" || \
				echo "is down"
		done
	done
#
#	Cleanup
#
	rm -f $TMP

@sea, just for the fun of it, some comments:

  • use ping6 to ping IPv6 addresses
  • There's only one IP_PRE, so the while loop might be redundant. maybe:
IP_PRE=$(ip addr | awk -vFLT=" " '/ 127\./ {next} $0 ~ "inet" FLT {sub (/[^.]*$/, "", $2); print $2}')
  • maybe a one-liner for range:
for r in $(for i; do [[ "$i" =~ "-" ]] && echo -n "$(seq -s" " ${i/-/ 1 }) " || echo -n "$i "; done)
   do ...