I'm trying to figure out how to edit this script so it will validate an IP range instead of just one IP, i.e. 192.168.1.0/24.
echo "Target IP Address range or specific IP: "
read IPaddr
#IPv4 Validation
is_ip(){
local ip=$1
if expr "$ip" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null;then
for i in 1 2 3 4;do
if [ $(echo "$ip" | cut -d. -f$i) -gt 255 ];then
return 1
fi
done
return 0
else
return 1
fi
}
#Test User-inputted IPv4 Address
is_ip "$IPaddr"
if [[ $? -eq 0 ]]; then
echo "Valid IP address/range"
else
echo "Invalid IPv4"
exit 6
fi
This script seems to do what you want if I've understood your question properly.
#!/bin/bash
locInput="$1"
locIP=${locInput%\/*}
if [[ $locInput = #(*/*) ]];then
locRange=${locInput#*\/}
fi
function is_ip
{
if [[ $locIP == ?([0-9])+([0-9])\.?([0-9])+([0-9])\.?([0-9])+([0-9])\.?([0-9])+([0-9]) ]]; then
locVerif=(${locIP//./ })
for i in ${locVerif[*]}; do
if [[ $i -lt 0 || $i -gt 255 ]]; then
return 1
fi
done
if [[ -n $locRange && ($locRange -lt 0 || $locRange -gt 31) ]]; then
return 1
fi
return 0
else
return 1
fi
}
is_ip
if [[ $? -eq 1 ]]; then
echo "Wrong IP/Range"
else
echo "Good IP/Range"
fi
Hope it can help.
Related
I'm writing a function in shell script to check if the two numbers are Palindromes but I am getting an error, It is showing error in line 18 command not found. Please help me how can I remove this error.
#!/bin/bash
echo "Enter two number:"
read a
read b
for num in $a $b;
do
x=$x$sep$num
sep=" "
done
y=$x
num1=$a
num2=$b
rem=""
rev=0
for word in $y;
do
checkPalindrome $word
if [ $? -eq 0 ]
then
echo "$word is palindrome"
fi
done
checkPalindrome() {
local s=$1
for i in $s ;
do
while [ $i -gt 0]
do
rem=$(($i%10));
rev=$(($rev*10+$rem));
i=$(($i / 10));
done
done
if [[ $rev -eq $num1 && $rev -eq $num2 ]]
then
return 0;
else
return 1;
fi
}
You need to provide your checkPalindrome() definition before you use it, as below:
#!/bin/bash
checkPalindrome() {
local s=$1
for i in $s
do
while [ "$i" -gt 0 ]
do
rem=$((i%10))
rev=$((rev*10+rem))
i=$((i / 10))
done
done
if [[ $rev -eq $num1 && $rev -eq $num2 ]]
then
return 0
else
return 1
fi
}
echo "Enter two number:"
read -r a
read -r b
for num in $a $b
do
x="$x$sep$num"
sep=" "
done
y="$x"
num1="$a"
num2="$b"
rem=""
rev=0
for word in $y;
do
if checkPalindrome "$word"
then
echo "$word is palindrome"
fi
done
You could consider the input as string (you don't have to restrict it to be an integer)
#!/bin/bash
is_palindrome() {
local arg=$1 i j
for ((i = 0, j = ${#arg} - 1; i < j; ++i, --j)); do
[[ ${arg:i:1} = "${arg:j:1}" ]] || return
done
}
read -r -p 'Enter two words: ' a b
for word in $a $b; do
is_palindrome "$word" && echo "$word is palindrome"
done
I have a small piece of code which checks IP address validity :
function valid_ip()
{
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then
stat=1
else
stat=0
fi
fi
return $stat
}
But I am having problems with its usage in bash conditionals. I have tried many techniques to test its return value but most of them fail on me.
if [[ !$(valid_ip $IP) ]]; then
if [[ $(valid_ip IP) -eq 1 ]]; then
etc. etc. Can anyone suggest what should I do here ?
EDIT
Following your suggestions I have used something like :
if valid_ip "$IP" ; then
... do stuff
else
perr "IP: \"$IP\" is not a valid IP address"
fi
and I get errors like
IP: "10.9.205.228" is not a valid IP address
The return code is available in the special parameter $? after the command exits. Typically, you only need to use it when you want to save its value before running another command:
valid_ip "$IP1"
status1=$?
valid_ip "$IP2"
if [ $status1 -eq 0 ] || [ $? -eq 0 ]; then
or if you need to distinguish between various non-zero statuses:
valid_ip "$IP"
case $? in
1) echo valid_IP failed because of foo ;;
2) echo valid_IP failed because of bar ;;
0) echo Success ;;
esac
Otherwise, you let the various operators check it implicitly:
if valid_ip "$IP"; then
echo "OK"
fi
valid_IP "$IP" && echo "OK"
Here is a simple, idiomatic way of writing valid_ip:
valid_ip () {
local ip=$1
[[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] && {
IFS='.' read a b c d <<< "$ip"
(( a < 255 && b < 255 && c < 255 && d << 255 ))
}
}
There are two expressions, the [[...]] and the { ... }; the two are joined by &&. If the first fails, then valid_ip fails. If it suceeds, then the second expression (the compound statement) is evaluated. The read splits the string into four variables, and each is tested separately inside the arithmetic expression. If all are true, then the ((...)) succeeds, which means the && list succeeds, which means that valid_ip succeeds. No need to store or return explicit return codes.
No parentheses needed if the exit status is inspected:
if valid_ip $IP ; then
...
Just call the function in the way you would call any other command.
I've been playing with bash scripting for 40'ish days with 0 experience so forgive me if my code looks like crap. I have a script that will take the configured NTP servers out of the /etc/ntp.conf file (/root/ntp.conf for testing)
NTPSRVCounter=1
echo "--- NTP Configuration ---"
echo " "
while read -r line; do
if [ $NTPSRVCounter == 1 ] ; then
echo "Primary NTP: $line"
SEDConfiguredNTP1="$(echo $line | sed 's/\./\\./g')"
((NTPSRVCounter++))
echo " "
else
SEDConfiguredNTP2="$(echo $line | sed 's/\./\\./g')"
echo "Secondary NTP: $line"
echo ""
fi
done < <(grep -o -P '(?<=server ).*(?= iburst)' /root/ntp.conf)
And asks you if you want to change it with a case statement:
echo "Do you wish to change it? [Y/n]"
NTPSRVCounter2=1
read opt
case $opt in
Y|y) read -p "Enter in your primary NTP server: " -e -i '0.debian.pool.ntp.org' UserInputNTP1
read -p "Enter in your secondary NTP serer: " -e -i '1.debian.pool.ntp.org' UserInputNTP2
for NTP in "$UserInputNTP1" "$UserInputNTP2" ; do
is_fqdn "$NTP"
if [[ $? == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $? == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi
done
;;
N|n) return 0
;;
*) echo "I don't know what happened, but, eh, you're not supposed to be here."
;;
esac
The problem is with the "elif" statement and the function "is_fqdn" on the second run of the function. If I put "bash -x" on the script and run it, I see "is_fqdn" returning 0 on both runs of the function, but the elif statement "$?" is coming up as 1 instead of 0.
The two functions used are below. Have to validate NTP addresses as either valid domain names or I.P. addresses, right? :)
is_fqdn() {
hostname=$1
if [[ "$hostname" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
valid_ip "$hostname"
elif [[ "$hostname" == *"."* && "$hostname" != "localhost." && "$hostname" != "localhost" ]] ; then
return 0
else
return 1
fi
host $hostname > /dev/null 2>&1 || return 1
}
valid_ip(){
local stat=1
local ip=$1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS="."
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return "$stat"
}
The condition in your if sets the value of $?, and that is what's used by the condition in the elif part, not the return value of is_fqdn. You need to save the value if you want to use it in multiple places:
is_fqdn "$NTP"
is_fqdn_rv=$?
if [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi
COUNTER=0
let COUNTER=COUNTER+1
count=`ssh -i /var/www/.ssh/id_rsa_root -o stricthostkeychecking=no $host $cmd`
count1=`echo $count | awk '{print $4}'`
printf "count1 : $count1\n"
result1=${count1/.*}
if [ "$result1" -ge "0" ]; then
echo $host
else
echo $host
exit
fi
If the value of $result1 is INTEGER and greater than zero, it'll goto IF loop (works fine for me)
But when it is not INTEGER, it is coming to else loop (which it is suppose to do) with the following error in the Output
line 55: [: : integer expression expected
but i dont want the above error in my output. I tried to use 2>/dev/null with this but no luck.
please help!
If you want to handle an empty result gracefully, check for it explicitly:
if [ -z "$result1" ]; then
: "ignoring empty string"
elif [ "$result1" -ge 0 ]; then
printf '%s\n' "$host"
else
printf '%s\n' "$host"
exit
fi
You could also check if result1 is a valid integer before making arithmetic comparisons:
function isNumber () {
[[ $1 =~ ^-?[0-9]+$ ]]
}
if ! isNumber "$result1"; then
echo "not a number"
elif [ "$result1" -ge "0" ]; then
echo "null or positive"
else
echo "negative"
fi
Change if [ "$result1" -ge "0" ]; then to
if (( result1 >= 0 )); then
This syntax won't throw any errors if result1 isn't defined (or empty) or happen to be a string somehow.
I have a small piece of code which checks IP address validity :
function valid_ip()
{
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then
stat=1
else
stat=0
fi
fi
return $stat
}
But I am having problems with its usage in bash conditionals. I have tried many techniques to test its return value but most of them fail on me.
if [[ !$(valid_ip $IP) ]]; then
if [[ $(valid_ip IP) -eq 1 ]]; then
etc. etc. Can anyone suggest what should I do here ?
EDIT
Following your suggestions I have used something like :
if valid_ip "$IP" ; then
... do stuff
else
perr "IP: \"$IP\" is not a valid IP address"
fi
and I get errors like
IP: "10.9.205.228" is not a valid IP address
The return code is available in the special parameter $? after the command exits. Typically, you only need to use it when you want to save its value before running another command:
valid_ip "$IP1"
status1=$?
valid_ip "$IP2"
if [ $status1 -eq 0 ] || [ $? -eq 0 ]; then
or if you need to distinguish between various non-zero statuses:
valid_ip "$IP"
case $? in
1) echo valid_IP failed because of foo ;;
2) echo valid_IP failed because of bar ;;
0) echo Success ;;
esac
Otherwise, you let the various operators check it implicitly:
if valid_ip "$IP"; then
echo "OK"
fi
valid_IP "$IP" && echo "OK"
Here is a simple, idiomatic way of writing valid_ip:
valid_ip () {
local ip=$1
[[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] && {
IFS='.' read a b c d <<< "$ip"
(( a < 255 && b < 255 && c < 255 && d << 255 ))
}
}
There are two expressions, the [[...]] and the { ... }; the two are joined by &&. If the first fails, then valid_ip fails. If it suceeds, then the second expression (the compound statement) is evaluated. The read splits the string into four variables, and each is tested separately inside the arithmetic expression. If all are true, then the ((...)) succeeds, which means the && list succeeds, which means that valid_ip succeeds. No need to store or return explicit return codes.
No parentheses needed if the exit status is inspected:
if valid_ip $IP ; then
...
Just call the function in the way you would call any other command.