Reputation: 1059
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
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
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
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