if-then-else based on command output - bash

I am using netstat command to get information on networks. I want to put a condition here on protocol fetched. If it's TCP, I need to print different columns than if it's UDP.
Below is what I am trying to do, but it doesn't work. Please suggest and advise if there is something I am doing wrong:
if [$(netstat -anputw | awk '{print $1}')=="tcp"] then
netstat -anputw | awk '{print $1,",",$4"}' >> $HOME/MyLog/connections_$HOSTNAME.csv
elif [$(netstat -anputw | awk '{print $1}')=="udp"] then
netstat -anputw | awk '{print $5,",",$7}' >> $HOME/MyLog/connections_$HOSTNAME.csv
fi

I don't know what you're trying to achieve, however I think that netstat returns a list rather than a string, therefore comparing the output against a string is pointless. You have to loop it. Try the following
#!/bin/bash
OUTPUT=$(netstat -anputw | awk '{print $1}');
for LINE in $OUTPUT
do
if [[ $LINE == "tcp" ]] ; then
echo "TCP!"
elif [[ $LINE == "udp" ]] ; then
echo "UDP!"
fi
done

Why don't you separate the two cases by not asking netstat to mix them up?
netstat -anptw # Just tcp
netstat -anpuw # Just udp
Also, in the tcp case, you don't seem to care about the -p information so you might as well not ask for it. And in the udp case, there is no data in the State column, so the PID/Program name will actually be in column 6.
Putting that together, I get:
netstat -antw | awk '{print $1","$4}' >> $HOME/MyLog/connections_$HOSTNAME.csv
netstat -anpuw | awk '{print $5","$6}' >> $HOME/MyLog/connections_$HOSTNAME.csv
I suspect that isn't quite the information you're looking for either, though. Perhaps you want to distinguish between TCP listening and non-listening connections.

Always leave a space after [ and before ] in if statement and you should put command $(netstat -anputw | awk '{print $1}' under double quotes if you are doing string comparison.
Here's the final script:
if [ "$(netstat -anputw | awk '{print $1}')" == "tcp" ]; then
netstat -anputw | awk '{print $1,",",$4"}' >> $HOME/MyLog/connections_$HOSTNAME.csv
elif [ "$(netstat -anputw | awk '{print $1}') " == "udp" ]; then
netstat -anputw | awk '{print $5,",",$7}' >> $HOME/MyLog/connections_$HOSTNAME.csv
fi

Related

bash script - store multiple outputs of a command in separate variables

I'd like to store the ouput of the following command in separate variables for each IP adress:
ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
Does anyone have an idea how to do this?
The requirement to store the values as separate variables seems out of place. Just produce the list, and loop over it or whatever.
Tangentially, you really want to lose the long chain of greps.
ifconfig |
awk '$1 == "inet" && ($2 != "127.0.0.1" && $2 != "addr:") { print $2 }
$1 == "inet" && $2 == "addr:" && $3 != "127.0.0.1" { print $3 }'
To assign the result to a Bash array, try
array=($(ifconfig | awk '...'))
but more often than not, you probably just want to loop over the result:
ifconfig |
awk '...' |
while IFS='' read -r ip; do
# something with "$ip"
done

assign wifi device name to variable

I'm running the following command to figure out which network interface is being used currently.
networksetup -listallhardwareports | grep -C1 $(route get default | grep interface | awk '{print $2}')
How can I use that command and parse out the device name of that interface and then compare it to the device name of the Wi-Fi interface?
So I run the command above and this is what I get:
Hardware Port: Ethernet
Device: en0
Ethernet Address: a8:60:b6:03:0a:97
This is telling me that my ethernet port, or device en0 is the active network port on my computer. I want to assign en0 to a variable, say currentPort.
I will also run this command:
networksetup -listallhardwareports
This would be the results of that:
Hardware Port: Ethernet
Device: en0
Ethernet Address: a8:60:xx:xx:xx:xx
Hardware Port: Wi-Fi
Device: en1
Ethernet Address: 2c:f0:xx:xx:xx:xx
From this I want to pull the device name for my wifi, in this case en1 and assign it to another variable, say wifiPort.
So I should have currentPort=en0 and wifiPort=en1. I am hoping that I can then run an if then command that says is currentPort is not the same as wifiPort do one thing, if currentPort is the same as wifiPort, do something else.
Hope this helps explain things a little better.
This is what I'm working with right now, based on your help. echo $currentport and echo $wifiport doesn't give me any output and with the if commands, it echos "They are the same" regardless of what device I'm using.
#!/bin/bash
#currentport=`grep -A3 'Ethernet' t6.txt | grep "Device"| awk -F": " '{print $2}'`
currentport=`echo $a|grep -A3 'Ethernet'| grep "Device"| awk -F": " '{print $2}'`
echo $currentport
#wifiport=`grep -A3 'Wi-Fi' t5.txt | grep "Device"| awk -F": " '{print $2}'`
wifiport=`echo $b|grep -A3 'Wi-Fi'| grep "Device"| awk -F": " '{print $2}'`
echo $wifiport
if [[ $currentport == $wifiport ]]
then
echo They are the same
else
echo They are different
fi
exit 0
Try this:
For currentport:
Assume the output of your networksetup command is stored in a file: t6.txt
Hardware Port: Ethernet
Device: en0
Ethernet Address: a8:60:b6:03:0a:97
Do this:
mayankp#mayank:~/ currentport=`echo $a|grep -A3 'Ethernet'| grep "Device"| awk -F": " '{print $2}'`
mayankp#mayank:~/ echo $currentport
en0
For wifiport:
Assume the output of your networksetup command is stored in a file: t5.txt
Hardware Port: Ethernet
Device: en0
Ethernet Address: a8:60:xx:xx:xx:xx
Hardware Port: Wi-Fi
Device: en1
Ethernet Address: 2c:f0:xx:xx:xx:xx
Do this:
mayankp#mayank:~/ wifiport=`echo $b|grep -A3 'Wi-Fi'| grep "Device"| awk -F": " '{print $2}'`
mayankp#mayank:~/ echo $wifiport
en1
Now, you have both variables: $currentport and $wifiport.
Use if to do what you want:
if [[ $currentport == $wifiport ]]
then
<do your stuff>
else
<do other stuff>
fi
Let me know if this helps.
I think I'd avoid using all those pipes, and just do this in awk:
awk 'NR==FNR&&/interface/{i=$2} NR==FNR{next} index($0,"Device: "i)' \
<(route get default) \
RS= \
<(networksetup -listallhardwareports)
The awk script first parses the route command's output to determine the interface to use, then sets RS= which forces awk into multi-line mode, which allows the index() command to be used as a condition for printing a record.
And if you want just the WiFi port, the awk script is even simpler, because you don't need to parse the route command:
awk 'index($0,"Hardware Port: Wi-Fi")' RS= <(networksetup -listallhardwareports)
And if you want to compare the results, i.e. determine whether you are currently using WiFi, it's easy enough to wrap the commands you need in process substitution.
#!/bin/bash
currentPort=$(
awk '/interface/{print $2;exit}' <(route get default)
)
wifiPort=$(
awk 'index($0,"Hardware Port: Wi-Fi") {
sub(/.*Device: /,"");sub(/[[:space:]].*/,"")
print; exit
}' \
RS= \
<(networksetup -listallhardwareports)
)
if [[ "$wifiPort" = "$currentPort" ]]; then
echo "I'm on WiFi!"
else
echo "I'm NOT on WiFi!"
fi
Of course, you could also do this in bash alone, without the need for awk:
#!/bin/bash
junk=$(route get default)
[[ $junk =~ .*interface:\ ([a-z]+[0-9]+) ]]
currentPort="${BASH_REMATCH[1]}"
while read line; do
if [[ $line = *Wi-Fi ]]; then
read line
wifiPort="${line##* }"
break
fi
done < <(networksetup -listallhardwareports)
if [[ "$wifiPort" = "$currentPort" ]]; then
echo "I'm on WiFi!"
else
echo "I'm NOT on WiFi!"
fi
Note that the while read line loop isn't particularly efficient, and a bash 4 mapfile/readarray would perform better. But the default version of bash in macOS is still 3. :)

how can i grep the interface names given in following output of netstat -i

Hi i want grep the interfaces names as a list , am getting the table of interfaces with netstat -i and it looks like this :
thanks .
It's better to use also awk to simplify expressions:
netstat -i | awk '{print $1}' | grep -vE '(Kernel|Iface)'
In this case we are using awk to print only first column and after that we filter out words from first two lines of netstat output.
P.S. Or even shorter (thanks to #etan-reisner)
netstat -i | awk '! /(Kernel|Iface)/ {print $1}'
i got the preferred output with ifconfig -a | sed 's/[ \t].*//;/^$/d'
though netstat -i | awk '{print $1}' | grep -vE '(Kernel|Iface)' is also working , but i will prefer my solution since am writing a Qt QProcess and more arguments and programs will be not a solution . thanks :)
You can use the shell itself to test/parse the interface names as well without calling either awk or sed:
netstat -i | while read iface data; do
[ $(expr "$iface" : "Kernel\|Iface") -eq 0 ] &&
printf "%s\n" "$iface"
done
Or as a one-liner (not too long):
netstat -i | while read iface data; do [ $(expr "$iface" : "Kernel\|Iface") -eq 0 ] && printf "%s\n" "$iface"; done

Get details of all tcp listening processes

#! /bin/bash
a=`netstat -plant | grep -i listen`
#to get ip and port
b=`echo $a | awk {'print $4}'`
#to get the process id
c=`echo $a | awk {'print $7}' | awk -F '/' {'print $1'}`
set -- $c
#to get the details of process
g=`ps aux | grep $1`
m=`echo $g | awk {'print $2}'`
n=`echo $g | awk {'print $9}'`
o=`echo $g | awk {'print $11}'`
echo The process with PID $m invoked by command "$o", is listening at IP and Port : $b . The process has been running since $n
I was trying to make a script to display the details like PID, IP, port, running since, and the command of all tcp listening processes in a simple language. The script I made gives the details of only 1 process
You only need to change the assignment to a with a while read construct:
netstat -plant | grep -i listen | while read a; do
#to get ip and port
b=`echo $a | awk {'print $4}'`
#to get the process id
c=`echo $a | awk {'print $7}' | awk -F '/' {'print $1'}`
set -- $c
#to get the details of process
g=`ps aux | grep $1`
m=`echo $g | awk {'print $2}'`
n=`echo $g | awk {'print $9}'`
o=`echo $g | awk {'print $11}'`
echo The process with PID $m invoked by command "$o", is listening at IP and Port : $b . The process has been running since $n
done
This construct will read output from the grep into a variable one line at a time.

How to get IPv4, gateway and netmask address in shell?

How to detect IPv4, gateway and netmask and DNS address in shell?
I need this to modify a script to automate deployment of virtual machines.
A very simple way, but very unreliable, if you know what interface you need could be:
ifconfig_line=$(ifconfig wlan0 | grep -sw "inet" | tr ":" " ")
echo "IP: "$(echo $ifconfig_line | awk {'print $3'})
echo "Mask:"$(echo $ifconfig_line | awk {'print $7'})
echo "Gateway: "$(route -n |head -n3|tail -n1|awk '{print $2}')
echo "DNS: "$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')

Resources