K.Wanter
K.Wanter

Reputation: 1059

Timeout a bash script when there is no output for a while

I have a.sh that calls a b.sh:

. "b.sh" 2>&1 | tee -a "log.txt" &
wait $!

xxx

how can I write a condition that detects when b.sh is not outputting log.txt for a certain time and then run through wait $!

Upvotes: 1

Views: 1103

Answers (3)

William Pursell
William Pursell

Reputation: 212208

You could do:

#!/bin/bash


./b.sh 2>&1 | { while read -t 3 line; do
    echo "$line" >> log.txt; done; pkill -g 0; } &

wait $!

Note that in your example, your script is not calling b.sh, but is sourcing it. This solution calls b.sh. That seems cleaner, as reading the output of a sourced script is truly strange behavior.

But note that if b.sh is calling some long running program that is generating a lot of output but doing it slowly, you will undoubtedly run into buffering issues. The long running program will very likely be block buffering its output, so although it is generating data periodically into its internal buffers, the read in the while loop will not see it and may timeout prematurely.

Upvotes: 2

Timo
Timo

Reputation: 513

Quite old topic but I've done a mix of all the solutions suggested to fit my need and I think

#!/bin/bash

set -e

rm -rf log.txt

touch log.txt

rm -rf finish

./"b.sh" > log.txt 2>&1 && touch finish &

process_to_keep=$!

{ tail -f log.txt | while read -t 3 line && kill -0 "$process_to_keep" 2>/dev/null; do
    echo "$line"
done;
if [ -e finish ]; then
  echo "finish properly"
else
  if kill -0 "$process_to_keep" 2>/dev/null; then
    echo "no output after 3s"
    kill $process_to_keep 2>/dev/null
  else
    echo "process not alive anymore"
  fi

  exit 1
fi; } &

process_to_wait=$!

wait $process_to_keep
echo "done" >> log.txt
wait $process_to_wait

echo "cleaning temporary files"
rm -rf finish
rm -rf log.txt

This script will stop if the script b exit at any moment (without any delay which was the case with other solution) and it will also exit if there is no output for 3s with a proper message in the console.

I think this solution does not work properly on macOS.

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 140940

. "b.sh" 2>&1 | tee -a "log.txt" &
child=$!
# loop while child process exists
while kill -0 "$child" 2>/dev/null; then

     # get first length
     if [[ -z "$len1" ]]; then
          len1=$(wc log.txt)
     fi

     # sleep for a certain time
     sleep 1

     # get length of file after 1 second
     len2=$(wc log.txt)

     # compare lengths
     if [ "$len1" == "$len2" ]; then
         echo "Och my! File log.txt did not change in 1 second"
         break
     else
         echo "All good! File log.txt did change in 1 second"
     fi

     # len1 becomes len2
     len1=$len2;
fi

Upvotes: 0

Related Questions