Searching for a particular string using Regex in Bash/Shell Scripting - linux

I am trying to echo out the the average round trip time for 4 ICMP echo/echo rely packets (in ms) for a website like google. This is my code as of now.
echo "$(ping -c 4 google.com | grep '??????')"
Pinging the website works but I have no idea how to echo out only the average round trip time. I have only used Regex for validation on web forms, but I haven't used it in awhile. I assume I can use Regex to find only what I am searching for, but if there is a better way of doing this, that would also be great. I am writing this using shell scripting for linux ubuntu
This is an example of the output. The only part of this I need is the part at the bottom where it says rtt min/avg/max/mdev = 14.556/14.579/14.614/0.088 ms.
PING google.com (142.250.74.238) 56(84) bytes of data.
64 bytes from par10s40-in-f14.1e100.net (142.250.74.238): icmp_seq=1 ttl=108 tim e=14.5 ms
64 bytes from par10s40-in-f14.1e100.net (142.250.74.238): icmp_seq=2 ttl=108 tim e=14.5 ms
64 bytes from par10s40-in-f14.1e100.net (142.250.74.238): icmp_seq=3 ttl=108 time=14.5 ms
64 bytes from par10s40-in-f14.1e100.net (142.250.74.238): icmp_seq=4 ttl=108 time=14.6 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 14.556/14.579/14.614/0.088 ms

Assuming the ping output looks like the following:
$ ping -c 4 google.com
PING google.com (172.217.14.238): 56 data bytes
64 bytes from 172.217.14.238: icmp_seq=0 ttl=118 time=78.019 ms
64 bytes from 172.217.14.238: icmp_seq=1 ttl=118 time=62.416 ms
64 bytes from 172.217.14.238: icmp_seq=2 ttl=118 time=63.019 ms
64 bytes from 172.217.14.238: icmp_seq=3 ttl=118 time=62.415 ms
--- google.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 62.415/66.467/78.019/6.674 ms
In this scenario the average time is 66.467 (ms)
One awk solution:
awk '/avg/ {split($0,arr,"/"); print arr[5]}'
Where:
/avg/ - look for line with the string avg
split($0,arr,"/") - split the line using a forward slash (/) as the delimiter, place the segments in the arr[] array
print arr[5] - print the 5th element of the arr[] array
Combining with the ping:
ping -c 4 google.com | awk '/avg/ {split($0,arr,"/"); print arr[5]}'
66.467
And if we need to include the measurement of time (ms in this case), we can also print the last field of the line that contains the string avg, eg:
ping -c 4 google.com | awk '/avg/ {split($0,arr,"/"); print arr[5],$NF}'
66.467 ms
NOTES:
OP may need to tweak the awk command if their ping output is in a different format
obviously (?) each time the ping is run we're likely to get a slightly different value.
if OP wants to be 100% certain of the value then the ping command output should be saved to a file (or variable) and then run the awk command against said file (or variable)

Related

Command 'bg' and '&' don't work on Linux terminal

I'm running Linux:
Linux davide 5.7.0-kali1-amd64 #1 SMP Debian 5.7.6-1kali2 (2020-07-01) x86_64 GNU/Linux
When I try to run some process in the background they appear on the terminal and I can see all the STDOUT. I tried both with the command "'Ctrl+z'+bg" and '&' after the expression.
Example: Ping -c 10 127.0.0.1 &
It seems that the process is running in the background (in fact I receive the PID like if it is working) but then I see all the output in the terminal.
I can also run other commands like here:
$ ping -c 10 127.0.0.1 &
[1] 2079
$ PING 127.0.0.1 (127.0.0.1) 56 (84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.053 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.053 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.047 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.052 ms
64 bytes from 127.0.0.1: icmp_seq=6 ttl=64 time=0.059 ms
64 bytes from 127.0.0.1: icmp_seq=7 ttl=64 time=0.053 ms
ls
Desktop Documents Downloads Music Pictures Public Templates Videos
$ 64 bytes from 127.0.0.1: icmp_seq=8 ttl=64 time=0.054 ms
64 bytes from 127.0.0.1: icmp_seq=9 ttl=64 time=0.057 ms
64 bytes from 127.0.0.1: icmp_seq=10 ttl=64 time=0.054 ms
--- 127.0.0.1 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9215ms
Rtt min/avg/max/mdev = 0.041/0.052/0.059/0.004 ms
[1]+ Done ping -c 10 127.0.0.1
I don't know if is a bug of the new release or a misconfiguration, but I could't find any topic about this. Can Somebody help with this?
& is used to make the command run the background but it does not make its output to hide.
If you want to redirect the output to a file use >, which is used to redirect the output.
E.g:
ping www.wikipedia.com > output.txt &
Also, you can redirect the output to /dev/null if you don't want to store it although it would not be relevant here.
Regarding Ctrl + z: It is used to put a command to suspend mode not run in background. For more information see here

How to make command ping to output with domain name which I ping?

E.g., I type ping www.domain.com and the output I want is like:
64 bytes from yyy.xxx.com (www.domain.com): icmp_seq=32 ttl=52 time=84.8 ms
(or other format with domain name).
Not possible by any flag ping command provides.
But we always can roll up our sleeves and get hands dirty.
ping google.com | sed -e 's/\([[:digit:]]*\+\:\)/\1 (google.com)/g'
Considering output format includes something like that "64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.397 ms" we can try to parse with sed.
So, sed looks for digit and ":" symbol afterwards, replaces it to "digit: (google.com)".

Unable To Ping External Hosts Using In Perl Using Net::Ping

In Perl (5.16.3), I'm trying to use Net::Ping to test whether a remote host is available or not. I'm able to ping "internal" hosts which I know are online within my company's LAN, but I'm unable to ping "external" ones. Specifically, trying to ping 'www.google.com' fails.
My code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::Ping;
my $hostname1 = 'prophet'; #internal
my $hostname2 = 'www.google.com'; #external
my $p;
my $rv1;
my $rv2;
$p = Net::Ping->new();
$rv1 = $p->ping($hostname1);
$rv2 = $p->ping($hostname2);
print "Response1: $rv1\n";
print "Response2: $rv2\n";
Yields this result:
[oracle#prophet:bin]$ ./ping_test
Response1: 1
Response2: 0
[oracle#prophet:bin]$
Even though using the (CentOS) ping utility does show that 'www.google.com' is available:
[oracle#prophet:bin]$ which ping; ping www.google.com
/usr/bin/ping
PING www.google.com (64.233.177.105) 56(84) bytes of data.
64 bytes from 64.233.177.105: icmp_seq=1 ttl=46 time=15.6 ms
64 bytes from 64.233.177.105: icmp_seq=2 ttl=46 time=15.6 ms
64 bytes from 64.233.177.105: icmp_seq=3 ttl=46 time=15.7 ms
64 bytes from 64.233.177.105: icmp_seq=4 ttl=46 time=16.5 ms
^C
--- www.google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 15.614/15.884/16.547/0.394 ms
[oracle#prophet:bin]$
I realize that if I do this (in my Perl program):
$p = Net::Ping->new('icmp');
Then su - root before I run the program, it'll work...
[oracle#prophet:bin]$ su root
Password:
[root#prophet:bin]# ./ping_test
Response1: 1
Response2: 1
[root#prophet:bin]#
... but, I'd like to be able to use Net::Ping (w/ icmp packets) without having to su - root. It's actually a requirement for an automation program I need to write. It seems a little crazy to me that I can run the ping (CentOS) utility as a regular user and get the expected results, but that trying to use Net::Ping as a regular user is a no-go.
Any ideas?
G
The ping utility works because it's setuid — it runs with root privileges, even when executed by a normal user:
-rwsr-xr-x 1 root root 44168 May 7 2014 /bin/ping
Like it or not, using ICMP inherently requires root privileges. You can't do it as a normal user.
If you want to check for connectivity, consider making a TCP connection. (Or, heck, a full HTTP request.)

Why ping unknown host is happening when inside a while loop?

I am trying to get a column from a csv file and ping each line in a while loop
But every time it just show ping:unknown host (website)
#!/bin/bash
while IFS=, read num ip; do
echo $num
ping -c 10 $ip
done <site.csv
And the format of the csv file is
1, facebook.com
2, google.com
And the result will always be
ping: unknown host facebook.com
ping: unknown host google.com
But when I just ping the website directly, it is actually working, so i think is not the network problem
-bash-4.1$ ping -c 2 facebook.com
PING facebook.com (173.252.120.6) 56(84) bytes of data.
64 bytes from edge-star-shv-12-frc3.facebook.com (173.252.120.6): icmp_seq=1 ttl=70 time=94.1 ms
64 bytes from edge-star-shv-12-frc3.facebook.com (173.252.120.6): icmp_seq=2 ttl=70 time=93.8 ms
--- facebook.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1094ms
rtt min/avg/max/mdev = 93.882/94.040/94.199/0.345 ms
Is it the while loop or read the column from the csv causing the prooblem?
Is there a way to use a wile loop to read the site from the csv file and ping it?
Following up on Glenn Jackman's suggestion that the problem is DOS line-endings, here is a simple way to make sure that they are removed from the input. Replace:
while IFS=, read num ip; do
With:
while IFS=$',\r' read num ip; do
By adding \r to IFS, this makes the shell treat the DOS character as a field separator. This means it does not become part of ip.

Bash Script to log average ping times, every 20 seconds for a day

I'm currently trying to write a bash script to log the average ping time of atm. three different targets, every 20 seconds for a whole day.
This is what I currently have..
#!/bin/bash
echo "SCRIPT STARTED" >> pingthing.log
date +%d.%m.%y' '%R:%S >> pingthing.log
for i in $(seq 1 4320);
do
date +%d.%m.%y' '%R:%S >> pingthing.log
#save just target IP and avg time.
ping -c 3 -q -W 2 8.8.8.8 >> pingthing.log
ping -c 3 -q -W 2 64.25.40.16 >> pingthing.log
ping -c 3 -q -W 2 96.17.199.48 >> pingthing.log
sleep 20
done
echo "SCRIPT ENDED" >> pingthing.log
date +%d.%m.%y' '%R:%S >> pingthing.log
Now to my question...
How to sed/awk the ping summary to just save the target and the avg time?
and how could I handle a 100% loss case?
EDIT: sorry, I have no experience with sed/awk but know that it can be done with these tools.. let me try to clarify myself
This is currently what is saved in my logfile.. yet this only shows the very start of it
SCRIPT STARTED
07.02.14 22:14:13
07.02.14 22:14:13
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 127.773/152.321/192.204/28.452 ms
PING 64.25.40.16 (64.25.40.16) 56(84) bytes of data.
--- 64.25.40.16 ping statistics ---
3 packets transmitted, 3 received, +2 duplicates, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 213.889/237.182/286.825/26.656 ms
PING 96.17.199.48 (96.17.199.48) 56(84) bytes of data.
--- 96.17.199.48 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 305.028/340.081/375.135/35.058 ms
now I'd want to have only the target and its avg. time of the ping command like
SCRIPT STARTED
07.02.14 22:14:13
07.02.14 22:14:13
8.8.8.8 152.321
64.25.40.16 237.182
96.17.199.48 340.081
I'm aware that I should pipe the ping command to sed/awk but as I have no experience with this I left it out for the time being.
I wouldn't want you to just solve everything, I'm here to discuss and learn.
For the 100% loss problem.. the output would look like this
ping -W 2 -q -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2016ms
Now here is no summary line as in the ones with successful ping, so I can't use sed/awk for that pattern..
Given your posted sample input file:
$ awk -F'[ /]' 'NR~/^[123]$/; /^---/{ip=$2} /^rtt/{print ip, $8}' file
SCRIPT STARTED
07.02.14 22:14:13
07.02.14 22:14:13
8.8.8.8 152.321
64.25.40.16 237.182
96.17.199.48 340.081
You don't tell us what output you want for "the 100% loss problem" so I don't know what you want done with that. Just include it in your sample input and expected output unless there's some specific reason not to that isn't clear so far.
If all you want is something printed stating 100% loss, you could just tweak the script to:
awk -F'[ /]' 'NR~/^[123]$/; /^---/{ip=$2} /^rtt/{print ip, $8} /100% packet loss/{print ip, "100% packet loss"}' file
The possibilities are endless... just tell us what you need to be output.
Here it is one line at a time with comments:
awk -F'[ /]' ' # use space and / as the field separator
NR~/^[123]$/; # if youre on input line 1, 2, or 3, print that line (the default action)
/^---/{ip=$2} # if the line starts with 3 dashes, save the 2nd field as the IP address
/^rtt/{print ip, $8} # if the line starts with rtt, print the saved IP address and the 8th field which is the averages
/100% packet loss/{print ip, 2000} # if the line contains the 100%... statement, print the IP address and a default value of 2000
' file

Resources