Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Let's assume I have a file named confirmation.sh with the following content:

#!/bin/bash

echo -n "Are you sure [Y/n]? "
read line
case "$line" in
    n|N) echo "smth"
        ;;
    y|Y) echo "smth"
        ;;
esac

and I want to run this script in the following way:

cat confirmation.sh | sh

I see Are you sure [Y/n]? and script is interrupted. What's the problem?

Thanks!

share|improve this question
1  
You have /bin/bash in the bang line, yet you use a .sh extension and try to pipe the script to sh. Not a problem since the code you have is compatible with both, but worth pointing out. –  Graeme Mar 24 '14 at 22:30

3 Answers 3

up vote 4 down vote accepted

As others have said, this is because the stdin of sh has been redirected to read from the pipe, it is not connected to the terminal as it would normally be. One thing you can do to get around this is to use /dev/tty to force the script to read from the terminal. Eg:

#!/bin/sh

read -p "Are you sure [Y/n]?" line </dev/tty
case "$line" in
  y|Y) echo "confirmed"
    ;;
  *) echo "not confirmed"
    ;;
esac

Normally you would only do this if you specifically want to prevent people from scripting the input, eg:

echo Y | sh confirmation.sh

This would still read from the terminal even though the user might expect this to automatically input Y at the prompt. It is common for programs that expect a password to do this.

share|improve this answer
sh 3<<CONFIRM /dev/fd/3
    $(cat ./confirmation.sh)
CONFIRM

sh 3<./confirmation.sh /dev/fd/3

note: thanks to @Graeme for correcting me on the above two examples...

Its a lot easier to do if you keep stdin clear.

2<./confirmation.sh . /dev/stderr

Or, since a terminal's 0 1 2 are all the same file, just add:

read line <&2

And your

cat ./confirmation.sh | sh

Works just fine.

share|improve this answer
    
I can't get any of these to work apart from the last one. –  Graeme Mar 26 '14 at 11:48
    
Weird, they all worked for me... I'm in the middle of something, but in... 10 or so minutes i can test again. In the meantime... BOLD YOUR COMMENT maybe? I dont like disseminating misinformation. –  mikeserv Mar 26 '14 at 11:50
    
@Graeme - not sure why I missed it the first time - could have sworn I tested them all at the same time - but the first two do need a change to operate correctly. Thank you. –  mikeserv Mar 26 '14 at 12:41
    
Looks good, It still doesn't read from the terminal when I source from stderr though. I probably should though, I don't understand why. –  Graeme Mar 26 '14 at 13:40
    
@Graeme - weird - I tried it with dash sh zsh and bash. All worked. –  mikeserv Mar 26 '14 at 14:02

The short answer is you can't. The pipe redirects stdout to stdin, so therefore you cannot run an interactive script, as you have already redirected the output from the first command as the input to the second command in the pipe statement.

You might be looking to do something like this:

cat confirmation.sh > ask.sh && sh ask.sh
share|improve this answer
    
You can still run an interactive script, see my answer. Also, why not just sh confirmation.sh? –  Graeme Mar 24 '14 at 23:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.