1

Let's say I have a bash script which relies on user input (using read and the like).

I now want to run this script N times, each invocation taking an argument, and where those arguments are read from a text file. So essentially I want to do "for each line in text file call script with line as argument and let the user interact with it".

However, when I call my script through my "forall" loop, my read calls are just skipped, no user input is read.

Dumbed down example:

hello.sh:

name=$1
read -p "How old are you, $name? " age

echo "Hello $name, you are $age years old"

This works fine to call as

$ ./hello.sh Adam
How old are you, Adam? <user enters 42>
Hello Adam, you are 42 years old

Now I create my file of names:

names.txt:

Andrew
Benjamin
Charles
David
Edward

And my forall script:

forall.sh:

file=$1
command=$2

while read line; do
    if [ ! -z "$line" ]; then
        $command $line
    fi
done < $file

I now do forall.sh names.txt ./hello.sh, expecting to have my 5 users enter their ages, but instead I get this:

$ forall.sh names.txt ./hello.sh
Hello Andrew, you are Benjamin years old
Hello Charles, you are David years old
Hello Edward, you are  years old

Apparently, the read call will consume a line from the names.txt file instead of reading from a prompt.

How can I do "for each line in file call script with line" and still have the called script accept user input?

1
  • A much better design is to avoid read in the subprocess. Many scripts which require interactive I/O also offer the possibility to instead pass the required parameters as command-line options. Commented Nov 4, 2020 at 10:40

2 Answers 2

3

stdin is not the terminal in that loop, it's set to < $file. You need to pass the terminal explicitly to that command as stdin:

while read -r line; do
    if [ ! -z "$line" ]; then
        $command "$line" < /dev/tty
    fi
done < "$file"
Sign up to request clarification or add additional context in comments.

Comments

1

Alternately the while-read loop can use a different file descriptor (not stdin)

# ..............vvv
while read line <&3; do
    [ -n "$line" ] && "$command" "$line"
done 3< "$file"
# ...^^

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.