There are a number of problems here. First, timeout
takes as argument a single command. So when you write
timeout 10s ping -c 5 www.google.com | awk '{print "from local to google |", $0;}'
what happens is more or less this:
( timeout 10s ping -c 5 www.google.com ) | awk '{print "from local to google |", $0;}'
I.e. timeout
kills ping
, not the entire pipe, and thus you get back the exit code of the pipe (namely that of awk
).
To get the exit code of timeout
you need a subshell. But since timeout
takes as argument a single command, you need to write that explicitly:
timeout 10 sh -c 'ping ... | awk ...' sh
Alternatively you could just time the last command in the pipe (i.e. awk
):
ping ... | timeout 10 awk ...
This should work fine for ping | awk
, but it can be prone to race conditions for other commands. And if ping
produces a lot of output you might also may get a SIGPIPE, for killing the listener.
Back to your question, you also want to put all that in background. To get the exit code of a background command you need to wait
for it:
timeout 10 sh -c 'ping ... | awk ...' sh &
wait $!
echo $?
Sadly bash
doesn't have an asynchronous wait
, which kind of defeats the purpose of running the commands in background. You can however run other commands before wait
.