Bir borudan kullanıcı girişi nasıl okunur?


9

confirmation.shAşağıdaki içeriğe sahip bir dosyam olduğunu varsayalım :

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

ve bu betiği şu şekilde çalıştırmak istiyorum:

cat confirmation.sh | sh

Anlıyorum Are you sure [Y/n]?ve senaryo kesintiye uğradı. Sorun ne?


2
You have /bin/bashpatlama hattında, henüz bir kullanmak .shuzantısı ve boruya senaryoyu deneyin sh. Sahip olduğunuz kod her ikisiyle de uyumlu olduğu için sorun değil, ancak belirtmeye değer.
Graeme

Yanıtlar:


8

Diğerleri bahsedilen gibi, bunun nedeni stdinarasında shnormal olacak şekilde borudan okuma yönlendirildi, bu terminale bağlı değildir. Bunu aşmak için yapabileceğiniz bir şey /dev/tty, komut dosyasını terminalden okumaya zorlamaktır. Örneğin:

#!/bin/sh

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

Normalde bunu yalnızca kişilerin girdiyi komut dosyası yazmalarını özellikle önlemek istiyorsanız yaparsınız, örneğin:

echo Y | sh confirmation.sh

Kullanıcı Yistemde otomatik olarak girilmesini beklese bile bu durum terminalden okunacaktır . Parolanın bunu yapmasını bekleyen programlar için yaygındır.


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

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

not: Yukarıdaki iki örnekte beni düzelttiği için @Graeme sayesinde ...

Eğer stdinnet tutarsanız yapmak çok daha kolay .

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

Veya bir terminalin 0 1 2'si aynı dosya olduğundan, şunu ekleyin:

read line <&2

Ve senin

cat ./confirmation.sh | sh

Sadece iyi çalışıyor.


Bunlardan hiçbirinin sonuncusundan ayrı çalışmasını sağlayamıyorum.
Graeme

Tuhaf, hepsi benim için çalıştı ... Bir şeyin ortasındayım, ama ... 10 dakika kadar sonra tekrar test edebilirim. Bu arada ... YORUMUNUZU KALIN olabilir mi? Yanlış bilgileri yaymaktan hoşlanmıyorum.
2014'te

@Graeme - neden ilk kez kaçırdığımdan emin değilim - hepsini aynı anda test ettim - ama ilk ikisinin doğru çalışması için bir değişikliğe ihtiyacı var. Teşekkür ederim.
mikeserv

İyi görünüyor, yine de kaynak geldiğimde hala terminalden okumuyor stderr. Muhtemelen düşünmeliyim, nedenini anlamıyorum.
Graeme

@Graeme - garip - Ben çizgi sh zsh ve bash ile denedim. Hepsi işe yaradı.
mikeserv

0

Bu benim senaryo piped tek bir argüman için çalıştı:

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

Sonra $1diğer komut dosyası çalışmaları ile uyumlu bir konumsal argüman ( ), borulu verilere erişebilirsiniz .


Gönderen info test:

[ -p /dev/stdin ]: -p FILEDOSYA varsa ve adlandırılmış bir kanalsa, Doğru'dur.


-1

Kısa cevap, yapamayacağınızdır. Boru, stdout'u stdin'e yönlendirir, bu nedenle etkileşimli bir komut dosyasını çalıştıramazsınız, çünkü ilk olarak, komut deyimindeki ikinci komutun girdisi olarak ilk komuttan çıktıyı yönlendirmişsinizdir.

Bunun gibi bir şey yapmak istiyor olabilirsiniz:

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

Yine de etkileşimli bir komut dosyası çalıştırabilirsiniz, cevabımı görün. Ayrıca, neden sadece sh confirmation.sh?
Graeme
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.