tags:

views:

403

answers:

2

I have a bash script that I mostly use in interactive mode. However, sometimes I pipe in some input to the script. After processing stdin in a loop, I copy a file using "-i" (interactive). However, this never gets executed (in pipe mode) since (I guess) standard input has not been flushed. To simplify with an example:

#!/bin/bash
while read line
do
    echo $line
done
# the next line does not execute 
cp -i afile bfile

Place this in t.sh, and execute with: ls | ./t.sh

The read is not executed. I need to flush stdin before the read. How could it do this?

+5  A: 

This has nothing to do with flushing. Your stdin is the output of ls, you've read all of it with your while loop, so read gets EOF immediately. If you want to read something from the terminal, you can try this:

#!/bin/bash
while read line
do
    echo $line
done
# the next line does execute 
read -p "y/n" x < /dev/tty
echo "got $x"
unbeli
+1, but I would use $(tty) instead of /dev/tty.
mouviciel
@mouviciel nope, $(tty) is not going to work. Try it ;)
unbeli
@mouviciel: Why?
Dennis Williamson
I tried both < /dev/tty and < $(tty). Doesn't work, and the second gives an error. ./rtest2.sh: line 122: $(tty): ambiguous redirectActually, if you see the question, my problem is with a "cp -i" command. The code sample I gave was just demonstrative, since the code itself is large.One could perhaps replace the read command with a cp -i to get the problem
rahul
@rahul works equally well with cp -i for me. If it does not work for you, please post your system details (uname -a) and more on how exactly it does not work
unbeli
I tried it again. Voila. "< dev/tty" has worked !Thanks a lot.
rahul
A: 

I'm not sure it's possible to do what you want here (i.e. having the read take its input from the user and not from ls). The problem is that all standard input for your script is taken from the pipe, period. This is the same file descriptor, so it will not 'switch' to the terminal just because you want it to.

One option would be to run the ls as a child of the script, like this:

#!/bin/bash

ls | while read line
do
    echo $line
done

read -p "y/n" x
echo "got $x"
Gyom
Sadly, I often use this program directly from the command line without piping input. In that case it works interactively, like a shell prompting me for commands.<p>Some times I pipe in the contents of a file to it through some filters, or i directly grep and sed some content to it through a pipe.
rahul