BASH search for multiple IP's in table - bash

This is a continuation of a script I got help on a few weeks ago. I got everything working, unfortunately the scenario has changed a bit and I'm under a little pressure to get this up and running so I was hoping someone here would help me quickly modify this script.
Here are the basics. The purpose of the script is to recapture a specific floating IP. Due to system limitations, the only way to do this currently is by kinda playing the lottery... The script requests a pool of floating IP's and puts them in a table that looks like this:
+------------+-----------+----------+---------------+
| Ip | Server Id | Fixed Ip | Pool |
+------------+-----------+----------+---------------+
| 10.10.10.1 | | - | floating-pool |
| 10.10.10.2 | | - | floating-pool |
| 10.10.10.3 | | - | floating-pool |
| 10.10.10.4 | | - | floating-pool |
| 10.10.10.5 | | - | floating-pool |
+------------+-----------+----------+---------------+
The script then checks to see if the floating IP we are looking for is in that table, ie has been captured. If not, the script returns all IP's back to the pool and tries again. If the address we are looking for has been captured, then the script drops all other IP's and terminates.
The current version of this script works great to capture a single IP, but now we need it to capture several IP's. Here is the old single IP version:
#!/bin/bash
# Floating IP Reclaimer
################# CONFIG ##################
float="10.10.10.3"
tenantid="blah"
###########################################
# Start
clear
loop=true
if ! [ "$tenantid" = "$OS_TENANT_ID" ]; then
echo "ERROR - Be sure you have sourced the proper tenant ID!"
else
l=1
while $loop; do
printf "Floating IP Reclaimer\n\n"
printf "Requesting address block...\n"
for ((i=1;i<=5;i++));
do
nova floating-ip-create floating-pool > /dev/null 2>&1
done
printf "Checking for matches...\n"
nova floating-ip-list > /tmp/block
while read garbage1 ip garbage2;
do
if [ "$ip" != "$float" ]; then
printf "Releasing $ip\n"
nova floating-ip-delete "$ip" > /dev/null 2>&1
else
loop=false
fi
done < <(tail -n +4 /tmp/block | head -n -1)
printf "\nFloating IP blocks searched: "$l
l=$((l+1))
clear
done
printf "\nFloating IP reclaimed!\n\n"
fi
Thank you everyone for the help. I'm working on a solution as we speak. Unfortunately, sometimes I don't work too well under pressure.
Thanks!

Try this on for size (it hasn't been tested). I know it's not bash, but it should get the job done
#!/usr/bin/python
import os,time
import novaclient.client as nvclient
class FloatingIpManager():
def __init__(self,desired_addresses=[],sleep=5):
self.ips = desired_addresses
self.nova = get_nova_client()
self.sleep = sleep
def get_nova_client(self,env=os.environ):
d = {}
d['username'] = env['username']
d['api_key'] = env['password']
d['auth_url'] = env['auth_url']
d['project_id'] = env['tenant_name']
return nvclient.Client('2',**d)
def get_float(self,address=None,pool=None):
while True:
try:
flip = self.nova.floating_ips.create(pool)
if flip.ip in self.ips or address == None:
return True
else:
self.release_float(flip)
except Exception as e:
print e
time.sleep(self.sleep)
def release_float(self,flip):
return self.nova.floating_ips.delete(flip)
def reclaim_all(self,addresses=None):
if addresses == None:
addresses = self.ips
for i in self.ips:
get_float(i)
if __name__ == '__main__':
nova = get_nova_client()
reclaimer = FloatingIpManager(['192.168.100.1'])
reclaimer.reclaim_all()

Your bash answer. Call it with the IP's you want as arguments, like "reclaimer 192.168.1.1 192.168.1.2 192.168.1.3"
#!/bin/bash
# Floating IP Reclaimer
################# CONFIG ##################
#float="10.10.10.3"
tenantid="blah"
###########################################
# Start
clear
loop=true
let count=$#-1
if ! [ "$tenantid" = "$OS_TENANT_ID" ]; then
echo "ERROR - Be sure you have sourced the proper tenant ID!"
else
l=1
while $loop; do
printf "Floating IP Reclaimer\n\n"
printf "Requesting address block...\n"
for ((i=1;i<=5;i++));
do
nova floating-ip-create floating-pool > /dev/null 2>&1
done
printf "Checking for matches...\n"
nova floating-ip-list > /tmp/block
while read garbage1 ip garbage2;
do
for float in $#; do
if [ "$ip" != "$float" ]; then
printf "Releasing $ip\n"
found=false
else
let i=i+1
continue 2
fi
done
nova floating-ip-delete "$ip" > /dev/null 2>&1
done < <(tail -n +4 /tmp/block | head -n -1)
printf "\nFloating IP blocks searched: "$l
l=$((l+1))
clear
if [ i -eq count ]; then
loop=false
fi
done
printf "\nFloating IP reclaimed!\n\n"
fi

Related

The command 'startx' only works when entered in the terminal and not from a bash script

I wrote a rule in /etc/udev.rules.d/ that runs a bash script '/home/pi/startx.sh' if a device is plugged into my Raspberry Pi 4. This rule works, in the sense that if in my script I write
#!/bin/bash
touch test.txt
the test.txt file is actually created each time I insert e.g. a keyboard. Now I would like this script to run the startx command as the user 'pi'.
In practice, I want the Raspberry to start in console mode and starts the 'pi' user's desktop only if this device is inserted through the script startx.sh.
Now if in my script I write
#!/bin/bash
startx
it doesn't work and the pi's Xorg Desktop doesn't start.
If I try to run it from ssh it says (well, i dont care to start it via ssh, it was only a try):
parse_vt_settings /dev/tty0 (permission denied)
The really absurd thing is that if I run the startx command from the keyboard in front of the monitor startx works without problems (always as user pi).
What's more, if I run the script ./startx.sh from the console when I'm physically in front of the monitor it works perfectly.
It is important to specify that I want the Desktop to start as the user 'pi' and not as root or other users.
So the command sudo startx is not suitable (which works by giving me obviously another Desktop that is not pi's).
I also don't want to change any permissions on tty, video, etc. because if it works from the console when I'm physically in front of the monitor, I don't understand why it can't work from a bash script.
OS: Raspbian GNU/Linux 10 (buster)
Raspberry pi 4
I tried modifying the script like this:
#!/bin/bash -l
startx
or
#!/bin/bash
sudo -u pi startx
or
#!/bin/bash -l
sudo -u pi startx
and also
#!/bin/bash
sudo -i -u pi xinit
without any result.
"startx" will start the Desktop, as long as the Desktop is not already running.
You are facing either
a conflict with a previous Desktop instance, or
you have not correctly identified the device that the system believes to be the console where the Desktop "must" be displayed, or
you haven't correctly defined the device for a dual-head Pi, or
the configuration for that target device is malformed as an intended X display.
To help in assisting you with identifying process parents and dependencies, below is a script (reused/modified) to display the processes in a hierarchy tree. The original was simply called pt. I call my own pt.sh.
#!/bin/sh
##################################################################################
###
### $Id: pt.sh,v 2.4 2022/08/17 22:27:05 root Exp $
###
### Script to print a process tree on stdout.
### - easy to see relationships between processes with this script
### Synt: pt [opts] [startPID]
### Opts: -h,H,-V : help,HELP,version
### -w width: screen width
### -o type : output type: 1, 2, or 3 (def 3)
### Parm: startPID: show tree starting at this PID (def: 1)
###
### #(#) pt - display Process Table "Tree"
###
### Original Author: William J. Duncan (prior to May 7 1996)
###
### Synopsis:
### pt [opts] [startPID] | less # (or whatever your fav pager is)
###
### Notes:
### - all recent implementations of awk I have seen have recursion.
### It is a requirement. This is a nice little example of using
### recursion in awk.
###
### - under bsd, there was no real happy mix of options which
### would pick up a user's name, and do everything else we wanted.
### (eg. need to pick up PPID for example)
### So we need to do a separate search through the passwd entries
### ourselves and build a lookup table, or alternatively run ps
### twice.
###
### - notice the ugliness of 3 separate sets of quotes required in
### the line:
### while ("'"$GETPASSWD"'" | getline > 0)
###
### The inside pair of quotes keeps the 2 tokens for the command
### together. The pair of single quotes escapes from within the
### awk script to the "outside" which is the shell script. This
### makes the shell variable "$GETPASSWD" available for use with-
### in the awk script as a literal string. (Which is the reason
### for the outside pair of double quotes.)
###
### - This is the general format of including awk scripts within
### the shell, and passing ENVIRONMENT variables down. -wjd
###
##################################################################################
##################################################################################
###
### Mods by E. Marceau, Ottawa, Canada
###
### - Added logic to determine max length of username for proper display of that field
###
##################################################################################
TMP=/tmp/`basename "$0" ".sh" `.$$
set -u
## Constants
rcsid='$Id: pt.sh,v 2.4 2022/08/17 22:27:05 root Exp $'
P=`basename $0`;
## This command should list the password file on on "all" systems, even
## if YP is not running or 'ypcat' does not exist.
## List the local password file first because the UIDS array is assigned
## such that later entries override earlier entries.
if [ -z "`which ypcat 2>>/dev/null `" ]
then
GETPASSWD="(cat /etc/passwd)"
else
GETPASSWD="(ypcat passwd 2>/dev/null)"
fi
## Name: usage; Desc: standard usage description function
usage() { awk 'NF==0{if(n++=='${1:-0}')exit}0==0'<$0; }
maxWidth=0
## check for options
set -- `getopt ehHVw:o: ${*:-}`
test $? -ne 0 && usage 0 && exit 9
for i in $*; do
case $i in
-e) maxWidth=1 ; COLS=512 ; shift ;;
-h) usage 0 && exit 9 ;;
-H) usage 1 && exit 9 ;;
-V) echo "${P} ${rcsid}"|cut -d' ' -f1,4-5; exit;;
-w) COLS=$2 ; shift 2 ;;
-o) outtype=$2 ; shift 2 ;;
--) shift ; break ;;
esac
done
## initialize
startpid="${1:-1}"
SYSTEM=${SYSTEM:-`uname`}
outtype="${outtype:-3}"
case ${SYSTEM} in
# XENIX) # or any other sys5 i think
# PS=/bin/ps
# AWK=/bin/awk
# PSFLAGS=-ef
# SYSTEM=sys5
# SIZE='/bin/stty size'
# ;;
# SunOS) # bsd flavours of ps
# os=`uname -r | cut -c1`
# PS=/bin/ps
# AWK=nawk
# if test "$os" = "4"; then
# PSFLAGS=-axjww
# SYSTEM=bsd
# SIZE='/bin/stty size'
# else
# PSFLAGS=-ef
# SYSTEM=sys5
# SIZE='/usr/ucb/stty size'
# fi
# ;;
# HP-UX)
# PS=/bin/ps
# AWK=/usr/bin/awk
# PSFLAGS=-ef
# SYSTEM=sys5
# SIZE='/bin/stty size'
# ;;
Linux)
PS=/bin/ps
AWK=awk
PSFLAGS=-axjww
SYSTEM=bsd
SIZE='/bin/stty size'
;;
*)
PS=/bin/ps
AWK=awk
PSFLAGS=-axjww
SYSTEM=bsd
SIZE='/bin/stty size'
;;
esac
COLShere=`${SIZE} | awk '{print $2}' `
COLS=${COLS:-$COLShere}
COLS=${COLS:-80}
echo "\t [1] ${COLS}"
${PS} ${PSFLAGS} |
${AWK} -v maxWidth="${maxWidth}" 'BEGIN{ lowestPID=9999 ;
FS = ":" ;
while ("'"${GETPASSWD}"'" | getline > 0){
UIDS[ $3 ] = $1 ;
} ;
UIDS[ 0 ] = "root" ; # fix for "extra" root accounts
for ( var in UIDS ){
lenT=length( UIDS[var] ) ;
if ( lenT > lenM ){
lenM=lenT ; # longest=UIDS[var] ;
} ;
} ;
printf("%6s %6s %4s %-"lenM"s %s\n", "PID", "PPID", "TTY", "USER", "COMMAND" ) ;
FS = " " ;
COLS='${COLS}' ;
SYSTEM="'${SYSTEM}'" ;
if (SYSTEM == "sys5"){
fpid = 2 ;
fppid = 3 ;
fuid = 1 ;
}else{
if (SYSTEM == "bsd"){
fpid = 2 ;
fppid = 1 ;
fuid = 8 ;
} ;
} ;
outtype ="'${outtype}'" ;
if (outtype == 1){
SPACES=".............................................................................................." ;
SPREAD=1 ;
CMD_PREFIX=" " ;
}else{
if (outtype == 2){
SPACES="||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" ;
SPREAD=1 ;
CMD_PREFIX="" ;
}else{
SPACES="| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |" ;
SPREAD=2 ;
CMD_PREFIX="" ;
} ;
} ;
} ;
NR==1 { title = $0 ; next } ;
# All others
{
if ( $fpid < lowestPID ){ lowestPID=$fpid ; } ;
LINE[ $fpid ] = $0 ; # Line indexed by PID
PCNT[ $fppid ]++ ; # Index into PPID
PPID[ $fppid, PCNT[$fppid] ] = $2 ; # Parent to Children unique
INDENT=0 ;
} ;
function doprint(s, a, name, i, nf, tty, cmd){
# the splitting and complications here are mostly for
# sys5, which a different number of fields depending on STIME
# field. Argh.
nf = split(s,a) ;
for (i=7; i <= nf; i++){
if (a[i] ~ /[0-9]:[0-9][0-9]/){
break # set i here
} ;
} ;
for (i++ ; i <= nf; i++){
name = name " " a[i] ;
} ;
if (a[fuid] in UIDS){
a[fuid] = UIDS[a[fuid]] ; # if username found
} ;
if (SYSTEM == "bsd"){ # if bsd
tty = a[5] ;
}else{ # sys5 2 possible formats
tty = (a[5] ~ /^[0-9]+:/) ? a[6] : a[7] ;
} ;
cmd = substr(SPACES,1,INDENT*SPREAD) CMD_PREFIX substr(name,2) ;
#if ( length(cmd) > COLS-27 && maxWidth == 0 ){
if ( length(cmd) > COLS-27 ){
cmd = substr(cmd,1,COLS-27) ;
} ;
printf("%6d %6d %4s %-"lenM"s %s\n", a[fpid], a[fppid], substr(tty,length(tty)-1), a[fuid], cmd ) ;
} ;
function dotree(pid) { # recursive
if (pid == 0) return
doprint(LINE[ pid ])
INDENT++
while (PCNT[pid] > 0) {
dotree(PPID[ pid, PCNT[pid] ] ) ; # recurse
delete PPID[ pid, PCNT[pid] ] ;
PCNT[pid]-- ;
} ;
INDENT-- ;
} ;
END{
if ( lowestPID > startpid ){ startpid=lowestPID ; } ;
dotree('${startpid}') ;
}' >${TMP}.initial
###########################################################################################################################
###
### Additional coding to present results with PID correctly sorted along with associated children also in sorted order.
###
###########################################################################################################################
head -1 ${TMP}.initial >${TMP}.head
tail --lines=+2 ${TMP}.initial | sort --key=1,1n --key=2,2n >${TMP}.remainder
cat ${TMP}.head
while [ true ]
do
line=`awk '{ if ( NR == 1 ){ print $0 } ; exit }' <${TMP}.remainder `
first=`echo "${line}" | awk '{ print $1 }' `
echo "${line}"
#get children
tail --lines=+2 ${TMP}.remainder | awk -v pid="${first}" '{ if ( $2 == pid ){ print $0 } ; }' >${TMP}.next
tail --lines=+2 ${TMP}.remainder | awk -v pid="${first}" '{ if ( $2 != pid ){ print $0 } ; }' >${TMP}.others
cat ${TMP}.next ${TMP}.others >${TMP}.remainder
if [ ! -s ${TMP}.remainder ] ; then break ; fi
done ### >${TMP}.new ;cat ${TMP}.new
exit 0
exit 0
exit 0

What's the easiest way to find multiple unused local ports withing a range?

What I need is to find unused local ports withing a range for further usage (for appium nodes). I found this code:
getPorts() {
freePort=$(netstat -aln | awk '
$6 == "LISTEN" {
if ($4 ~ "[.:][0-9]+$") {
split($4, a, /[:.]/);
port = a[length(a)];
p[port] = 1
}
}
END {
for (i = 7777; i < 65000 && p[i]; i++){};
if (i == 65000) {exit 1};
print i
}
')
echo ${freePort}
}
this works pretty well if I need singe free port, but for parallel test execution we need multiple unused ports. So I need to modify the function to be able to get not one free port, but multiple (depends on parameter), starting from the first found free port and then store the result in one String variable. For example if I need ports for three 3 devices, the result should be:
7777 7778 7779
the code should work on macOS, because we're using mac mini as a test server.
Since I only started with bash, it's a bit complicated to do for me
This is a bash code, it works fine on Linux, so if your Mac also runs bash it will work for you.
getPorts() {
amount=${1}
found=0
ports=""
for ((i=7777;i<=65000;i++))
do
(echo > /dev/tcp/127.0.0.1/${i}) >/dev/null 2>&1 || {
#echo "${i}"
ports="${ports} ${i}"
found=$((found+1))
if [[ ${found} -ge ${amount} ]]
then
echo "${ports:1}"
return 0
fi
}
done
return 1
}
Here is how to use use it and the output:
$ getPorts 3
7777 7778 7779
$ getPorts 10
7777 7778 7779 7780 7781 7782 7783 7784 7785 7786
Finding unused ports from 5000 to 5100:
range=(`seq 5000 5100`)
ports=`netstat -tuwan | awk '{print $4}' | grep ':' | cut -d ":" -f 2`
echo ${range[#]} ${ports[#]} ${ports[#]} | tr ' ' '\n' | sort | uniq -u

how to use shell script to convert row to column or some nice table

I got the following script from stack overflow :
#!/bin/sh
in_file=temp2.txt # Input file
params=6 # Parameters count
res_file=$(mktemp) # Temporary file
sep=' ' # Separator character
# Print header
cnt=0
for i in $(cat $in_file | head -$((params*2))); do
if [ $((cnt % 2)) -eq 0 ]; then
echo $i
fi
cnt=$((cnt+1))
done | sed ":a;N;\$!ba;s/\n/$sep/g" >>$res_file
# Parse and print values
cnt=0
for i in $(cat $in_file); do
# Print values, skip param names
if [ $((cnt % 2)) -eq 1 ]; then
echo -n $i >>$res_file
fi
if [ $(((cnt+1) % (params*2))) -eq 0 ]; then
# Values line is finished, print newline
echo >>$res_file
elif [ $((cnt % 2)) -eq 1 ]; then
# More values expected to be printed on this line
echo -n "$sep" >>$res_file
fi
cnt=$((cnt+1))
done
# Make nice table format
cat $res_file | column -t
#rm -f $res_file
But then i have about 100 + lines in it and i'm getting a error**"column: line too long"** as below :
****column: line too long**** GigabitEthernet0/0 GigabitEthernet1/0/3 GigabitEthernet1/0/5 GigabitEthernet1/0/10
GigabitEthernet1/0/19 GigabitEthernet1/0/33 GigabitEthernet1/0/2
GigabitEthernet1/0/4 GigabitEthernet1/0/7 GigabitEthernet1/0/18
GigabitEthernet1/0/30 GigabitEthernet1/0/44 GigabitEthernet1/0/46
GigabitEthernet1/1/3 GigabitEthernet2/0/1 GigabitEthernet2/0/5
GigabitEthernet2/0/9 GigabitEthernet2/0/14 GigabitEthernet2/0/18
GigabitEthernet2/0/31 GigabitEthernet2/0/34 GigabitEthernet2/0/36
GigabitEthernet2/0/40 GigabitEthernet2/1/3 GigabitEthernet3/0/12
GigabitEthernet3/0/30 GigabitEthernet3/0/32 GigabitEthernet3/0/34
GigabitEthernet3/0/36 GigabitEthernet3/0/38 GigabitEthernet3/0/40
GigabitEthernet3/0/42 GigabitEthernet3/0/44 GigabitEthernet3/0/46
GigabitEthernet3/0/48 GigabitEthernet3/1/2
Any solutions you can give, i could not find the author of this script again here to ask him on this can be avoided.
Input file will be something like this :
{
GigabitEthernet0/0
GigabitEthernet1/0/2
GigabitEthernet1/0/3
GigabitEthernet1/0/4
GigabitEthernet1/0/5
GigabitEthernet1/0/7
GigabitEthernet1/0/10
GigabitEthernet1/0/18
GigabitEthernet1/0/19
GigabitEthernet1/0/30
GigabitEthernet1/0/33
GigabitEthernet1/0/44
GigabitEthernet1/0/45
GigabitEthernet1/0/46
GigabitEthernet1/1/2
GigabitEthernet1/1/3
GigabitEthernet1/1/4
GigabitEthernet2/0/1
GigabitEthernet2/0/2
GigabitEthernet2/0/5
GigabitEthernet2/0/8
GigabitEthernet2/0/9
GigabitEthernet2/0/12
GigabitEthernet2/0/14
GigabitEthernet2/0/15
GigabitEthernet2/0/18
GigabitEthernet2/0/22
GigabitEthernet2/0/31
GigabitEthernet2/0/33
GigabitEthernet2/0/34
GigabitEthernet2/0/35
GigabitEthernet2/0/36
GigabitEthernet2/0/38
GigabitEthernet2/0/40
GigabitEthernet2/1/2
GigabitEthernet2/1/3
GigabitEthernet2/1/4
GigabitEthernet3/0/12
GigabitEthernet3/0/23
GigabitEthernet3/0/30
GigabitEthernet3/0/31
GigabitEthernet3/0/32
GigabitEthernet3/0/33
GigabitEthernet3/0/34
GigabitEthernet3/0/35
GigabitEthernet3/0/36
GigabitEthernet3/0/37
GigabitEthernet3/0/38
GigabitEthernet3/0/39
GigabitEthernet3/0/40
GigabitEthernet3/0/41
GigabitEthernet3/0/42
GigabitEthernet3/0/43
GigabitEthernet3/0/44
GigabitEthernet3/0/45
GigabitEthernet3/0/46
GigabitEthernet3/0/47
GigabitEthernet3/0/48
GigabitEthernet3/1/1
GigabitEthernet3/1/2
GigabitEthernet3/1/3
GigabitEthernet3/1/4
}
Output i need something like this :
{
GigabitEthernet0/0 | GigabitEthernet1/0/33 |
GigabitEthernet1/0/2 | GigabitEthernet1/0/44 |
GigabitEthernet1/0/3 | GigabitEthernet1/0/43 |
GigabitEthernet1/0/4 | GigabitEthernet1/0/46 |
GigabitEthernet1/0/5 | GigabitEthernet1/1/2 |
GigabitEthernet1/0/7 | GigabitEthernet1/1/3 |
GigabitEthernet1/0/10| GigabitEthernet1/1/4 |
GigabitEthernet1/0/18| GigabitEthernet2/0/1 |
GigabitEthernet1/0/19| GigabitEthernet2/0/2 |
GigabitEthernet1/0/30| GigabitEthernet2/0/5 |
}
I have got this resolved using a column command.
it just posts the output something like this
column vacant_temp4.txt
GigabitEthernet1/0/1 GigabitEthernet1/0/48 GigabitEthernet2/0/34 GigabitEthernet3/0/44 GigabitEthernet4/0/28
GigabitEthernet1/0/2 GigabitEthernet1/1/2 GigabitEthernet2/0/35 GigabitEthernet3/1/1 GigabitEthernet4/0/29
GigabitEthernet1/0/3 GigabitEthernet1/1/3 GigabitEthernet2/0/36 GigabitEthernet3/1/2 GigabitEthernet4/0/30
GigabitEthernet1/0/5 GigabitEthernet1/1/4 GigabitEthernet2/0/38 GigabitEthernet3/1/3 GigabitEthernet4/0/31
GigabitEthernet1/0/7 GigabitEthernet2/0/1 GigabitEthernet2/0/45 GigabitEthernet3/1/4 GigabitEthernet4/0/32
GigabitEthernet1/0/8 GigabitEthernet2/0/5 GigabitEthernet2/1/2 GigabitEthernet4/0/1 GigabitEthernet4/0/33
GigabitEthernet1/0/9 GigabitEthernet2/0/8 GigabitEthernet2/1/3 GigabitEthernet4/0/5 GigabitEthernet4/0/34
GigabitEthernet1/0/14 GigabitEthernet2/0/9 GigabitEthernet2/1/4 GigabitEthernet4/0/6 GigabitEthernet4/0/35
GigabitEthernet1/0/16 GigabitEthernet2/0/10 GigabitEthernet3/0/2 GigabitEthernet4/0/9 GigabitEthernet4/0/36
GigabitEthernet1/0/19 GigabitEthernet2/0/13 GigabitEthernet3/0/5 GigabitEthernet4/0/12 GigabitEthernet4/0/37
GigabitEthernet1/0/20 GigabitEthernet2/0/14 GigabitEthernet3/0/7 GigabitEthernet4/0/13 GigabitEthernet4/0/38
GigabitEthernet1/0/26 GigabitEthernet2/0/16 GigabitEthernet3/0/13 GigabitEthernet4/0/16 GigabitEthernet4/0/39
GigabitEthernet1/0/27 GigabitEthernet2/0/20 GigabitEthernet3/0/16 GigabitEthernet4/0/17 GigabitEthernet4/0/40
GigabitEthernet1/0/28 GigabitEthernet2/0/21 GigabitEthernet3/0/19 GigabitEthernet4/0/18 GigabitEthernet4/0/41
GigabitEthernet1/0/30 GigabitEthernet2/0/25 GigabitEthernet3/0/22 GigabitEthernet4/0/19 GigabitEthernet4/0/42
GigabitEthernet1/0/31 GigabitEthernet2/0/26 GigabitEthernet3/0/25 GigabitEthernet4/0/20 GigabitEthernet4/1/1
GigabitEthernet1/0/35 GigabitEthernet2/0/27 GigabitEthernet3/0/26 GigabitEthernet4/0/21 GigabitEthernet4/1/2
GigabitEthernet1/0/36 GigabitEthernet2/0/28 GigabitEthernet3/0/27 GigabitEthernet4/0/22 GigabitEthernet4/1/3
GigabitEthernet1/0/37 GigabitEthernet2/0/29 GigabitEthernet3/0/37 GigabitEthernet4/0/23 GigabitEthernet4/1/4
GigabitEthernet1/0/40 GigabitEthernet2/0/30 GigabitEthernet3/0/39 GigabitEthernet4/0/24
GigabitEthernet1/0/45 GigabitEthernet2/0/31 GigabitEthernet3/0/41 GigabitEthernet4/0/26
GigabitEthernet1/0/46 GigabitEthernet2/0/32 GigabitEthernet3/0/42 GigabitEthernet4/0/27
It looked better than what you saw above on my putty screen .
Thank you oliv , tripleee , paul & all.

Write a bash script to subdivide an given subnet into a pre-defined number of smaller subnets

This question was recently asked in an interview.
Question: Write a bash script to subdivide an given subnet into a pre-defined number of smaller subnets.
After division IP addresses shouldn't be wasted, i.e. accumulation of your subdivisions should make up the divided subnet.
Every subnet has 3 IP addresses reserved and not usable by hosts: network, broadcast, gateway.
Show network/broadcast address, number of hosts and assign gateway. Gateway should be first IP available in divided subnet. Examples:
INPUT: ./subnetter.sh 192.168.0.0/24 3
OUTPUT:
subnet=192.168.0.0/25 network=192.168.0.0 broadcast=192.168.0.127 gateway=192.168.0.1 hosts=125
subnet=192.168.0.128/26 network=192.168.0.128 broadcast=192.168.0.191 gateway=192.168.0.129 hosts=61
subnet=192.168.0.192/26 network=192.168.0.192 broadcast=192.168.0.255 gateway=192.168.0.193 hosts=61
INPUT: ./subnetter.sh 192.168.0.0/24 4
OUTPUT:
subnet=192.168.0.0/26 network=192.168.0.0 broadcast=192.168.0.63 gateway=192.168.0.1 hosts=61
subnet=192.168.0.64/26 network=192.168.0.64 broadcast=192.168.0.127 gateway=192.168.0.65 hosts=61
subnet=192.168.0.128/26 network=192.168.0.128 broadcast=192.168.0.191 gateway=192.168.0.129 hosts=61
subnet=192.168.0.192/26 network=192.168.0.192 broadcast=192.168.0.255 gateway=192.168.0.193 hosts=61
INPUT: ./subnetter.sh 10.55.10.64/28 2
OUTPUT:
subnet=10.55.10.64/29 network=10.55.10.64 broadcast=10.55.10.71 gateway=10.55.10.65 hosts=5
subnet=10.55.10.72/29 network=10.55.10.72 broadcast=10.55.10.79 gateway=10.55.10.73 hosts=5
First of all, I am trying to analyse what logic is used to divide the subnets.
Secondly, I am trying to use the ipcalc command to get outputs but no luck.
Thanks
Here is the bash script, I have tried my hands on:
Should work fine. The script takes 2 arguments, CIDR block and number of subnets to divide into.
#!/bin/bash
cidr=$1
total_subnet=$2
nw_addr=`echo $cidr | awk -F'/' '{ print $1 }'` # retrieving network IP from input 1
nw_mask=`echo $cidr | awk -F'/' '{ print $2 }'` # retrieving network mask from input 1
dbit=`echo $nw_addr | awk -F'.' '{ print $4 }'` # retrieving the D-bit from network ( A.B.C.D )
significant_bit=`echo $nw_addr | awk -F'.' 'BEGIN {OFS = ""}{print $1,".",$2,".",$3 }'` # retrieving A.B.C bits from n/w address
change_bit=$(( 32 - $nw_mask))
max_addr=$(( 2 ** $change_bit)) # calculating maximum addresses available in the network that can be subdivided
dbit_max=$dbit
# A Funtion to calculate the least power of 2 that is equal or greater than the argument
least_greater_power_of_two()
{
next_power=2
power=1
subnet_range=$1
while [ $next_power -lt $subnet_range ]; do
power=$(($power+1))
next_power=$(( 2 ** $power))
done
}
#initialising Loop Variables
remaining_addr=$max_addr
max_subnet_dbit=$dbit
total_subnet_addr=0
starting_dbit=$dbit
i=$total_subnet
while [ $i -gt 0 ]; do
starting_dbit=$(( $starting_dbit + $total_subnet_addr )) #Finding the starting D bit of the subnet
#finding the total number of addresses in the subnet
subnet_range=$(( $remaining_addr / $i ))
least_greater_power_of_two $subnet_range
total_subnet_addr=$(( 2 ** $power ))
max_subnet_dbit=$(( $max_subnet_dbit + $total_subnet_addr ))
remaining_addr=$(( $remaining_addr - $total_subnet_addr )) # Remaining addresses left to be assigned to the other subnets
last_dbit=$(( $max_subnet_dbit - 1)) #calculating last D bit in the subnet range
subnet_mask=$(( $change_bit - $power + $nw_mask )) #calculating the subnet mask
gateway_dbit=$(( $starting_dbit + 1 )) # calculating the Gateway D bit
total_hosts=$(( $total_subnet_addr - 3 )) # calculating the Total-hosts in the network
echo "Subnet= $significant_bit.$starting_dbit/$subnet_mask Network=$significant_bit.$starting_dbit Broadcast=$significant_bit.$last_dbit Gateway= $significant_bit.$gateway_dbit Hosts=$total_hosts"
i=$(($i-1)) # updating loop variable
done
I believe I have done 70% of the stuff that you require off the script. Since you were using ipcalc, dediced to use a similar binary. To start off, do the following:
yum install sipcalc if you have a RPM based OS or apt-get install sipcalc depending on the distro of your Linux OS.
Then write the following script and save it as subnetter.sh and give it 'x' permissions so that it can be executed.
#!/bin/bash
if [ $# == 0 ]; then
echo "Usage: ./subnetter.sh IP/SUBNET RANGE"
exit
fi
subnet=$1
network=`echo $subnet | cut -d / -f1`
broadcast=`/usr/bin/sipcalc $1 | grep -i broadcast | cut -d '-' -f2`
gateway=`/usr/bin/sipcalc $1 | grep -i usable | awk '{print $4}'`
hosts=`/usr/bin/sipcalc $1 | grep -i addresses | cut -d '-' -f2`
echo "subnet =" $subnet "network =" $network "broadcast =" $broadcast "gateway =" $gateway "hosts =" $hosts
Output of my script:
[root#puppet ~]# ./subnetter.sh 192.168.0.0/24
subnet = 192.168.0.0/24 network = 192.168.0.0 broadcast = 192.168.0.255 gateway = 192.168.0.1 hosts = 256
Please note that the requirement of the third argument is very simple and can be simply done using a for loop. I expect you to do that.
You can use the following tool to make sure that your output is correct: http://www.subnet-calculator.com/subnet.php?net_class=C
I have gone through the above requirment and below is what i have programmed to achieve the result .
Python Code integrated with the above shell script to achieve the result as users are expecting
Below code will create sub subnet for the existing subnet and then will call the shell script to perform the operation in loop and will provide records based on the users request.
#
from netaddr import *
import ipaddress
import csv
import subprocess
import os
import shlex
import sys
import numpy as np
from itertools import islice
if os.path.exists('hst.txt'):
os.remove('hst.txt')
else:
print("Sorry, I can not remove " )
if os.path.exists('hst_refined.txt'):
os.remove('hst_refined.txt')
else:
print("Sorry, I can not remove " )
fd = open('store_subnet',"w")
enter_subnet = raw_input('Enter subnet please: ')
fd.write(enter_subnet)
fd = open('store_sub_subnet',"w")
sub_subnet = raw_input('Enter nested_subet_count: ')
fd.write(sub_subnet)
ip=ipaddress.ip_network(unicode(enter_subnet))
list_demo = list(ip.subnets(int(sub_subnet)))
for i in list_demo:
hs = open("hst.txt","a")
hs.write(str(i))
hs.write("\n")
hs.close()
p = subprocess.Popen([ "/home/ramkumar5/network_cal/report_demo.sh" ], stdout=subprocess.PIPE).communicate()[0]
for i in p:
hs = open("hst_refined.txt","a")
hs.write(i)
hs.close()
print(sub_subnet)
records_req = raw_input('Enter Number of Records needed: ')
f=open("hst_refined.txt")
for i in xrange(int(records_req)):
line=f.next().strip()
print line
f.close()
#
#
Code2
#!/bin/bash
for res in `cat hst.txt` ; do
subnet=$res
network=`echo $subnet | cut -d / -f1`
broadcast=`/usr/bin/sipcalc $res | grep -i broadcast | cut -d '-' -f2`
gateway=`/usr/bin/sipcalc $res | grep -i usable | awk '{print $4}'`
hosts=`/usr/bin/sipcalc $res | grep -i addresses | cut -d '-' -f2`
echo "subnet =" $subnet "network =" $network "broadcast =" $broadcast "gateway =" $gateway "hosts =" $hosts
done
#
Sample Out from the result###

how to distinguish the domain from a subdomain

i have a problem with script.
At my work i often have to check PTR of domain, MX records and similar data. I did the most of the script, but the problem appears when i do something likethis is subdomain
e-learning.go4progress.pl
this is domain but second level?
simple.com.pl
Now in my script there is something like: if i don't put www, it adds and does
dig www.e-learning.go4progress.pl
dig e-learning.go4progress.pl
dig go4progress.pl
he counts dots and subtracts 1, but problem is when domain looks like
simple.com.pl
because script make dig too for
com.pl
I don't check many domain which contains com.pl, co.uk, gov.pl. I've got an idea to make array and compare this what i put in script with array, when it finds in string component of array he subtracts 2 instead 1 ;)
I paste a part of script to better understand me why he substracks 1.
url="`echo $1 | sed 's~http[s]*://~~g' | sed 's./$..' | awk '!/^www/ {$0="www." $0}1'`"
ii=1
dots="`echo $url | grep -o "\." | wc -l`"
while [ $ii -le $dots] ; do
cut="`echo $url | cut -d "." -f$ii-9`"
ip="`dig +short $cut`"
host="`dig -x $ip +short`"
if [[ -z "$host" ]]; then
host="No PTR"
fi
echo "strona: $cut Host: $host"
ii=$[ii + 1]
Maybe you have diffrent idea how to help with my problem.
Second question is how to distinguish subdomain from domain.
I need compare mx records of subdomain(when the url contains subdomain) and mx records top level domain.
I waiting for your response ;)
My solution to find the domain as registered with the registrar:
wget https://raw.githubusercontent.com/gavingmiller/second-level-domains/master/SLDs.csv
DOMAIN="www.e-learning.go4progress.co.uk";
KEEPPARTS=2;
TWOLEVELS=$( /bin/echo "${DOMAIN}" | /usr/bin/rev | /usr/bin/cut -d "." --output-delimiter=".\\" -f 1-2 | /usr/bin/rev );
if /bin/grep -P ",\.${TWOLEVELS}" SLDs.csv >/dev/null; then
KEEPPARTS=3;
fi
DOMAIN=$( /bin/echo "${DOMAIN}" | /usr/bin/rev | /usr/bin/cut -d "." -f "1-${KEEPPARTS}" | /usr/bin/rev );
echo "${DOMAIN}"
Thanks to https://github.com/gavingmiller/second-level-domains and https://github.com/medialize/URI.js/issues/17#issuecomment-3976617

Resources