How to hand over bash variable to your python script? - bash

I am rather new to bash scripting, more used to batch. Anyways what I am trying to do is to be able to get a string from a bash variable that is created from an nmap scan and make it a variable for a python script. I was going to use grep but it gets too much. Here are the results:
Starting Nmap 5.21 ( http://nmap.org ) at 2014-05-22 20:12 PDT
Nmap scan report for 192.168.1.201
Host is up (0.00020s latency).
Not shown: 96 filtered ports
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
3389/tcp open ms-term-serv
MAC Address: 02:21:9B:88:3C:06 (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 4.77 seconds
What I want to get is: MAC Address: 02:21:9B:88:3C:06 WITH the space at the end. SO it would be MAC=$
Thank you in advance

MAC=$(egrep -o '^MAC Address: (..:){5}.. ' filename.txt)
The -o option makes egrep just output the part of the line that matches the regexp, so it will just go up to the space after the address.

You can use grep and pipe (|) to awk :
MAC=`grep -a 'MAC' Nmapscan.txt | awk -F ' ' {'print $1" "$2" "$3" " '}`
Or
MAC=`nmap 192.168.1.201 | grep 'MAC' | awk -F ' ' {'print $1" "$2" "$3" " '}`
If possible I'd strongly recommend adding this change too for security:
NMAP_FILE=`mktemp`
# start
nmap 192.168.1.201 > $NMAP_FILE
# middle
MAC=`grep -a 'MAC' $NMAP_FILE | awk -F ' ' {'print $1" "$2" "$3" " '}`
# end
rm -f $NMAP_FILE
To pass the $MAC over to your python script you can use:
ALERT.py $MAC &
and add this to ALERT.py
import sys
mac_address = sys.argv[0]
# now `mac_address` is "MAC Address: 02:21:... "

Related

read from the nth column on using awk

The nmcli -c no device displays:
DEVICE TYPE STATE CONNECTION
wlp3s0 wifi connected My Test Connection
p2p-dev-wlp3s0 wifi-p2p disconnected --
enp4s0f1 ethernet unavailable --
lo loopback unmanaged --
In order to separate the info on wifi, I have this command:
wf_info="$(nmcli -c no device | grep "wifi[^-]" | awk '{print "wf_devc="$1, "wf_state="$3, "wf_conn="$4}')"
eval "$wf_info"
echo "$wf_devc" # returns wlp3s0
echo "$wf_state" # returns connected
echo "$wf_conn" # returns My (while should be My Test Connection)
The problem with the above command is that for wf_conn it gives me My while I should be the full name My Test Connection. How can I tell the command to read from the 4th column on and not just the 4th column for the wf_conn?
You can "collect" the rest of the fields into a single variable and then print it:
read wf_devc wf_state wf_conn < <(nmcli -c no device | awk '/wifi[^-]/{r=""; for(i=4;i<=NF;i++){r=r (i==4 ? "":" ") $i}; print $1" "$3" "r}')
Note that grep part is incorporated into awk, /wifi[^-]/ will make sure only those lines will be printed that contains wifi followed by a char other than a - char.
The r=""; for(i=4;i<=NF;i++){r=r (i==4 ? "":" ") $i} part inits an r empty string and then all fields starting with Field 4 are concatenated using a space.
See the online demo:
#!/bin/bash
s='DEVICE TYPE STATE CONNECTION
wlp3s0 wifi connected My Test Connection
p2p-dev-wlp3s0 wifi-p2p disconnected --
enp4s0f1 ethernet unavailable --
lo loopback unmanaged --'
read wf_devc wf_state wf_conn < <(awk '
/wifi[^-]/{
r="";
for(i=4;i<=NF;i++){
r=r (i==4 ? "":" ") $i
};
print $1" "$3" "r
}' <<< "$s")
echo "wf_devc=$wf_devc wf_state=$wf_state wf_conn=$wf_conn"
Output:
wf_devc=wlp3s0 wf_state=connected wf_conn=My Test Connection

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

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###

Unix - bash -OSX

Trying to use grep to find some information. Evaluate the information. Then perform a function.
Heres what I have, any help is appreciated.
FIXED TO:
#! /bin/bash
UT=$(/usr/sbin/system_profiler SPSoftwareDataType | grep "Time since boot" | grep "days")
if [ "$UT" -ge "5 days" ]; then
echo this
else
echo that
fi
SPSoftwareDataType looks like this:
System Software Overview:
System Version: OS X 10.9.5
Kernel Version: Darwin 13.4.0
Boot Volume: Macintosh HD
Boot Mode: Normal
Computer Name: xxxxxxxxxxxx
User Name: xxxxxxxxxx (xxxxxxxxxx)
Secure Virtual Memory: Enabled
Time since boot: 8 days 3:25
Trying using sysctl
#! /bin/bash
UT=$(awk -F":" ' $4 > 200 ' sysctl -n kern.boottime)
echo $UT
if [ “$UT” -ge “1430315296” ]; then
echo this
else
echo that
fi
I can't see how you expect awk to compare anything specified in days and hours with anything else... nor do I know why you would choose to parse system_profiler output.
Have you considered:
sysctl -n kern.boottime
{ sec = 1431023230, usec = 0 } Thu May 7 19:27:10 201
which will give the boot time in seconds since the epoch which is just a simple integer you can compare with other times?
So, you can parse out the seconds like this
UT=$(sysctl -n kern.boottime | awk -F"[ ,]+" '{print $4}')
the -F"[ ,]+" says to treat multiple spaces or commas as field separators.
You can do all in awk
awk '/Time since boot.*days/ {print ($4>5?"This":"That")}' file
This
awk '/Time since boot.*days/ {print ($4>8?"This":"That")}' file
That
Edit:
#!/bin/bash
/usr/sbin/system_profiler SPSoftwareDataType | awk '/Time since boot.*days/ {print ($4>8?"This":"That")}'

Bash: Adding 1 to serial counter in a named.conf file, how is it done?

I have a script which updates DNS records on a DNS server. Every time the named.conf file is updated with a new site I have to raise the serial counter by at least 1.
So my scripts is running on a remote machine and I'm about to add the next line:
serial=`ssh root#172.19.214.X 'cat /var/named/named.booking.zone |grep serial |awk -F\" \" '{print $1}''`
It doesn't work well, I think i'm not escaping the "" correctly...
And then I thought of something like that:
ssh root#172.19.214.X "sed -e 'g/"$serial"/"$serial"+1/s' /var/named/named.booking.zone"
My source file:
$TTL 600
# IN SOA root. booking.local. (
2013030311 ; serial (d. adams)
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Minimum
;
IN MX 10 mail
IN NS dns
IN A 172.19.214.X
www IN A 172.19.214.X
Can you please show me how to do the escapes correctly?
Thanks!
Having this content for /var/named/named.booking.zone :
serial "1"
You can use something like this:
#!/usr/bin/bash
serial=$(ssh root#172.19.214.X 'grep serial /var/named/named.booking.zone' 2>/dev/null |awk '{print $1}' )
(( next_serial = serial + 1 ))
ssh root#172.19.214.X 'sed -i.bak -e 's_${serial}_${next_serial}_g' /var/named/named.booking.zone' 2>/dev/null

Resources