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

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.