bash how to extract iface inet and mask from ifconfig - bash

Can anyone help filter the information from ipconfig
the information im getting is
enp37s0 Link encap:Ethernet HWaddr 2c:41:38:15:41:30
inet addr:192.168.0.105 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::89be:e3f9:b746:19ed/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4593332 errors:0 dropped:0 overruns:0 frame:0
TX packets:2313662 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:6506620971 (6.5 GB) TX bytes:182579364 (182.5 MB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:9574 errors:0 dropped:0 overruns:0 frame:0
TX packets:9574 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1100854 (1.1 MB) TX bytes:1100854 (1.1 MB)
wlo1 Link encap:Ethernet HWaddr d0:df:9a:6c:7c:1d
inet addr:192.168.0.103 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::225d:a288:5fa7:2237/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:124147 errors:0 dropped:0 overruns:0 frame:0
TX packets:2681 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:32988267 (32.9 MB) TX bytes:266523 (266.5 KB)
And i would like to get.
enp37s0 : 192.168.0.105/255.255.255.0
lo : 127.0.0.1/255.0.0.0
wlo1: 192.168.0.103/255.255.255.0

The syntax will change depending on what operating system you're using, but you can use some sed commands to get the output you want. For example the command on my Arch Linux system is ifconfig (f not p) and my output is formatted a little differently. But here's something that ought to work on your system:
ipconfig | tr '\n' '~' | sed 's/~~/\n/g' | sed 's/~/ /g' | sed -E 's/^\s*(\S+)\s+.*\s+inet\s+(\S+)\s.*$/\1 \2/g'
We do a few things here:
Replace all the newlines with some unused character, here ~, because your interface name (enp37s0) and IP address (192.168.0.105) are on different lines, and we need to merge them onto the same line
Replace ~~ (which would have been two consecutive newlines - the separator between interfaces) with a single newline. This will effectively make sed operate on each interface separately in the remaining steps
Replace ~ (which would have been a single newline) with a space; this ensures we don't inadvertently join any parts of the original output (for example, we might get 30inet from the first two lines being joined together, but we want 30 inet since we're looking for inet
Finally the main part, we extract the first word on each line, then we look for the inet word and also extract the word immediately after it on that same line. We also discard everything after the first word and before inet, and everything after the word after inet. Here a "word" means anything separated by whitespace. \s in a regex matches whitespace and \S matches anything that isn't whitespace, so ^\s*(\S+)\s+ finds our first word, .* gets rid of anything following it, \s+inet\s+(\S+)\s finds inet and the word after it, and .*$ gets rid of anything to the end of the line.
This will produce the following in your case:
enp37s0 addr:192.168.0.105
lo addr:127.0.0.1
wlo1 addr:192.168.0.103
If you want to see what each individual step does, you can of course just execute part of the command.
Removing the addr: and/or adding the Mask into the result is left as an exercise to the reader as similar techniques can be used.

Challenge accepted :-)
Try this one-liner:
for ip in $(hostname -I | grep -Eo '([0-9]*\.){3}[0-9]*'); do echo ""$(ifconfig | grep -B1 "inet addr:"$ip | cut -d " " -f1 | tr -d " ")" : "$ip"/"$(ifconfig | grep "inet addr:"$ip | grep -Eo 'Mask:?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*') ; done;
Produces something like this on my Debian:
wlan1 : 192.168.1.116/255.255.255.0
docker_gwbridge : 172.18.0.1/255.255.0.0
br-2c830dcde04d : 172.25.0.1/255.255.0.0
br-d6bc6df716ef : 172.21.0.1/255.255.0.0
br-d6fccd14dfad : 172.19.0.1/255.255.0.0
br-df4c2b24c7c0 : 172.24.0.1/255.255.0.0
docker0 : 172.17.0.1/255.255.0.0
br-ef0e82befd79 : 172.22.0.1/255.255.0.0
br-fad2fced45f8 : 172.20.0.1/255.255.0.0
Some details if you're interested:
for ip in $(hostname -I | grep -Eo '([0-9]*\.){3}[0-9]*'); do
loop over IPv4 addresses in hostname output
ifconfig | grep -B1 "inet addr:"$ip | cut -d " " -f1 | tr -d " ")
take a matching line and the one above in ifconfig, then take the first word of that line above the IP address ... which should be the name of the interface
ifconfig | grep "inet addr:"$ip | grep -Eo 'Mask:?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*')
take that matching line again and search for a token with "Mask:", then extract the mask
Ok, I know, it is not pure bash, might not work on all OS variants, not even pure sed/grep on ifconfig, but... was fun to code it!

Related

Does anybody know what is the reason that question mark matches nothing in ubuntu 19.10?

When i use a dot(.) in globbing pattern, it successfully matches this bunch of addresses:
~$ ip addr show | grep i.et
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
inet 192.168.1.101/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp3s0
inet6 fe80::c705:4836:6aa7:d321/64 scope link noprefixroutet
At the same time, the question-marked version matches nothing:
~$ ip addr show | grep i?et
Any ideas?
Grep's patterns are regular expressions. The question mark you are trying to use is part of Bash's globbing (pattern matching).
Example using globbing:
ls -1d /proc/191?
returns :
/proc/1910
/proc/1913
/proc/1914
/proc/1915
/proc/1916
/proc/1918
/proc/1919
Now with grep's regular expressions (regex):
ls -1 /proc | grep '191.'
returns:
1910
1913
1914
1915
1916
1918
1919
Hope that helps clear up the confusion.

Making a simple system monitor bash script

I'm trying to create a simple bash script to monitor the following: CPU Utilization, outbound network bandwidth, and inbound network bandwidth. The kicker, I have to use information from /proc/loadavg for the CPU and information from /proc for the bandwidth.
For the CPU Utilization, because it is supposed to be on a short time interval, I can use the first value from /proc/loadavg. Thing is, I'm not sure how to just get that one value so what I have so far is this:
CPU=sudo cat /proc/loadavg | sed 's///'
echo "CPU Utilization: $CPU %"
Where I'm not sure what the sed operation should be. Also I'm not sure how to format what I would get from that so that it would print as "16.5%"
For the bandwidth monitors I haven't the slightest clue of what I could use in /proc to get that sort of information so I'm open to all suggestions.
Load average
You don't need sudo to read /proc/loadavg
In addition, sed is the wrong tool here, try using cut, for example:
$ cut -d' ' -f1 < /proc/loadavg
0.04
cut will cut lines by a delimiter (given with -d), in this case a space, and you can then use -f to select a field, in this case the first one.
Now, converting it to percentages is actually fairly meaningless, since you'll often end up above 100% (see comment below), I've seen load averages in excess of 50 (that would be 5000% percent?).
In all my years of UNIX/Linux experience, I can't recall ever seeing the load average being expressed as a percentage, and if I would encounter such a thing, I would find it very odd.
But if you really want to (you don't!), just multiply by 100 with dc, like so:
$ dc -e "`cut -d' ' -f1 < /proc/loadavg` 100 * p"
29.00
For the CPU Utilization, because it is supposed to be on a short time
interval, I can use the first value from /proc/loadavg.
The load average is not the same thing as CPU usage.
A load average of 1 means there is one process waiting for something (usually the CPU or disk).
A load average of 2 means there are two processes waiting.
A load average of 0.5 (over the last minute), can mean that for 30 seconds, there was one process waiting, and for 30 seconds, there were no processes waiting. It can also mean that for 15 seconds there were two processes waiting, and for 45 seconds there were no processes waiting. The keyword here is average.
If you want to get the CPU utilization, then this is probably the most portable way:
$ top -bn2 | grep "Cpu(s)" | \
tail -n1 | \
sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | \
awk '{print 100 - $1"%"}'
Note you need to use -n2 to get fairly accurate results.
I've adapted this from this answer, which also lists some other possibilities, some simpler, but most tools mentioned aren't installed by default on most systems.
Network
For the bandwidth monitors I haven't the slightest clue of what I
could use in /proc to get that sort of information so I'm open to all
suggestions.
You can use the output of ifconfig, for example, on my system:
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.178.28 netmask 255.255.255.0 broadcast 192.168.178.255
inet6 2001:980:82cd:1:20c:29ff:fe9e:c84b prefixlen 128 scopeid 0x0<global>
inet6 fe80::20c:29ff:fe9e:c84b prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:9e:c8:4b txqueuelen 1000 (Ethernet)
RX packets 45891 bytes 36176865 (34.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20802 bytes 2603821 (2.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
It's the RX packets & TX packets we want. Let's extract just those values:
$ ifconfig ens33 | grep -E '(R|T)X packets' | grep -Eo '\([0-9].*\)' | tr -d '()'
34.5 MiB
2.5 MiB
First we grep all the lines starting with RX or TX
With those lines, we then grep for a parenthesis \(, followed by a number [0-9], followed by any characters .*, followed by a closing parenthesis \). With the -o flag we show only the matching part, instead of the whole line.
With tr, we remove the unwanted parentheses.
This should be what you want. If you want to get a number of bytes, you can use a different grep pattern in the second grep. I'll leave it as an exercise to you what exactly that is.
Here's how you can print the first number output by cat /proc/loadavg as a percent value (but see #Carpetsmoker's caveat regarding whether that makes sense), rounded to 1 decimal place:
printf "1-minute load average: %.1f%%\n" \
$(bc <<<"$(cut -d ' ' -f 1 /proc/loadavg) * 100")

get the next word after grep matching [duplicate]

This question already has answers here:
Get string after character [duplicate]
(5 answers)
Closed 7 years ago.
I'm using this command to retrieve the signal average power of a client connected to an Access Point:
iw dev wlan0 station dump | grep -E 'Station|signal avg':
I got the following info:
Station "my_MAC_Address" (on wlan0)
signal avg: -46 dBm
In bold is what I matches with grep and I just only want to get the word after that matching, i.e the MAC address and the number -46.
I've been playing with awk but without success.
hope you can help me!
iw dev wlan0 station dump | grep -Po '(?<=Station\s|signal avg:\s)[^\s]*'
This regexp uses a so-called lookbehind syntax. You can read about it here
Example output:
00:11:22:33:44:55
-40
Update:
Thanks for voting this answer up. Now I know another solution:
iw dev wlan0 station dump | grep -Po '(Station\s|signal avg:\s)\K[^\s]*'
Which is actually a shorthand for the solution above. \K basically means "forget everything before its occurance".
You can use two grep to do this as well
iw dev wlan0 station dump | grep -E 'Station|signal avg' | grep -o [^'Station|signalavg'].*
One possible awk solution which plays fast and loose with whitespace is:
... | awk '$1 == "Station" { print $2 }
$1 $2 == "signalavg:" { print $3 }'

Extracting an IP address to a variable using Expect script

Hi I am new to Expect scripting, and I have been trying to fetch an IP address into a variable using following :
set timeout -1
spawn $env(SHELL)
match_max 100000
send "ifconfig | grep -A 1 'eth1' | tail -1\r "
expect -re "inet addr:.* " {send "ping $expect_out(0,string)\r"}
send -- "exit\r"
expect eof
The problem is that it is trying to ping with the result of the ifconfig command which has some string characters in it.
Could anyone help me to extract just IP address from the ifconfig command and store it in a variable? I have been using $expect_out(buffer) as well, but just couldn't get my head around it. Any help along these lines would be much appreciated.
You don't need to spawn a shell:
spawn ifconfig eth1
expect -re {inet addr:(\S+)}
set ipaddr $expect_out(1,string)
expect eof
spawn ping -c 10 $ipaddr
expect eof
In fact, you don't need to use Expect: in plain Tcl (with extra error checking for ping):
if {[regexp {inet addr:(\S+)} [exec ifconfig eth1] -> ipaddr]} {
set status [catch [list exec ping -c 10 $ipaddr] output]
if {$status == 0} {
puts "no errors from ping: $output"
} else {
puts "ERROR: $output"
}
}
You could use regexp on your existing code:
expect -re "inet addr:.* " {
regexp {inet.*?(\d+\.\d+\.\d+\.\d+)} $expect_out(buffer) match ip
puts "Pinging $ip"
send "ping $ip\r"
}
In the line:
regexp {inet.*?(\d+\.\d+\.\d+\.\d+)} $expect_out(buffer) match ip
The regexp command is capturing the ip address in a bracketed 'capture group':
(\d+\.\d+\.\d+\.\d+)
And then storing it in the variable ip.
The expect_out(buffer) variable is the source string containing everything read so far by expect (up to your expect -re command), and match is another variable which stores a string that matches the entire regex (everything from 'inet' to the end of the ip address.) match is simply there to conform to the regexp syntax of requiring a variable to be present before the capture groups- it's throwaway data in this particular example- a reworked version of regexp could use match to store the ip for this example, but in general I find capture groups more flexible, as you can have several to catch different pieces of data from a single string.
You may want to read up on the regexp command and, regular expressions in general, as Expect makes quite extensive use of them.
Change your 'send "ifconfig | grep -A 1 'en1' | tail -1\r" to look like the below line instead.
send "ifconfig | grep -A 1 'en1' | tail -1 | cut -d' ' -f2\r"
$ifconfig
eth0 Link encap:Ethernet HWaddr 00:1b:fc:72:84:12
inet addr:172.16.1.13 Bcast:172.16.1.255 Mask:255.255.255.0
inet6 addr: fe80::21b:fcff:fe72:8412/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:638661 errors:0 dropped:20 overruns:0 frame:0
TX packets:93858 errors:0 dropped:0 overruns:0 carrier:2
collisions:0 txqueuelen:1000
RX bytes:101655955 (101.6 MB) TX bytes:42802760 (42.8 MB)
Memory:dffc0000-e0000000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:3796 errors:0 dropped:0 overruns:0 frame:0
TX packets:3796 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:517624 (517.6 KB) TX bytes:517624 (517.6 KB)
try this:
ifconfig | sed '2,2!d' | sed 's/.*addr://' | sed 's/\ .*//' > ipaddress
this will give ip
$vi ipaddress

Bash - How to know my Linux server IP adress? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
Is there a way to echo only the server ip adress from Bash? I am on a Linux/Debian6.
My intent is to write to "/etc/hosts" the pair domain_name IP for each new domain I register in the server.
As this bash script will be opened for public use, I am trying to find a way of getting this information via cli.
CONCLUSION:
This is the final code, based on the clues my friends helped me with:
newhost() {
DMN=$1
X=`ifconfig | grep Bcast`
Y=`echo "${X#*:}"`
DNS=`echo "${Y%\ B*}"` # server DNS(207.112.37.222)
H='/etc/hosts' #hostfile
PAIR="$DNS\t$DMN"
if grep -i --silent "$DMN" "$H"; then
echo -e "$DMN already exists in $H"
else
bash <<EOF
echo -e "$PAIR" >> "$H"
EOF
echo -e "$PAIR added to $H"
fi
}
By the way, Isn't it funny that some born-already-smart dudes voted to close the question?
Thanks.
use:
ifconfig - your ip will be after the inet addr: in this case 1.1.1.1
sample output:
root#server [~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0A:E4:89:0B:97
inet addr:1.1.1.1 Bcast:1.1.1.63 Mask:255.255.255.192
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1/or modify
RX packets:14804377317 errors:0 dropped:0 overruns:0 frame:0
TX packets:11766937374 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:13799286299902 (12.5 TiB) TX bytes:4891709752100 (4.4 TiB)
Interrupt:169 Memory:fa000000-fa012800 will be useful,
http://www.debianadmin.com/network-interface-configuration-using-ifconfig.html
ip -4 a l dev $DEVICE | grep inet | awk '{ print $2 }'
replace $DEVICE with the device name. eth0 should be the right in the most cases

Resources