Bagaimana cara membaca input pengguna dari sebuah pipa?

9

Mari kita asumsikan saya memiliki file bernama confirmation.shdengan konten berikut:

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

dan saya ingin menjalankan skrip ini dengan cara berikut:

cat confirmation.sh | sh

Saya melihat Are you sure [Y/n]?dan skripnya terputus. Apa masalahnya?

Igor Timoshenko
sumber
2
Anda ada /bin/bashdi garis bang, namun Anda menggunakan .shekstensi dan mencoba untuk menyalurkan script sh. Bukan masalah karena kode yang Anda miliki kompatibel dengan keduanya, tetapi patut ditunjukkan.
Graeme

Jawaban:

8

Seperti orang lain berkata, ini karena stdindari shtelah diarahkan untuk membaca dari pipa, itu tidak terhubung ke terminal karena biasanya akan. Satu hal yang dapat Anda lakukan untuk menyiasatinya adalah menggunakan /dev/ttyuntuk memaksa skrip membaca dari terminal. Misalnya:

#!/bin/sh

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

Biasanya Anda hanya akan melakukan ini jika Anda secara khusus ingin mencegah orang lain untuk menuliskan input, misalnya:

echo Y | sh confirmation.sh

Ini masih akan membaca dari terminal meskipun pengguna mungkin berharap ini secara otomatis dimasukkan Ypada prompt. Adalah umum untuk program yang mengharapkan kata sandi untuk melakukan ini.

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

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

catatan: terima kasih kepada @Graeme untuk mengoreksi saya pada dua contoh di atas ...

Ini jauh lebih mudah dilakukan jika Anda tetap stdinjelas.

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

Atau, karena 0 0 2 terminal semua file yang sama, tambahkan saja:

read line <&2

Dan milikmu

cat ./confirmation.sh | sh

Bekerja dengan baik.

mikeserv
sumber
Saya tidak bisa mendapatkan ini bekerja terpisah dari yang terakhir.
Graeme
Aneh, mereka semua bekerja untuk saya ... Saya berada di tengah-tengah sesuatu, tetapi dalam ... 10 atau lebih menit saya dapat menguji lagi. Sementara itu ... BOLD KOMENTAR ANDA mungkin? Saya tidak suka menyebarkan informasi yang salah.
mikeserv
@ Greme - tidak yakin mengapa saya melewatkannya pertama kali - bisa bersumpah saya menguji mereka semua pada saat yang sama - tetapi dua yang pertama memang perlu perubahan untuk beroperasi dengan benar. Terima kasih.
mikeserv
Terlihat bagus, Masih tidak membaca dari terminal ketika saya sumber dari stderrolah Saya mungkin harus, saya tidak mengerti mengapa.
Graeme
@Graeme - aneh - Saya mencobanya dengan dash sh zsh dan bash. Semua berhasil.
mikeserv
0

Ini berhasil untuk satu argumen yang disalurkan ke skrip saya:

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

Saya kemudian dapat mengakses data yang disalurkan dalam argumen posisi ( $1), yang kompatibel dengan cara kerja skrip saya yang lain.


Dari info test:

[ -p /dev/stdin ]: -p FILEbenar jika FILE ada dan merupakan pipa bernama.

LinuxSecurityFreak
sumber
-1

Jawaban singkatnya adalah Anda tidak bisa. Pipa mengarahkan ulang stdout ke stdin, jadi karena itu Anda tidak dapat menjalankan skrip interaktif, karena Anda telah mengarahkan ulang output dari perintah pertama sebagai input ke perintah kedua dalam pernyataan pipa.

Anda mungkin ingin melakukan sesuatu seperti ini:

cat confirmation.sh > ask.sh && sh ask.sh
David
sumber
Anda masih dapat menjalankan skrip interaktif, lihat jawaban saya. Juga, mengapa tidak adil sh confirmation.sh?
Graeme