1

I have a bash script with a function that is not returning from the function as I think it should.

If the host responds to any of the 3 pings - it should exit the function with a return code 0 - otherwise it would fall out of the loop and exit with a return code 1.

What I find confusing is the trace shows executing the return 0 - but not actually doing it.

I also tried wrapping the ping with a 2nd while loop with a break 2 from the inner "while" but that didn't work as expected either.

What am I missing?

#!/bin/bash
pingCheck() {
  ping -c 3 -W 1 $1 2>&1 | grep --line-buffered time= | while read a; do
    return 0
  done
  return 1
}

set -x
pingCheck note5 || exit
...

and here is the trace output to a reachable host

+ ping -c 3 -W 1 note5
+ grep --line-buffered time=
+ read a
+ return 0
+ return 1
+ exit 

and here is the trace output to a non-reachable host (works as expected)

+ ping -c 3 -W 1 note5x
+ grep --line-buffered time=
+ read a
+ return 1
+ exit
0

2 Answers 2

4

The return 0 statement was associated with while loop body, and since when each parts of pipelines in bash was run in subshell, the return 0 cause the subshell executed while loop exit, not the entire function.

You can simply drop the while part, and using grep -c:

pingCheck() {
  num_res=$(ping -c 3 -W 1 "$1" 2>&1 | grep -c --line-buffered time=)
  if [ "$num_res" -ne 0 ]; then
    return 0
  else
    return 1
  fi
}

In some shells like zsh and ksh, the last part of pipelines was run in current shell, so your function will work in those shells.

Sign up to request clarification or add additional context in comments.

1 Comment

Ah! yes - I came from the old ksh and forgot about the subshell here. I am backgrounding this call to many hosts at once and wish it to return as quickly as possible. If all hosts are up, the "wait" finishes in a 100ms or so without the 2+ second delay for 3 successful pings. Hence, the reason to return on the 1st successful reply.
1

Or drop everything except ping:

pingCheck() {
    if ping -c 3 -W 1 $1 2>&1 ; then
        return 0
    else
        return 1
    fi
}

If you are simply interested in 3-successful pings with no output and a return of 0 on success and 1 on failure, then:

pingCheck() {
    if ping -c 3 -W 1 $1 >/dev/null 1>&2 ; then
        return 0
    else
        return 1
    fi
}

note: the point made is well taken. Using only ping will cause a return on the first failure. So this will confirm 3 successful pings, or a failure of 1 of the 3.

5 Comments

How about the case when the first two success, the last one fail? At least, you should double quote your variables.
That is the caveat of using only ping, it will return on the first failure.
I don't see the ping documentation mention about the case, can you give me the reference? As I seen in practice, ping won't return on the first failure.
The return on failure is not a result of a ping option, but due to its return value in response to a failure. -c 3 tells ping to return a maximum of 3 responses and -w provides a 1 sec timeout in between each response. However, if the network is unreachable ping will not receive any response within the 1 second timeout and will exit with a return of 1.
The if/then/return/else can also be removed altogether since the exit code of the last command is the exit code of the function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.