Jak odczytać dane wejściowe użytkownika z potoku?


9

Załóżmy, że mam plik o confirmation.shnastępującej treści:

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

i chcę uruchomić ten skrypt w następujący sposób:

cat confirmation.sh | sh

Rozumiem, Are you sure [Y/n]?a skrypt został przerwany. Jaki jest problem?


2
Masz /bin/bashlinię podziału, ale używasz .shrozszerzenia i próbujesz przesłać skrypt do niego sh. Nie stanowi to problemu, ponieważ kod, który posiadasz, jest zgodny z oboma, ale warto zwrócić uwagę.
Graeme

Odpowiedzi:


8

Jak mówili inni, to dlatego, że stdinod shzostało przekierowane do zapoznania się z rury, to nie jest podłączony do terminala jak to zwykle. Aby obejść ten problem, należy /dev/ttyzmusić skrypt do odczytu z terminala. Na przykład:

#!/bin/sh

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

Zwykle robiłbyś to tylko wtedy, gdy chcesz uniemożliwić innym osobom pisanie skryptów, np .:

echo Y | sh confirmation.sh

Nadal będzie czytać z terminala, nawet jeśli użytkownik może oczekiwać, że zostanie to automatycznie wprowadzone Ypo znaku zachęty. Jest to powszechne w programach, które oczekują hasła.


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

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

Uwaga: dzięki @Graeme za poprawienie mnie w powyższych dwóch przykładach ...

O wiele łatwiej to zrobić, jeśli będziesz trzymać się z stdindaleka.

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

Lub, ponieważ wszystkie 0 1 2 terminala są tym samym plikiem, po prostu dodaj:

read line <&2

I twój

cat ./confirmation.sh | sh

Działa dobrze.


Nie mogę zmusić żadnego z nich do działania poza ostatnim.
Graeme

Dziwne, wszyscy dla mnie pracowali ... Jestem w trakcie czegoś, ale za ... 10 minut mogę znów przetestować. W międzyczasie ... ODWRÓĆ SWÓJ KOMENTARZ ? Nie lubię rozpowszechniać dezinformacji.
mikeserv

@Graeme - nie jestem pewien, dlaczego przegapiłem to za pierwszym razem - mógłbym przysiąc, że przetestowałem je wszystkie w tym samym czasie - ale pierwsze dwa wymagają zmiany, aby działać poprawnie. Dziękuję Ci.
mikeserv

Wygląda dobrze, ale mimo to nie czytam z terminala stderr. Prawdopodobnie powinienem, ale nie rozumiem dlaczego.
Graeme

@Graeme - dziwne - próbowałem z dash sh zsh i bash. Wszystko działało.
mikeserv

0

Działa to w przypadku pojedynczego argumentu przesyłanego do mojego skryptu:

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

Następnie mogę uzyskać dostęp do danych potokowych za pomocą argumentu pozycyjnego ( $1), który jest zgodny z moimi innymi działaniami skryptowymi.


Od info test:

[ -p /dev/stdin ]: -p FILEma wartość Prawda, jeśli istnieje PLIK i jest nazwanym potokiem.


-1

Krótka odpowiedź brzmi: nie możesz. Potok przekierowuje stdout na stdin, dlatego nie można uruchomić skryptu interaktywnego, ponieważ przekierowano już dane wyjściowe z pierwszego polecenia jako dane wejściowe do drugiego polecenia w instrukcji potoku.

Być może chcesz zrobić coś takiego:

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

Nadal możesz uruchomić interaktywny skrypt, zobacz moją odpowiedź. A dlaczego nie tylko sh confirmation.sh?
Graeme
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.