8

Say I've got a bash script:

#!/bin/bash

read -p "Gimme some stuff: " stuff
echo "**${stuff}**"

If the script is invoked with something piping into it, such as:

echo "Here's some stuff" | ./myscript.bash

Then the read command will read from the pipe. Even if I try to clear stdin out before I hit that read command, it will still return immediately.

Is there any way around that? If I don't have any control of the way in which my script is invoked, is there any way to force it to accept input for a read or select from the terminal? If not, are there any sneakier ways to pause the script to get input from a user other than from stdin?

glibdud
  • 203
  • 2
  • 6
  • This is such a wonderfully worded question! It was still very difficult to find because any search matching `/bash .* (read|accept|pipe) .* (stdin|tty)/` favors simple questions about how to pipe into a bash script. I'm so glad you managed to break through the algorithm. – Bruno Bronosky Jun 25 '23 at 03:59

1 Answers1

11

Yes. The terminal is always /dev/tty. All that is necessary is to have read get its input from the terminal rather than stdin:

#!/bin/bash

read -p "Gimme some stuff: " stuff </dev/tty
echo "**${stuff}**"

In operation, this looks like:

$ echo asdfdsaf | read.sh
Gimme some stuff: 123
**123**

A slightly more complex way of doing the same thing

Here we open /dev/tty as file descriptor 3. The option -u 3 tells read to use file descriptor 3:

exec 3<>/dev/tty
read -u 3 -p "Gimme some stuff: " stuff
echo "**${stuff}**"
John1024
  • 16,593
  • 5
  • 50
  • 45