Reputation: 9285
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?
Upvotes: 1
Views: 4005
Reputation: 246744
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"
# ...^^
Upvotes: 1
Reputation: 157947
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"
Upvotes: 3