Como ler a entrada do usuário no pipe?

8

Vamos supor que eu tenha um arquivo chamado confirmation.sh com o seguinte conteúdo:

#!/bin/bash

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

e quero executar esse script da seguinte maneira:

cat confirmation.sh | sh

Eu vejo Are you sure [Y/n]? e o script está interrompido. Qual é o problema?

Obrigado!

    
por Igor Timoshenko 24.03.2014 / 22:34

3 respostas

6

Como outros já disseram, isso ocorre porque o stdin de sh foi redirecionado para leitura do pipe, ele não está conectado ao terminal como normalmente seria. Uma coisa que você pode fazer para contornar isso é usar /dev/tty para forçar o script a ler do terminal. Por exemplo:

#!/bin/sh

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

Normalmente, você só faria isso se quisesse especificamente evitar que as pessoas criassem scripts na entrada, por exemplo:

echo Y | sh confirmation.sh

Isso ainda seria lido no terminal, embora o usuário possa esperar que ele insira automaticamente Y no prompt. É comum que programas que esperam uma senha façam isso.

    
por 25.03.2014 / 00:08
2
sh 3<<CONFIRM /dev/fd/3
    $(cat ./confirmation.sh)
CONFIRM

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

nota: agradece a @Graeme por me corrigir nos dois exemplos acima ...

É muito mais fácil fazer isso se você manter stdin claro.

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

Ou, como o terminal 0 1 2 é todo o mesmo arquivo, adicione:

read line <&2

E o seu

cat ./confirmation.sh | sh

Funciona bem.

    
por 26.03.2014 / 05:44
0

A resposta curta é que você não pode. O pipe redireciona stdout para stdin, portanto, você não pode executar um script interativo, já que você já redirecionou a saída do primeiro comando como a entrada para o segundo comando na instrução pipe.

Você pode estar procurando fazer algo assim:

cat confirmation.sh > ask.sh && sh ask.sh
    
por 24.03.2014 / 22:52