0

I'm trying to write a bash script that will execute and if a certain condition (grep) is met then the script exits but if the grep is not found within X seconds then I'd like it to echo something and then exit. The biggest issue is one of the commands in it is long running and I have to exit it otherwise is just keeps going and going until I close the terminal.

To help, we're using the Pusher CLI https://pusher.com/docs/pusher_cli/documentation to ping IoT devices out in the field.

To get this to work I'm first subscribing to the channel and then backgrounding this process, waiting 5 seconds and then sending the ping. I'm then greping the output from the background process and looking for a "pong" in the response and exiting if it's found. This is all working great, the problem I'm running into is when a "pong" is not found (device offline) and the subscribe process just keeps running indefinitely in the background and I have no sense that the device is offline.

So I'd like something that can fire off the commands and then after 10 seconds kill everything but if the "pong" is found then kill everything that way.

Here is the script that I have going so far

ping () {
  subscribe_channel $1 &
  sleep 5
  ping_channel $1
}

ping_channel () {
  pusher channels apps trigger --app-id $appid --channel $1 --event $event --message $message
}

subscribe_channel () {
  while read -r line; do
    echo $line
    if [[ $(echo $line | grep "pong") ]]; then
      echo "online"
      exit
    fi
  done < <(pusher channels apps subscribe --app-id $appid --channel $1)
}

ping channel
2
  • BTW, there are a whole lot of quoting bugs here. Run your code through shellcheck.net and fix what it finds. Commented Apr 18, 2018 at 20:22
  • Also, if you want to just test whether a line contains a substring, [[ $line = *pong* ]] is literally orders of magnitude faster than running a pipeline invoking grep inside a process substitution. Commented Apr 18, 2018 at 20:23

1 Answer 1

1

You can run your ping_channel with a timeout and to exit after 10 seconds.

If a command exits due to a timeout, then its return code will be 124, rather than 0.

An example of this being:

timeout 1 sleep 10  # Try to sleep for 10 seconds but timeout after 1 second
echo $?  # Exits with a status of 124

timeout 2 sleep 1  # Sleep for 1 second, the timeout of 2 seconds is not hit
echo $?  # Exits with a status of 0

To use this in your code, change the line:

pusher channels apps trigger --app-id $appid --channel $1 --event $event --message $message

to:

timeout 10 pusher channels apps trigger --app-id $appid --channel $1 --event $event --message $message
pusher_status=$?
if (( pusher_status == 124 )); then
    echo "ping_channel has timed out after 10 seconds"
fi

Hopefully you can use the above to work with your code.

Edit:

timeout is preinstalled on some Linux OS variants, but you may need to install it if it is not.

If you are unable to install it, then some solutions on the following BashFAQ may help: BashFAQ068 (thanks @CharlesDuffy)

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

6 Comments

Using arithmetic construct ((...)) is better in this case. So, if ((pusher_status == 124)); then ....
Hi @codeforester, Thanks. I'm interested - I've always done arithmetic using [[..]]. How comes using ((..)) is better?
You don't need a $ to expand variables inside (( )) and it offers more operations as well. Remember, = (assignment) and == are not same inside (( ... )).
Note that timeout is not built into bash -- it's an external tool (and not standardized by POSIX and thus guaranteed to be provided by your OS vendor either). You might want to tell the OP where to get it, or at least specify that it needs to be installed for this answer to work.
(For a canonical, maintained reference that covers timeout and equivalent tools, I'd suggest adding a link to BashFAQ #68).
|

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.