Search code examples
bashiostdin

read builtin doesn't work with pipe


I'd like to ask user a confirmation to read from stdin (Display output [Y/n]). It works Ok if some arguments were provided, or no arguments were provided but there was some input. However, if some data was piped to the script, there's no confirmation.

#!/bin/bash

output_file=$(mktemp)

cleanup() {
    rm -f "$output_file"
}

trap cleanup 0 1 2 3 15

if [ $# -gt 0 ]; then
    while [ $# -gt 0 ]; do
        echo "$1" >> "$output_file"
        shift
    done
else
    while read -r line; do
        echo "$line" >> "$output_file"
    done
fi

while true; do
    read -p "Display output? [Y/n]" response
    if [ -z "$response" ]; then
        break
    fi

    case $response in
        [Yy]*) break;;
        [Nn]*) exit;;
    esac
done

less "$output_file"

What prevent read -p to work? What should be done to provide consistent behavior?


Solution

  • The read command reads input from standard in. If you have standard in fed from a pipe then read looks for its data from the pipe, not from your terminal.

    On most platforms you can work around this by redirecting the read command's input directly from the tty device, as in:

    read -p "Display output? [Y/n]" response </dev/tty