zsh non può immettere nel terminale quando si esegue il piping di stdin e stdout con un comando variabile che ha un output di tty


11

Informazioni di sistema:

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)

Scorri fino agli ESEMPI in basso se vuoi solo approfondire gli esempi semplificati che ho fatto.

NOTA: non sono un grande zshutente.


Stavo guardando le fzfcombinazioni di tasti per bashe zsh.

Notare come entrambi eseguono un comando variabile $(__fzfcmd). __fzfcmdper impostazione predefinita output fzfsu stdout e la sostituzione dei parametri esegue semplicemente command ( fzf) risultante dall'output.

Una differenza tra lo script bashe zshè che bashquello convoglia ulteriormente l'output di $(__fzfcmd)ma zshlo cattura semplicemente all'interno di un array. La mia ipotesi è dovuta a un problema in zshcui si esegue ulteriormente il piping dell'output in fzfcui non è possibile immettere fzfe il processo a cui viene eseguito il piping fzfnon ottiene alcuno stdin. La tua unica scelta è di ^Zo ^C. ^Csembra fare da sfondo al processo per qualche motivo. O forse volevano solo in una matrice in modo che potessero potessero funzionare zle vi-fetch-historysu di esso . La bashversione fa un po 'di magia nel key binding con"\e^": history-expand-line

Adesso fzfnon è importante. Sembra che tu abbia solo bisogno di un programma che emetta l'output ttyper essere chiamato dalla sostituzione dei parametri per causare questo problema. Quindi mostrerò alcuni esempi più semplici.

Ecco alcuni altri comandi che ttygenerano in output che possono causare questo problema in zsh:

  • vipe (esegui l'editor nel mezzo di una pipe)
  • 'vim -' (fai in modo che vim legga da stdin. simile a vipe ma non verrà riprodotto in stdout)

Negli esempi seguenti, sostituire ogni occorrenza di vipecon vim -se non si desidera eseguire un'installazione separata. Ricorda solo che vim -il contenuto dell'editor non verrà riprodotto su stdout come vipefa.

ESEMPI:

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

Ora, mi chiedo principalmente perché 2)abbia un problema per zshma non per bashe perché 4)e 5)risolva il problema per zsh.

I requisiti per zshavere questo problema sembrano essere esattamente ciò che ho inserito nel titolo:

  • tubo di ingresso
  • comando eseguito dalla sostituzione variabile / parametro che ha ttygenerato
  • tubo di uscita

AGGIORNARE

Ho aggiunto un'altra soluzione che non causare zshad avere questo problema, 5). È simile 4)ma invece di reindirizzare stdoutdirettamente in stin, lo reindirizzo in un file che reindirizza stdinall'utilizzo della sostituzione del processo.


1
Come l'output di psti dirà, in nessuno di questi casi i gusci sono congelati o bloccati. Stanno semplicemente aspettando i processi figlio in modo normale; e torneranno sicuramente a richiedere input nel modo normale una volta che quei processi figlio sono sospesi o chiusi. Il titolo e il corpo della domanda includono una premessa implicita falsa. "Perché la mia shell si blocca?" è una domanda caricata senza risposta quando la shell non si blocca in primo luogo. Avresti una domanda migliore per rimuovere questa premessa implicita falsa.
JdeBP

Ok, posso cambiarlo. Non è veramente congelato nel senso che il processo non è più in grado di eseguire istruzioni sulla CPU. Hai ragione che sta solo aspettando. Ma non è "bloccato"? È in attesa di input che non sono in grado di fornire. Qual è un termine migliore per descriverlo in modo conciso? Non corrisponde a questa descrizione di hang when either a computer program or system ceases to respond to inputs
dosentmatter il

1
La shell non è in attesa di input. Sta aspettando i suoi figli. È meglio porre questa domanda semplicemente descrivendo cosa succede . Non formulare ipotesi e inferenze come "il mio guscio è congelato" e quindi chiedere delle inferenze. Descrivere cosa succede e chiedere: Le sequenze di input del terminale di caratteri speciali (che normalmente sospenderebbero il lavoro in primo piano, o interromperebbero o abbandonerebbero il lavoro, o invierebbero un'indicazione EOF alla lettura del processo dal terminale) non hanno alcun effetto. Che cosa sta succedendo? Perché? . Questo è replicabile su Debian Linux e FreeBSD / TrueOS, a proposito,
JdeBP

1
Ho segnalato il bug nella mailing list di sviluppo di zsh . Per ora, dovresti essere in grado di aggirarlo avvolgendolo in una subshell(echo | $(echo vipe) | cat)
Stéphane Chazelas,

1
Il fatto che le sostituzioni di processo siano avviate in background è documentato, credo (o almeno noto)
Stéphane Chazelas,

Risposte:


0

Credo che il tuo problema si riduce a citare erroneamente le tue espansioni.

Citando da zsh: 14 Expansion

Un comando racchiuso tra parentesi preceduto da un simbolo di dollaro, come $(...), o citato con accenti gravi, come ' ...', viene sostituito con il suo output standard, con ogni nuova riga finale cancellata. Se la sostituzione non è racchiusa tra virgolette, l'output viene suddiviso in parole utilizzando il parametro IFS. La sostituzione $(cat foo)può essere sostituita dall'equivalente ma più veloce $(<foo). In entrambi i casi, se l'opzione GLOB_SUBST è impostata, l'output è idoneo per la generazione del nome file.

Nota che l'esempio n. 2 nella tua domanda genera un'eco infinita di NULL, a causa di:

Se la sostituzione non è racchiusa tra virgolette, l'output viene suddiviso in parole utilizzando il parametro IFS.

In altre parole, la shell attende infinitamente il echo, poiché il delimitatore predefinito è SPACE, l'eco non si completa mai. Vedi TLDP: variabili interne . Questo lascia un tubo sospeso per il catcomando.

Credo che 4 e 5 funzionino a causa del reindirizzamento dell'output.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.