4
votes

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?

2

2 Answers

6
votes

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"
0
votes

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"