124

I am having a bash script which is something like following,

cat filename | while read line
do
    read input;
    echo $input;
done

but this is clearly not giving me the right output as when I do read in the while loop it tries to read from the file filename because of the possible I/O redirection.

Any other way of doing the same?

1
  • Same thing happens when you switch user in bash and run read command under switched user in script Commented Sep 20, 2013 at 12:16

5 Answers 5

128

Read from the controlling terminal device:

read input </dev/tty

more info: http://compgroups.net/comp.unix.shell/Fixing-stdin-inside-a-redirected-loop

Sign up to request clarification or add additional context in comments.

2 Comments

-1, as this will circumvent any other redirect. For example, bash yourscript < /foo/bar will wait for user input, this is acceptable only when reading passwords. The answer by @GordonDavisson is preferable for all other uses.
The link now points to a completely irrelevant website.
72

You can redirect the regular stdin through unit 3 to keep the get it inside the pipeline:

{ cat notify-finished | while read line; do
    read -u 3 input
    echo "$input"
done; } 3<&0

BTW, if you really are using cat this way, replace it with a redirect and things become even easier:

while read line; do
    read -u 3 input
    echo "$input"
done 3<&0 <notify-finished

Or, you can swap stdin and unit 3 in that version -- read the file with unit 3, and just leave stdin alone:

while read line <&3; do
    # read & use stdin normally inside the loop
    read input
    echo "$input"
done 3<notify-finished

5 Comments

why is your second script hanging?
@LucaBorrione: How are you using it? Is it waiting for you to give it input (note that read line is reading from notify-finished, but if you just run it as written read -u 3 input is reading from the console)?
I get read: 3: invalid file descriptor: Bad file descriptor when tryiing to do read -u 3
@maxprehl I assume you're using the first version? Did you include the 3<&0 part in the redirect after done (but before the redirect from the input file)? That's what sets up file descriptor 3.
example 3 is perfect. removing cat input_file | while also has the benefit, that inside the while loop, you can modify variables of the parent scope. see also A variable modified inside a while loop is not remembered. the cat input_file could be moved to a process substitution like done 3< <(cat input_file)
5

Try to change the loop like this:

for line in $(cat filename); do
    read input
    echo $input;
done

Unit test:

for line in $(cat /etc/passwd); do
    read input
    echo $input;
    echo "[$line]"
done

4 Comments

@w2lame Tested again, change "while" loop to "for" loop - working for me. Try "sex -x" see where is error comes from
don't use cat, see answer from Hai Vu
+1. This was much easier to implement for my specific needs than other suggestions.
See Don't Read Lines With For on the Wooledge wiki. Also, shellcheck.net warning SC2013
3

I have found this parameter -u with read.

"-u 1" means "read from stdout"

while read -r newline; do
    ((i++))
    read -u 1 -p "Doing $i""th file, called $newline. Write your answer and press Enter!"
    echo "Processing $newline with $REPLY" # united input from two different read commands.
done <<< $(ls)

4 Comments

This is not stdin. FD 1 which is not flushed and you can read from it. You also can use read -u 2.
Well, if it is not an stdin, why can I not to use FD 12??? (I am not an expert. I only wonder.)
I was also wondering. but it seems because the FD 12 does not exist. FD 0 is the stdin. FD 1 stdout FD 2 error. it also works with the error descriptor as I wrote above. read -u 2
Yes. The file with FD=12 is not open yet. I corrected the text. Thanks for the hit. :-)
-7
echo "Enter the Programs you want to run:"
> ${PROGRAM_LIST}
while read PROGRAM_ENTRY
do
   if [ ! -s ${PROGRAM_ENTRY} ]
   then
      echo ${PROGRAM_ENTRY} >> ${PROGRAM_LIST}
   else
      break
   fi
done

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.