I have following response checker in a script:


echo "--- BEGIN ---"
echo "--- END ---"

while true; do
    read -r -n 1 -p "Continue? [y/n]: " REPLY
    case $REPLY in
      [yY]) break ;;
      [nNqQ]) echo;exit ;;
      *) printf "\033[31m%s\033[0m\n" " invalid input: ${REPLY}"

test_fn /tmp/warning 

it works fine...

$ ./test.sh

--- BEGIN ---
test warning
--- END ---

Continue? [y/n]: a invalid input: a
Continue? [y/n]: s invalid input: s
Continue? [y/n]: d invalid input: d
Continue? [y/n]: w invalid input: w
Continue? [y/n]: s invalid input: s
Continue? [y/n]: q

...until I change line:

test_fn /tmp/warning

with line:

test_fn /tmp/warning | tee -a /tmp/logfile

then, it scrambles lines:

$ ./test.sh

--- BEGIN ---
test warning
Continue? [y/n]: --- END ---

aContinue? [y/n]:  invalid input: a
sContinue? [y/n]:  invalid input: s
dContinue? [y/n]:  invalid input: d
fContinue? [y/n]:  invalid input: f

Anyone could please tell why it works so?

  • 4
    It's because read is writing the prompt to stderr but you are only redirecting stdout to tee I think; that results in the original stderr getting intermixed with the teed stdout. Try test_fn /tmp/warning 2>&1 | tee -a /tmp/logfile – steeldriver Mar 24 '18 at 13:29
  • @steeldriver, indeed, you are absolutely right, thank you. – DonJ Mar 24 '18 at 17:42

To convert a comment to an answer:

read -p writes the prompt to stderr; in order to get the results in-line for tee, pipe the function's stderr to stdout before the tee with:

test_fn /tmp/warning 2>&1 | tee -a /tmp/logfile

To demonstrate read's behavior:

$ read -p "my prompt: " >/dev/null
my prompt: hi
$ read -p "my prompt: " 2>/dev/null

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.