Come leggere l'input dell'utente da una pipe?


9

Supponiamo di avere un file chiamato confirmation.shcon il seguente contenuto:

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

e voglio eseguire questo script nel modo seguente:

cat confirmation.sh | sh

Vedo Are you sure [Y/n]?e lo script è interrotto. Qual è il problema?


2
Hai /bin/bashnella linea del botto, ma usi .shun'estensione e provi a reindirizzare lo script sh. Non è un problema poiché il codice che hai è compatibile con entrambi, ma vale la pena sottolineare.
Graeme,

Risposte:


8

Come altri hanno già detto, ciò è dovuto al fatto che stdinof shè stato reindirizzato per leggere dalla pipe, non è collegato al terminale come sarebbe normalmente. Una cosa che puoi fare per aggirare questo è usare /dev/ttyper forzare la lettura dello script dal terminale. Per esempio:

#!/bin/sh

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

Normalmente lo faresti solo se vuoi specificamente impedire alle persone di scrivere script sull'input, ad esempio:

echo Y | sh confirmation.sh

Ciò continuerebbe a leggere dal terminale anche se l'utente potrebbe aspettarsi che questo venga inserito automaticamente Yal prompt. È comune per i programmi che prevedono una password per farlo.


2
sh 3<<CONFIRM /dev/fd/3
    $(cat ./confirmation.sh)
CONFIRM

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

nota: grazie a @Graeme per avermi corretto sui due esempi precedenti ...

È molto più facile da fare se rimani stdinchiaro.

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

Oppure, poiché 0 1 2 di un terminale sono tutti lo stesso file, basta aggiungere:

read line <&2

E il tuo

cat ./confirmation.sh | sh

Funziona bene.


Non riesco a far funzionare nessuno di questi a parte l'ultimo.
Graeme,

Strano, hanno funzionato tutti per me ... Sono nel mezzo di qualcosa, ma tra ... circa 10 minuti posso testare di nuovo. Nel frattempo ... BOLD IL TUO COMMENTO forse? Non mi piace diffondere disinformazione.
Mikeserv,

@Graeme - non so perché l'ho perso la prima volta - avrei giurato di averli testati tutti allo stesso tempo - ma i primi due hanno bisogno di una modifica per funzionare correttamente. Grazie.
Mikeserv,

Sembra buono, comunque non legge dal terminale quando provengo da stderrperò. Probabilmente dovrei però, non capisco perché.
Graeme,

@Graeme - strano - l'ho provato con dash sh zsh e bash. Tutto ha funzionato.
Mikeserv,

0

Questo ha funzionato per un singolo argomento inviato alla mia sceneggiatura:

if [ -p /dev/stdin ]; then set -- "$( cat )"; fi

Posso quindi accedere ai dati inoltrati in un argomento posizionale ( $1), che è compatibile con i miei altri script script.


Da info test:

[ -p /dev/stdin ]: -p FILEè True se esiste FILE ed è una pipe denominata.


-1

La risposta breve è che non puoi. La pipe reindirizza stdout su stdin, quindi non è possibile eseguire uno script interattivo, poiché hai già reindirizzato l'output dal primo comando come input al secondo comando nell'istruzione pipe.

Potresti voler fare qualcosa del genere:

cat confirmation.sh > ask.sh && sh ask.sh

Puoi ancora eseguire uno script interattivo, vedi la mia risposta. Inoltre, perché non solo sh confirmation.sh?
Graeme,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.