3

Output of just the ping command:

[root@servera ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=8.04 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=7.47 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=7.72 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=7.50 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 7.473/7.683/8.037/0.225 ms

I want to just capture the integer 4 from the "4 received".

ping -c 4 8.8.8.8 | awk -F ',' '/received/ { print $2 }'

The result is 4 received. I want to capture just the number 4 from the above command. How can I do that? The delimiter is space now.

0

8 Answers 8

10

All you need is:

awk '/received/{print $4}'

e.g. using cat file to get the same input for awk as in your question:

$ cat file
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=8.04 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=7.47 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=7.72 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=7.50 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 7.473/7.683/8.037/0.225 ms

$ cat file | awk '/received/{print $4}'
4

Obviously just replace cat file with ping -c 4 8.8.8.8 for your real testing.

In response to the OPs comment below asking what line it's matching on:

$ awk '/received/' file
4 packets transmitted, 4 received, 0% packet loss, time 3007ms

and why field number 4 is the one to print:

$ awk '/received/{for (i=1; i<=NF; i++) print i, "<" $i ">"}' file
1 <4>
2 <packets>
3 <transmitted,>
4 <4>
5 <received,>
6 <0%>
7 <packet>
8 <loss,>
9 <time>
10 <3007ms>
3
  • Can you explain how the integer 4 aligns to fourth field? When you do {print $4}, which line and which filed number is it printing ? Just want to understand the process.
    – Cruise5
    Apr 5 at 0:45
  • 1
    On the line: 4 packets transmitted, 4 received, 0% packet loss, time 3007ms field 1. 4 field 2.packets field 3. transmitted, field 4. 4 The awk is selecting the line that matches received
    – Scot
    Apr 5 at 1:36
  • 1
    @Cruise5 I added a breakdown of what the script is doing at the end of my answer.
    – Ed Morton
    Apr 5 at 11:11
7

There is another way to do this with awk (similar to comment on one of the answers)

awk -F, '/received/ {print int($2)}'

function int() will "discard" nonnumber information after the first number

1
7

You have already gotten some fine awk answers, so here are a few alternatives.

  1. GNU grep

    $ ping -c 4 8.8.8.8 | grep -oP '\d+(?= received,)'
    4
    
  2. Perl

    $ ping -c 4 8.8.8.8 | perl -lne 'print $1 if /(\d+) received,/'
    4
    
  3. sed

    $ ping -c 4 8.8.8.8 | sed -En 's/.*, ([0-9]+) received,.*/\1/p'
    4
    
6

The field separator can be a regular expression, so you can set multiple field delimiters in awk using [ ] such as:

awk -F '[, ]' '/received/ {print $5}'

However in this case I would probably just remove the word received:

 awk -F, '/received/ {sub(/received/, "", $2); print $2}'

The awk sub() function sub(regexp, replacement [, target]) will find the pattern represented by the regular expression, replace it with replacement, and can optionally be narrowed to a target column.

6
  • 3
    I wonder if it would anger the awk gods if you simply forced numeric conversion of the field i.e. awk -F, '/received/ {print $2+0}' ? Apr 4 at 16:41
  • What is the function of sub and "" in the parenthesis)?
    – Cruise5
    Apr 4 at 17:39
  • /received/ {sub(/received/, "", $2); print $2} = sub(/received/, ""){print $2} in this case, but it still leaves undesirable blanks either way.
    – Ed Morton
    Apr 4 at 17:40
  • +1 for answering the question as asked, rather than providing workarounds. You never know when someone will actually need 2 separate delimiters an stumble on this thread. Apr 5 at 14:09
  • 1
    @shadowtalker Conversely, sometimes they're asking the wrong question, i.e. it's an XY problem.
    – Barmar
    Apr 6 at 14:51
3
 ping -c4 <ipadress>|awk '/received/{for(i=1;i<=NF;i++){if($i ~ /received/){print $(i-1)}}}'

output

4
0
2

All of the answers here are good at addressing OP's specific rqeuirements.

However, none of them address the general question of splitting a field on a delimiter other than the "main" delimiter used by the main AWK loop.

The answer is to use the split() function, available in all AWK versions that I know of, including the One True AWK and the POSIX specification:

/received/ {
  split($2, recv, " "); print(recv[1])
}

This emits 4 on stdout:

awk -F ',' '
/received/ {
  split($2, recv, " "); print(recv[1])
}
' <<\EOD
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=8.04 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=7.47 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=7.72 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=7.50 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 7.473/7.683/8.037/0.225 ms
EOD

Note split() has the same semantics as top-level record splitting with FS. That is, it should behave exactly like a second delimiter. This is implied by (but not explicitly stated in) the POSIX specification, and is explicitly stated in the GNU AWK manual page. The main effect of this that (like FS) if the separator pattern is " ", leading and trailing whitespace is stripped and consecutive whitespace characters are treated as single spaces.

0
1

Bash command line:

recv=( $(ping -c 4 8.8.8.8 | grep received) ); echo ${recv[3]}

Capture the result of 'ping' piped to 'grep' as the array 'recv'; display the 3rd element of the array.

Output:

4
0

Or do it in the most awk fashion without physically counting fields :

mawk NF RS='^.+tted,[ \t]*|[ \t]*recei.+$' testfile4.txt

4

If you use the quick printout feature from gawk, you can see that RT matches the entire tail of it :

RT: " received, 0% packet loss, time 3007ms\nrtt min/avg/max/mdev = 7.473/7.683/8.037/0.225 ms\n"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.