zsh tidak dapat menginput ke terminal saat memipakan stdin dan stdout dengan perintah variabel yang memiliki keluaran tty

11

Sistem Informasi:

macOS Sierra 10.12.6
zsh 5.4.2 (x86_64-apple-darwin16.7.0)
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)

Gulir ke CONTOH di bagian bawah jika Anda hanya ingin menggali contoh sederhana yang saya buat.

CATATAN: Saya bukan zshpengguna besar .


Saya mencari di fzfkeybindings untuk bashdan zsh.

Perhatikan bagaimana keduanya menjalankan perintah variabel $(__fzfcmd). __fzfcmdsecara default output fzfke stdout dan substitusi parameter hanya menjalankan perintah ( fzf) yang dihasilkan dari output.

Satu perbedaan antara skrip bashdan zshadalah skrip yang bashlebih lanjut mem-pipe output $(__fzfcmd)tetapi zshhanya menangkapnya di dalam array. Dugaan saya adalah karena masalah zshketika Anda lebih lanjut mem-pipkan output di fzfmana Anda tidak dapat input ke fzfdan proses piped by fzftidak mendapatkan stdin. Satu-satunya pilihan Anda adalah ^Zatau ^C. ^CSepertinya latar belakang proses karena beberapa alasan. Atau mungkin mereka hanya ingin dalam array sehingga mereka bisa bisa berjalan zle vi-fetch-historydi atasnya . The bashVersi melakukan sihir di kunci mengikat dengan"\e^": history-expand-line

Sekarang fzftidak penting. Sepertinya Anda hanya perlu program yang menampilkan ke ttyuntuk dipanggil oleh substitusi parameter untuk menyebabkan masalah ini. Jadi saya akan menunjukkan beberapa contoh sederhana.

Berikut adalah beberapa perintah lain yang menghasilkan ttyyang dapat menyebabkan masalah ini di zsh:

  • vipe (jalankan editor di tengah-tengah pipa)
  • 'vim -' (membuat vim dibaca dari stdin. mirip dengan vipe tetapi tidak akan menampilkan ke stdout)

Dalam contoh di bawah ini, ganti setiap kejadian vipedengan vim -jika Anda tidak ingin melakukan pemasangan terpisah. Ingat saja bahwa vim -tidak akan menampilkan konten editor ke stdout seperti vipehalnya.

CONTOH:

1) echo 1 | vipe | cat            # works in both bash and zsh
2) echo 1 | $(echo vipe) | cat    # works in bash only. zsh problem with no output until I hit `^C`:
   ^C
   zsh: done                    echo 1 | 
   zsh: suspended (tty output)  $(echo vipe) | 
   zsh: interrupt               cat
   # seems like the process is backgrounded. I can still see it in jobs command

3) cat <(echo 1 | $(echo vipe))   # zsh and bash has the problem. I'm guessing because
                                  # the file isn't finished writing and cat is
                                  # blocking vipe's tty output
                                  # both their `^C` output is just:
   ^C # nothing special, as expected

4) cat < <(echo 1 | $(echo vipe)) # works in both bash and zsh
5) echo 1 | $(echo vipe) > >(cat) # works in both bash and zsh

# The following don't have and input pipe to vipe.
# Type something then send EOF with ^D
6) vipe | cat                     # works for both
7) $(echo vipe) | cat             # works for both

Sekarang, saya sebagian besar bertanya-tanya mengapa 2)ada masalah untuk zshtetapi tidak untuk bashdan mengapa 4)dan 5)memperbaiki masalah untuk zsh.

Persyaratan untuk zshmemiliki masalah ini tampaknya persis seperti yang saya cantumkan pada judul:

  • pipa input
  • perintah dijalankan oleh substitusi variabel / parameter yang memiliki ttyoutput
  • pipa keluaran

MEMPERBARUI

Saya menambahkan solusi lain yang tidak menyebabkan zshmasalah ini 5),. Ini mirip dengan 4)tetapi alih-alih mengarahkan stdoutlangsung ke stin, saya mengarahkan kembali ke file yang mengarahkan kembali stdinmenggunakan proses substitusi.

dosentmatter
sumber
1
Seperti yang akan disampaikan oleh output dari psAnda, dalam semua kasus ini tidak ada cangkang yang beku atau macet. Mereka hanya menunggu proses anak dengan cara normal; dan mereka memang akan kembali ke meminta input dengan cara normal setelah proses anak ditangguhkan atau dihentikan. Judul dan badan pertanyaan Anda termasuk premis palsu implisit. "Mengapa cangkangku membeku?" adalah pertanyaan yang tidak dapat dijawab ketika shell Anda tidak benar - benar membeku. Anda akan memiliki pertanyaan yang lebih baik untuk menghapus premis palsu implisit ini.
JdeBP
Ok, saya bisa mengubahnya. Ini tidak benar-benar beku dalam arti bahwa proses tidak dapat menjalankan instruksi pada CPU lagi. Anda benar bahwa itu hanya menunggu. Tapi bukankah itu 'macet'? Sedang menunggu input, saya tidak bisa memberikannya. Apa istilah yang lebih baik untuk menggambarkan ini secara ringkas? Tidak cocok dengan deskripsi hang when either a computer program or system ceases to respond to inputs
dosentmatter
1
Shell tidak menunggu input. Itu sedang menunggu anak-anaknya. Pertanyaan ini akan lebih baik hanya menggambarkan apa yang terjadi . Jangan membuat hipotesis dan kesimpulan seperti "cangkang saya membeku" dan kemudian bertanya tentang kesimpulan. Jelaskan apa yang terjadi dan tanyakan tentang itu: Urutan input terminal karakter khusus (yang biasanya akan menangguhkan pekerjaan latar depan, atau mengganggu atau keluar dari pekerjaan, atau mengirim indikasi EOF ke proses pembacaan dari terminal) tidak berpengaruh. Apa yang terjadi? Mengapa? . Ini dapat direplikasi di Debian Linux dan FreeBSD / TrueOS, by the way,
JdeBP
1
Saya telah melaporkan bug di milis pengembangan zsh . Untuk saat ini, Anda harus bisa mengatasinya dengan membungkusnya dalam subkulit(echo | $(echo vipe) | cat)
Stéphane Chazelas
1
Fakta bahwa proses pergantian dimulai di latar belakang didokumentasikan saya pikir (atau setidaknya diketahui)
Stéphane Chazelas

Jawaban:

0

Saya percaya masalah Anda bermuara pada mengutip ekspansi Anda secara tidak benar.

Mengutip dari zsh: 14 Ekspansi

Perintah yang dilampirkan dalam tanda kurung didahului dengan tanda dolar, seperti $(...), atau dikutip dengan aksen serius, seperti ' ...', diganti dengan output standar, dengan setiap baris baru yang tertinggal dihapus. Jika substitusi tidak dimasukkan dalam tanda kutip ganda, output dibagi menjadi kata-kata menggunakan parameter IFS. Substitusi $(cat foo)dapat diganti dengan yang setara tetapi lebih cepat $(<foo). Dalam kedua kasus, jika opsi GLOB_SUBST diatur, output memenuhi syarat untuk pembuatan nama file.

Perhatikan bahwa Contoh # 2 dalam pertanyaan Anda menghasilkan gema NULL yang tak terbatas, karena:

Jika substitusi tidak dimasukkan dalam tanda kutip ganda, output dibagi menjadi kata-kata menggunakan parameter IFS.

Dengan kata lain shell tanpa batas menunggu echo, karena pembatas default adalah SPACE, gema tidak pernah selesai. Lihat TLDP: Variabel Internal . Ini meninggalkan pipa yang menggantung untuk catperintah.

Sebagai dugaan, saya percaya 4 dan 5 berfungsi karena pengalihan output.

eyoung100
sumber