Masalah umum
Saya ingin menulis skrip yang berinteraksi dengan pengguna meskipun itu di tengah-tengah rantai pipa.
Contoh nyata
Konkretnya, diperlukan a file
atau stdin
, menampilkan garis (dengan nomor baris), meminta pengguna untuk memasukkan pilihan atau nomor baris, dan kemudian mencetak baris yang sesuai untuk stdout
. Sebut skrip ini selector
. Maka pada dasarnya, saya ingin bisa melakukannya
grep abc foo | selector > myfile.tmp
Jika foo
berisi
blabcbla
foo abc bar
quux
xyzzy abc
kemudian memberi selector
saya (di terminal, bukan di myfile.tmp
!) dengan opsi
1) blabcbla
2) foo abc bar
3) xyzzy abc
Select options:
setelah itu saya ketik
2-3
dan berakhir dengan
foo abc bar
xyzzy abc
sebagai isi myfile.tmp
.
Saya menjalankan skrip pemilih dan menjalankannya, dan pada dasarnya skrip ini berfungsi dengan baik jika saya tidak mengarahkan input dan output. Begitu
selector foo
berperilaku seperti yang saya inginkan. Namun, ketika menyatukan hal-hal seperti pada contoh di atas, selector
mencetak opsi yang disajikan ke myfile.tmp
dan mencoba membaca pilihan dari input yang diterima.
Pendekatan saya
Saya sudah mencoba menggunakan -u
bendera read
, seperti pada
exec 4< /proc/$PPID/fd/0
exec 4> /proc/$PPID/fd/1
nl $INPUT >4
read -u4 -p"Select options: "
tapi ini tidak melakukan apa yang saya harapkan.
T: Bagaimana cara saya mendapatkan interaksi pengguna yang sebenarnya?
cmd | { some processing; read var </dev/tty; } | cmd
alias selector='{ TMPFILE=$(mktemp); cat > $TMPFILE; nl -s") " $TMPFILE | column -c $(tput cols); read -e -p"Select options: " < /dev/tty; rangeselect -v range="$REPLY" $TMPFILE; rm $TMPFILE; }'
yang berfungsi cukup baik. Namungrep b foo | selector | wc -l
istirahat di sini. Ada ide bagaimana cara memperbaikinya? Omong-omong,rangeselect
yang saya gunakan dapat ditemukan di pastebin.com/VAxTSSHs . Ini adalah skrip AWK sederhana yang mencetak garis-garis file yang sesuai dengan sejumlah linenumber tertentu. (Rentang bisa berupa "3-10, 12,14,16-20".)alias
itu, lebihselector() { all of that stuff...; }
ke fungsi.alias
es mengubah nama perintah sederhana sedangkan fungsi mengemas perintah gabungan menjadi satu perintah sederhana .Jawaban:
Penggunaan
/proc/$PPID/fd/0
tidak dapat diandalkan: induk dariselector
proses mungkin tidak memiliki terminal sebagai inputnya.Ada jalur standar yang selalu mengacu pada terminal proses saat ini:
/dev/tty
.atau
sumber
Saya telah menulis fungsi kecil: itu tidak akan menjawab tentang apa yang Anda minta chaining pipa tetapi akan menyelesaikan masalah Anda.
Fungsi membalik semua argumen yang Anda berikan segera
grep
. Jika Anda menggunakan shell glob untuk menentukan file yang harus dibaca dari itu akan mengembalikan semua pertandingan di semua file, mulai dengan yang pertama dalam urutan glob dan berakhir dengan pertandingan terakhir.grep
meneruskan outputnya kenl
nomor mana setiap baris dan yang melewati outputnyatee
yang menggandakan outputnya kestdout
dan ke/dev/tty
. Ini berarti bahwa output dari pipa secara bersamaan dicetak baik ke array argumen fungsi di mana ia dibagi pada\n
baris baru dan ke terminal saat ia bekerja.Selanjutnya
_in()
fungsi mencoba untukread
memilih jika setidaknya ada 1 hasil dari tindakan sebelumnya maksimum lima kali. Pilihan dapat terdiri dari hanya angka yang dipisahkan oleh spasi, atau rentang angka yang dipisahkan oleh-
. Jika ada yang lainread
(termasuk baris kosong) itu akan mencoba lagi - tetapi hanya, seperti sebelumnya, maksimum lima kali.Terakhir
_out()
fungsi mem-parsing pilihan pengguna dan memperluas rentang apa pun di dalamnya. Ini mencetak hasilnya dalam bentuk"${[num]}"
untuk masing-masing - dengan demikian cocok dengan nilai dari garis yang disimpan dalaminf()
array arg. Output ini adalaheval
ed sebagai argumenprintf
yang karenanya hanya mencetak garis yang telah dipilih pengguna.Ini secara eksplisit
read
dari terminal dan hanya mencetakSelect:
menu kestderr
dan jadi itu banyak pipa ramah. Misalnya, yang berikut ini berfungsi:Tetapi Anda dapat menggunakan opsi apa pun yang akan Anda berikan
grep
dan sejumlah nama file yang mungkin Anda berikan juga. Artinya, Anda dapat menggunakan salah satu dari satu jenis - sebagai efek samping dari input parsing$IFS
dengannya tidak akan berfungsi jika Anda mencari baris kosong. Tetapi siapa yang ingin memilih dari daftar nomor baris kosong?Catatan terakhir bahwa karena ini bekerja dengan secara langsung menerjemahkan input pengguna numerik ke dalam parameter posisi numerik yang disimpan dalam array argumen fungsi, maka output akan menjadi apa pun yang dipilih pengguna, sebanyak yang dipilih pengguna, dan dalam urutan apa pun pengguna memilih Itu.
Sebagai contoh:
sumber