1

I want a Bash script to generate some output messages. The script is supposed to capture messages, do some filtering, transform, and then output them to the screen.

The filtered results are correct in the output, but the script is not terminated. I must press a return key to finish it. How do I fix it?

Demo script:

#!/bin/bash

exec &> >( 
        {
        while read line; do
            [ "$line" = "exit" ] && break 
            echo "`date +%H:%M:%S.%N` $line" 
        done
        echo "while finish"
        } )

for ((i=3;i--;)); do
    echo "text $i"
done

echo "exit"
2
  • I tried to improve the description. Now it looks... acceptable. But still don't quite understand what you mean. Commented Nov 12, 2016 at 16:01
  • stackoverflow.com/q/40564647/1030675 Commented Nov 12, 2016 at 16:02

1 Answer 1

1

The script does terminate, but the script itself finishes before the background process that writes the output does, so the prompt is displayed first, then the output, leaving your terminal with a blank line that looks like the script is still running. You could type any command instead of hitting return, and that command would execute.

To avoid this, you need to run the while loop in an explicit background job that you can wait on before exiting your script.

mkfifo logpipe
trap 'wait $logger_pid; rm logpipe' EXIT

while read line; do
    [ "$line" = "exit" ] && break
    echo "$(date +%H:%M:%S.%N) $line"
done < logpipe &
logger_pid=$!

exec &> logpipe

# ==========

for ((i=3;i--;)); do
    echo "text $i"
done

echo "exit"

The while loop runs in the background, reading its input from the named pipe logpipe. Once that is running, you can redirect all your output to the pipe and start your "main" script. The exit trap ensures that your script doesn't actually exit until the while loop completes; it also cleans up the named pipe for you.


You might not have noticed yet, but there is no guarantee that the while loop will receive the merged standard output and standard error in the exact order in which things are written to them. For instance,

echo out1
echo err1 >&2
echo out2
echo err2 >&2

may end up being read as

out1
err1
err2
out2

Each stream itself will remain in order, but the two could be arbitrarily merged.

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

Comments

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.