IP address calculator script - bash

I need to write a Bash script that converts IP address from CIDR format to quad-style.
I must enter the IP address in the following style:
10.10.10.10/24
If I entered it in this style:
10.10.10.10 255.255.255.0
an error message should appear.
I tried this script:
#!/bin/bash
echo "enter you ip"
read ip
case $ip in
*.*.*.*/*)
b=`echo $ip | cut -d/ -f1`
a=`echo $ip | cut -d/ -f2`
if [ $a -eq 24 ];then
echo "$b 255.255.255.0"
elif [ $a -eq 25 ];then
echo "$b 255.255.255.128"
elif [ $a -eq 26 ];then
echo "$b 255.255.255.192"
elif [ $a -eq 27 ];then
echo "$b 255.255.255.224"
elif [ $a -eq 28 ];then
echo "$b 255.255.255.240"
elif [ $a -eq 29 ];then
echo "$b 255.255.255.248"
elif [ $a -eq 30 ];then
echo "$b 255.255.255.252"
elif [ $a -eq 31 ];then
echo "$b 255.255.255.254"
elif [ $a -eq 32 ];then
echo "$b 255.255.255.255"
fi
case $ip in
*.*.*.* *.*.*.*)
echo "enter a valid address"
esac
but I get an error
./ipcalculater2.sh: line 32: syntax error near unexpected token `...'
./ipcalculater2.sh: line 32: ` ... ...)'
What is wrong with my script?

Here's an example of four ways one might convert from CIDR to netmask notation in bash.
#!/usr/bin/env bash
if [[ "$1" != *.*.*.*/* ]]; then
echo "Usage: ${0##*/} ip.ad.dr.ess/bits" >&2
exit 1
fi
# separate our input into network and mask using IFS
IFS=/ read network bits <<<"$1"
# build a temporary variable $s that we'll use to build $bitmask
# for the first three variants...
read zeros <<< $(printf '%032s' 0)
s=${zeros//0/1}${zeros}
# convert the mask into a 32-digit binary number
bitmask=${s:$((32-bits)):32}
# Four different methods for generating the netmask...
# The first two use `bc` and `dc`. One is likely installed on your system.
read mask1 <<<$( dc -e "2i $(fold -w8 <<<"$bitmask " | paste -sdp -)" | paste -sd. - )
read mask2 <<<$( fold -w8 <<<"$bitmask" | paste - | bc -e 'ibase=2' | paste -sd. - )
# And if dc and bc are unavailable, or you prefer not to spawn subshells, or
# risk missed dependencies, you can do this in pure bash with a few more lines.
unset mask3
for ((i=0;i<4;i++)); do
mask3+="${mask3:+.}$((2#${bitmask:$((8*i)):8}))"
done
# And finally, instead of a loop, you can do the same thing with fancy math:
# This variant avoides the need for $bitmask, set above.
mask4="$(( 2**32 - (1 << (32-$bits)) ))"
mask4=$(( mask4/2**24 )).$(( mask4/2**16 %256 )).$(( mask4/2**8 % 256 )).$(( mask4 % 256 ))
# Print the results, obviously.
echo "network=$network"
echo "netlength=$bits"
echo "netmask via 'dc': $mask1"
echo "netmask via 'bc': $mask2"
echo "netmask via loop: $mask3"
echo "netmask via math: $mask4"
I've included code that works in each of dc and bc, since I can't predict which calculator will be available on your system. These calculators are used for base conversion. If you don't mind your script being a little longer, you can avoid spawning external tools (like fold and paste and the calculator) using the method that generates $netmask3.
Note that in the third case, this usage of bc depends on availability of a -e option which exists in *BSD. Use another variant if you're using GNU bc (i.e. you're in Linux.)
You can of course adjust the output so that it meets your needs, as well as trim the parts of the script you're not using.

Please check for this corrections:
#!/bin/bash
echo "enter you ip"
read ip
case $ip in
*.*.*.*/*)
b=`echo $ip | cut -d/ -f1`
a=`echo $ip | cut -d/ -f2`
if [ $a -eq 24 ];then
echo "$b 255.255.255.0"
elif [ $a -eq 25 ];then
echo "$b 255.255.255.128"
elif [ $a -eq 26 ];then
echo "$b 255.255.255.192"
elif [ $a -eq 27 ];then
echo "$b 255.255.255.224"
elif [ $a -eq 28 ];then
echo "$b 255.255.255.240"
elif [ $a -eq 29 ];then
echo "$b 255.255.255.248"
elif [ $a -eq 30 ];then
echo "$b 255.255.255.252"
elif [ $a -eq 31 ];then
echo "$b 255.255.255.254"
elif [ $a -eq 32 ];then
echo "$b 255.255.255.255"
fi
;;
*.*.*.*\ *.*.*.*)
echo "enter a valid address"
;;
esac

Related

How to filter only digits from a string in bash shell scripting?

I want to measure temperature of Raspberry pi 3, and change the background color of the text accordingly. As the code goes, we can print the temperature on the display. Now, I want to filter the digits only out of the text. And use that in the if condition. The source code goes like this:
#!/bin/bash
measurement()
{
i=1
echo "Reading Temperature"
echo "Updating time is set to $1"
while [ $i -eq 1 ]; do
temp="$(vcgencmd measure_temp | cut -d= -f 2 | cut -d\' -f 1)"
tput setaf 7
if [[ $temp -ge 70 ]]; then
tput setab 1
echo -ne "Temperature = $temp\r"
elif [[ $temp -ge 65 && $temp -le 69 ]]; then
put setab 3
echo -ne "Temperature = $temp\r"
elif [[ $temp -ge 60 && $temp -le 64 ]]; then
tput setab 2
echo -ne "Temperature = $temp\r"
elif [[ $temp -ge 55 && $temp -le 59 ]]; then
tput setab 6
echo -ne "Temperature = $temp\r"
else
tput setab 4
echo -ne "Temperature = $temp\r"
fi
sleep $1
done
}
if [ -n "$1" ]; then
sleep_time=$1
measurement $sleep_time
else
read -p "Enter the Update Time: " sleep_time
measurement $sleep_time
fi
enter image description here
The typical tools for removing unwanted characters from text are tr and sed (and manipulating variables directly in the shell, with constructs like ${var##text}, but unless you want to use shell specific extensions those provide limited capability). For your use case, it seems easiest to do:
temp="$(vcgencmd measure_temp | tr -cd '[[:digit:]]')"
This simply deletes (-d) all characters that are not (-c) a member of the character class digit.
You could use a builtin string operation to print just the digits and periods in a variable. The following is a global substring replacement of any character that is not a digit or period with an empty string:
echo "${temp//[^0-9.]/}"

line 14: [: 55.5: integer expression expected --shell error

I'm getting error for line 8,11,14,17 .
the program is
#!/bin/sh
read a
b=$(grep -i $a TeamScore.txt| awk 'BEGIN{FS =" "}{print ($2+$4)/2}')
echo "the avg is $b"
if [ "$b" -ge 80] #line8
then
echo "1st class "
elif [ "$b" -lt 80 ] || [ "$b" -ge 70 ] #line11
then
echo "2nd class"
elif [ "$b" -lt 70 ] || [ "$b" -ge 60 ] #line14
then
echo "3rd class"
elif [ "$b" -lt 60 ] #line17
then
echo "fail"
else
echo "code not working"
fi
I'm new to unix and shell scripting and i would like to whats wrong and how can i fix it.the TeamScore.txt contains a table of names and their score(for 2 exams).
The problem is that the test command only understands integers, but you're setting b to 55.5, which contains a fraction. Change the awk command to round it down.
b=$(grep -i $a TeamScore.txt| awk 'BEGIN{FS =" "}{print int(($2+$4)/2)}')
You also need a space before ] on line #8.
Line 8: add an extra space:
if [ "$b" -ge 80 SPACE_HERE_REQUIRED ]
Line11, line14 and line17: number operators can't be compared with strings, so use $b instead of "$b", so, for example, use this
if [ $b -ge 80 ]
instead of:
if [ "$b" -ge 80 ]

Having difficulty writing a script to sort words

I am dealing with sorting words in Bash according to a given argument. I am given either argument -r, -a , -v or -h and according to it there are options to sort the words, as you can see at my "help".
Somehow, if I pass the argument -r it creates an error. I really don't understand what I am doing wrong, as if[["$arg"=="-a"]] works, but I have to use case somehow.
Here is my code:
#!/bin/bash
# Natalie Zubkova , zubkonat
# zubkonat#cvut.fel.cz , LS
#help
help="This script will calculate occurances of words in a given file, and it will sort them according to the given argument in following order> \n
without parametre = increasing order according to a number of occurance\n
-r = decreasing order according to a number of occurance\n
-a = in alphabetical increasing order\n
-a -r = in alphabetical decreasing order\n
There are also special cases of the given parametre, when the script is not sorting but:\n
-h = for obtaining help \n
-v = for obtaining a number of this task "
# this function will divide a given chain into a words, so we can start calculating the occurances, we also convert all the capital letters to the small ones by - tr
a=0;
r=0;
EXT=0;
if [ "$1" == "-h" ]; then
echo $help
exit 0
fi
if [ "$2" == "-h" ]; then
echo $help
exit 0
fi
if [ "$1" == "-v" ]; then
echo "5"
exit 0
fi
if [ "$2" == "-v" ]; then
echo "5"
exit 0
fi
function swap {
while read x y; do
echo "$y" "$x";
done
}
function clearAll {
sed -e 's/[^a-z]/\n/gI' | tr '[A-Z]' '[a-z]' | sort | uniq -c |awk '{i++; if(i!=1) print $2" "$1}' #swap
}
for arg do
case "$arg" in
"-a")
a=1
;;
"-r")
r=1
;;
"-v")
echo "5" #number of task is 5
exit 0
;;
"-h")
echo $help
exit 0
;;
"-?")
echo "invalid parametre, please display a help using argument h"
exit 0
;;
esac
done
#Sort according to parametres -a and -r
function sortWords {
if [[ a -eq 1 ]]; then
if [[ r -eq 0 ]]; then
clearAll | sort -nk1
fi
fi
if [[ a -eq 1 ]]; then
if [[ r -eq 1 ]]; then
clearAll | sort -nk1 -r
fi
fi
if [[ r -eq 1 ]]; then
if [[ a -eq 0 ]]; then
clearAll | sort -nk2 -r
fi
fi
if [[ a -eq 0 ]]; then
if [[ r -eq 0 ]]; then
clearAll | sort -nk2
fi
fi
}
#code is from Stackoverflow.com
function cat-all {
while IFS= read -r file
do
if [[ ! -z "$file" ]]; then
cat "$file"
fi
done
}
#histogram
hist=""
for arg do
if [[ ! -e "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
elif [[ ! -f "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
elif [[ ! -r "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
fi
done
for arg do
hist="$hist""$arg""\n"
done
echo -e "$hist" | cat-all | sortWords
exit $EXT;
Here is what our upload system which does some test to see if our program works says:
Test #6
> b5.sh -r ./easy.txt
ERROR: script output is wrong:
--- expected output
+++ script stdout
## --- line 1 (167 lines) ; +++ no lines ##
-the 89
-steam 46
-a 39
-of 37
-to 35
...
script written 484 lines, while 484 lines are expected
script error output:
A FILE DOESNT EXIST
cat: invalid option -- 'r'
Try `cat --help' for more information.
script exit value: 1
ERROR: Interrupted due to failed test
If anyone could help me I would really appreciate it.
You forgot to move the parameter index position with shift:
"-r")
r=1
shift
;;
shift above moves to the next command line arg: ./easy.txt in your case.
Without it, read -r file will read -r instead of the file name.

Using shell script which checks if the user has logged in twice into Unix server and displays the details of the users

Here I want to display logname of my system, if I logged in twice.
But displays many other lognames also.
v1=`who | wc -l`
c=`expr $v1 - 1`;
count=0
declare -a val
val=`who | cut -d" " -f1`
echo "$c"
temp=0
while [ $temp -le $c ]
do
if [ "{$val[$v]}" -eq `logname` ]
then
count=`expr $count + 1`
if [ $count -eq 2 ]
then
echo "`logname`, `uname`, `hostname`"
else
echo "No one";
fi
temp=`expr $temp + 1`
echo $temp
fi
done
Kindly check my code...

Float conditional in bash

in bash I need to compare two float numbers, one which I define in the script and the other read as paramter, for that I do:
if [[ $aff -gt 0 ]]
then
a=b
echo "xxx "$aff
#echo $CX $CY $CZ $aff
fi
but I get the error:
[[: -309.585300: syntax error: invalid arithmetic operator (error token is ".585300")
What is wrong?
Thanks
Using bc instead of awk:
float1='0.43255'
float2='0.801222'
if [[ $(echo "if (${float1} > ${float2}) 1 else 0" | bc) -eq 1 ]]; then
echo "${float1} > ${float2}"
else
echo "${float1} <= ${float2}"
fi
use awk
#!/bin/bash
num1=0.3
num2=0.2
if [ -n "$num1" -a -n "$num2" ];then
result=$(awk -vn1="$num1" -vn2="$num2" 'BEGIN{print (n1>n2)?1:0 }')
echo $result
if [ "$result" -eq 1 ];then
echo "$num1 greater than $num2"
fi
fi
Both test (which is usually linked to as [)and the bash-builtin equivalent only support integer numbers.
Use bc to check the math
a="1.21231"
b="2.22454"
c=$(echo "$a < $b" | bc)
if [ $c = '1' ]; then
echo 'a is smaller than b'
else
echo 'a is larger than b'
fi
I would use awk for that:
e=2.718281828459045
pi=3.141592653589793
if [ "yes" = "$(echo | awk "($e <= $pi) { print \"yes\"; }")" ]; then
echo "lessthanorequal"
else
echo "larger"
fi
The simplest solution is this:
f1=0.45
f2=0.33
if [[ $f1 > $f2 ]] ; then echo "f1 is greater then f2"; fi
which (on OSX) outputs:
f1 is greater then f2
Here's another example combining floating point and integer arithmetic (you need the great little perl script calc.pl that you can download from here):
dateDiff=1.9864
nObs=3
i=1
while [[ $dateDiff > 0 ]] && [ $i -le $nObs ]
do
echo "$dateDiff > 0"
dateDiff=`calc.pl $dateDiff-0.224`
i=$((i+1))
done
Which outputs
1.9864 > 0
1.7624 > 0
1.5384 > 0

Resources