Shell script : Displaying network interface and their corresponding ip address in a table format - bash

I want to display network interface and their ip address in a table format using shell script. I have this code
#! /bin/bash
interface=$(ifconfig | cut -d ' ' -f1| tr '\n' ' ' | tee save.tmp)
ip=$(ifconfig | awk -F':' '/inet addr/&&!/127.0.0.1/{split($2,_," ");print _[1]}')
echo $interface
echo $ip
The output of this code is
eth0 vmnet1 vmnet8
10.30.10.226 192.168.142.1 192.168.3.1
I want like this
eth0 10.30.10.226
vmnet1 192.168.142.1
vmnet8 192.168.3.1
Thank you in advance

Rearrange it like this:
for iface in $(ifconfig | cut -d ' ' -f1| tr '\n' ' ')
do
addr=$(ip -o -4 addr list $iface | awk '{print $4}' | cut -d/ -f1)
printf "$iface\t$addr\n"
done

Here is my shell script (hope it helps) :
#!/bin/bash
clear
echo -e "+-----------+-----------------+\n| Interface | IP Address |\n+-----------+-----------------+"
for iface in $(ip -o -4 addr list | awk '{print $2}' | tr '\n' ' ')
do
ipaddr=$(ip -o -4 addr list $iface | awk '{print $4}' | cut -d/ -f1)
printf "|%10s | %-16s|\n" $iface $ipaddr
done
echo "+-----------+-----------------+"
Output:
+-----------+-----------------+
| Interface | IP Address |
+-----------+-----------------+
| lo | 127.0.0.1 |
| enp0s31f6 | 10.10.10.100 |
| wlp61s0 | 10.11.11.111 |
| tun0 | 10.20.20.200 |
+-----------+-----------------+

Related

Dealing with linebreaks in while read line

Maybe I'm using the wrong tool for the job here...
My data looks like this (this is from a json file which has been converted to a csv):
"hostname1",1,""
"hostname2",1,""
"hostname3",0,"yay_some_text
more_text
more_text
"
The first column is the hostname, second is the exit code and the third the result. I usually do something like this and make a moderately pretty table:
cat tmp.file | ( while read line
do
name=$(echo $line | awk -F "," '{print $1}')
exit_code=$(echo $line | awk -F "," '{print $2}')
output=$(echo $line | awk -F "," '{print $3}')
#I can then do stuff with the output here and ultimately do this:
echo -e "|${name}\t|${exit_code}\t|${output}\t|"
done
)
However the third column is causing me no end of problems; I think regardless of what I do, the read line bit will make this impossible. Does anyone have a better method of sorting this? I'd ideally like to keep the linebreaks, but if thats going to be too hard, I'll happily replace them with commas.
Desired output (either is fine):
| hostname1 | 1 | |
| hostname2 | 1 | |
| hostname3 | 0 | yay_some_text
more_text
more_text |
| hostname1 | 1 | |
| hostname2 | 1 | |
| hostname3 | 0 | yay_some_text, more_text, more_text |
Whichever of these you prefer will work robustly* and efficiently using any awk in any shell on every UNIX box:
$ cat tst.awk
{ rec = rec $0 ORS }
/"$/ {
gsub(/[[:space:]]*"[[:space:]]*/,"",rec)
gsub(/,/," | ",rec)
printf "| %s |\n", rec
rec = ""
}
.
$ awk -f tst.awk file
| hostname1 | 1 | |
| hostname2 | 1 | |
| hostname3 | 0 | yay_some_text
more_text
more_text |
.
$ cat tst.awk
{ rec = rec $0 RS }
/"$/ {
gsub(/[[:space:]]*"[[:space:]]*/,"",rec)
gsub(/,/," | ",rec)
gsub(RS,", ",rec)
printf "| %s |\n", rec
rec = ""
}
.
$ awk -f tst.awk file
| hostname1 | 1 | |
| hostname2 | 1 | |
| hostname3 | 0 | yay_some_text, more_text, more_text |
*robustly assuming your quoted strings never contain commas or escaped double quotes, i.e. it looks like the example you provided and your existing code relies on.
$ gawk -v RS='"\n' -v FPAT='[^,]*|"[^"]*"' -v OFS=' | ' '
{gsub(/"/,""); $1=$1; print OFS $0 OFS}' file
| hostname1 | 1 | |
| hostname2 | 1 | |
| hostname3 | 0 | yay_some_text
more_text
more_text
|
In your case, one way is , you can transform the file to a simpler structure before using
awk '/[^"]$/ { printf("%s", $0); next } 1' tmp.file | ( while read line
do
name=$(echo $line | awk -F ',' '{print $1}')
exit_code=$(echo $line | awk -F ',' '{print $2}')
output=$(echo $line | awk -F ',' '{print $3}')
#I can then do stuff with the output here and ultimately do this:
echo -e "|${name}\t|${exit_code}\t|${output}\t|"
done
)
If all you want to do is to display as a table, you can use column utility
awk '/[^"]$/ { printf("%s", $0); next } 1' tmp.file | column -t -o " | " -s ,
If you are so particular about the starting and ending seperator '|', you can simply pipe the output of this command to a sed|awk.

Raspberry Pi Bash Script for network adapter, ip addresss and Mac address

I want to have a short cut to display the adapter, IP address and Mac address. I have the following:
#! /bin/bash
for iface in $(ifconfig | grep -v "lo" | cut -d ' ' -f1| tr '\n' ' ')
do
ipadd=$(ip -o -4 addr list $iface | awk '{print $4}' | cut -d/ -f1)
madd=$(ip -o link list $iface | awk '{print $17}')
printf "$iface\t$ipadd\t$madd\n"
done
The ethernet adapter doesn't show IP address and show as no such device. But if I run the command manually in bash it work and show up. The same script work correctly on my Ubuntu but not on Raspberry Pi (only manual command work). wlan0 works with no problem on Pi
The MAC address doesn't work at all, but if I run the command manually ip -o link list <adapter> | awk '{print $17}') it show the Mac address correctly.
Please advise where could have gone wrong.
Update:
+++ ifconfig
+++ grep -v lo
+++ cut -d ' ' -f1
+++ tr '\n' ' '
++ for iface in $(ifconfig | grep -v "lo" | cut -d ' ' -f1| tr '\n' ' ')
+++ ip -o -4 addr list enxb827ebe7229c:
+++ awk '{print $4}'
+++ cut -d/ -f1
Device "enxb827ebe7229c:" does not exist.
++ ipadd=
+++ ip -o -4 link list enxb827ebe7229c:
+++ awk '{print $17}'
Device "enxb827ebe7229c:" does not exist.
++ madd=
++ printf 'enxb827ebe7229c:\t\t\n'
enxb827ebe7229c:
++ for iface in $(ifconfig | grep -v "lo" | cut -d ' ' -f1| tr '\n' ' ')
+++ ip -o -4 addr list wlan0:
+++ awk '{print $4}'
+++ cut -d/ -f1
++ ipadd=192.168.1.4
+++ ip -o -4 link list wlan0:
+++ awk '{print $17}'
RTNETLINK answers: No such device
Cannot send link get request: No such device
++ madd=
++ printf 'wlan0:\t192.168.1.4\t\n'
wlan0: 192.168.1.4
If I run the command manually:
ip -o -4 link list enxb827ebe7229c | awk '{print $17}'
I get the Mac address
If I run this
ip -o addr list enxb827ebe7229c | awk '{print $4}' | cut -d/ -f1
I too will get the ipaddress correctly
A small fix was enough:
for iface in $(ifconfig | grep -v "lo:" | cut -d ' ' -f1 | cut -d: -f1); do
ipadd=$(ip -o -4 addr list $iface | awk '{print $4}' | cut -d/ -f1);
madd=$(ip -o link list $iface | awk '{print $17}');
printf "$iface\t$ipadd\t$madd\n";
done
The part ifconfig | grep -v "lo:" | cut -d ' ' -f1| tr '\n' ' ' leaves the : character in the output, so you are iterating over eth0: eth1: not over eth0 eth1. You need to remove the :, either with a simple cut -d: -f1 or tr -d: or any other mean.
Also note, as you've just discovered, the ifconfig output differs between platforms and implementations. It's better to just stick to the new ip command. Ex. ip a | sed -n '/^[^ ]*: \([^ ]*\):.*/{s//\1/;p;}'
There is no need for tr '\n' ' '. Shell interprets any whitespace character - that is tab, space or newline - as a word separator.

Output multiple commands into columns

I'm trying to write a script which runs various commands and outputs the result of each command into one column but I'm not able to get the output ot be displayed in colums.
#!/bin/bash
# Get GBP Neighbour NAMES
NEIGHBOR=$(vtysh -c 'show ip bgp neighbors' | grep Incoming | awk '{print $7}')
# Get IPs of BGP neighbours
IP=$(vtysh -c 'show ip bgp summary' | awk '{print $1}' | head -n -2 | tail -n +6)
# Get Up/Down time
TIME=$(vtysh -c 'show ip bgp summary' | awk '{print $9}' | head -n -2 | tail -n +6)
# Get State/PfxRcd
STATE=$(vtysh -c 'show ip bgp summary' | awk '{print $10}' | head -n -2 | tail -n +6)
How can I get the output to be separated in columns such as:
NEIGHBOR | IP | TIME | STATE
With paste command:
paste -d'|' <(echo "$NEIGHBOR ") <(echo "$IP") <(echo "$TIME") <(echo "$STATE")

Pass value from output of one command to sed

I have a file, config.txt with many lines. One line is like this
address=
I am getting the ip address of the machine on which config.txt resides, with
ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/'
That code is taken from a Stack Overflow answer.. The output I am getting is an IP address -
192.168.3.260
I would like to replace
address=
in config.txt with
address='192.168.3.260'
Is it possible to do it in one line, i.e.
ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/' | <some sed command >
Using grep, cut and awk in a single pipeline is almost always a mistake, since awk can do everything grep can do, and then some. You can extract the IP address with a sed one-liner, like this:
ip addr | sed -n '/state UP/ {n;n;s/ *inet \(.*\)\/.*/\1/p}'
You can also use this approach to build the command you are looking for:
ip addr | sed -n "/state UP/ {n;n;s/ *inet \(.*\)\/.*/s|address=|\&'\1'|/p}"
which prints something like this:
s|address=|&'192.168.3.260'|
And then you can pipe that program to sed:
ip addr | sed -n "/state UP/ {n;n;s/ *inet \(.*\)\/.*/s|address=|\&'\1'|/p}" \
| sed -f - config.txt
sed -i 's/address=/address='$(ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/')'/' filename
Where filename is the name of the file in question, the key here is to use indirection i.e. $(ip addr | grep 'state UP' -A2 | tail -1 | awk '{print $2}' | cut -f1 -d'/') and then use this in a sed command placing particular emphasis on the quotation marks. The indirection must side outside of the single quotation marks of the sed command.

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