zsh kann nicht in das Terminal eingegeben werden, wenn stdin und stdout mit einem variablen Befehl mit tty-Ausgabe weitergeleitet werden


11

Systeminformationen:

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)

Scrollen Sie zu den BEISPIELEN unten, wenn Sie nur die vereinfachten Beispiele betrachten möchten, die ich gemacht habe.

HINWEIS: Ich bin kein großer zshBenutzer.


Ich habe mir die fzfTastenkombinationen für bashund angesehen zsh.

Beachten Sie, wie beide einen variablen Befehl ausführen $(__fzfcmd). __fzfcmdStandardmäßig wird die Ausgabe fzfan stdout fzfausgegeben, und die Parametersubstitution führt nur den Befehl ( ) aus, der sich aus der Ausgabe ergibt.

Ein Unterschied zwischen dem bashund dem zshSkript besteht darin, dass bashderjenige die Ausgabe von weiterleitet, sie $(__fzfcmd)jedoch zshnur in einem Array erfasst. Meine Vermutung ist auf ein Problem zurückzuführen, zshbei dem Sie die Ausgabe, fzfan die Sie keine Eingabe vornehmen können, weiterleiten fzfund der Prozess, an den weitergeleitet fzfwird, keine Standardwerte erhält. Ihre einzige Wahl ist zu ^Zoder ^C. ^Cscheint den Prozess aus irgendeinem Grund zu unterstützen. Oder vielleicht wollten sie es einfach in einem Array, damit sie darauf laufen zle vi-fetch-historykönnen . Die bashVersion macht etwas Magie in der Schlüsselbindung mit"\e^": history-expand-line

Jetzt fzfist nicht wichtig. Es scheint, als bräuchten Sie nur ein Programm, das an das ausgegeben wird tty, um durch Parametersubstitution aufgerufen zu werden, um dieses Problem zu verursachen. Ich werde also einige einfachere Beispiele zeigen.

Hier sind einige andere Befehle, die an das ausgegeben werden, das ttydieses Problem verursachen kann zsh:

  • vipe (Editor in der Mitte einer Pipe ausführen)
  • 'vim -' (vim von stdin lesen lassen. ähnlich wie vipe, aber nicht an stdout ausgeben)

Ersetzen Sie in den folgenden Beispielen jedes Vorkommen von vipedurch, vim -wenn Sie keine separate Installation durchführen möchten. Denken Sie daran, dass vim -der Editorinhalt nicht wie gewohnt an stdout ausgegeben vipewird.

BEISPIELE:

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

Jetzt frage ich mich hauptsächlich, warum 2)es ein Problem gibt, zshaber nicht für bashund warum 4)und 5)behebt das Problem für zsh.

Die Voraussetzungen für zshdieses Problem scheinen genau das zu sein, was ich in den Titel eingefügt habe:

  • Eingangsleitung
  • Befehl, der durch Variablen- / Parametersubstitution ausgeführt wird, die ttyausgegeben wurde
  • Ausgangsrohr

AKTUALISIEREN

Ich habe eine weitere zshProblemumgehung hinzugefügt , die dieses Problem nicht verursacht 5). Es ist ähnlich, 4)aber anstatt stdoutdirekt umzuleiten stin, leite ich es in eine Datei um, die zur stdinVerwendung der Prozessersetzung umleitet .


1
Wie die Ausgabe von pszeigt, sind die Muscheln in keinem dieser Fälle eingefroren oder stecken fest. Sie warten einfach auf normale Weise auf untergeordnete Prozesse. und sie werden in der Tat auf normale Weise zur Eingabeaufforderung zurückkehren, sobald diese untergeordneten Prozesse angehalten oder beendet werden. Der Titel und der Text Ihrer Frage enthalten eine implizite falsche Prämisse. "Warum friert meine Muschel ein?" ist eine unbeantwortete geladene Frage, wenn Ihre Shell überhaupt nicht friert. Sie hätten eine bessere Frage, um diese implizite falsche Prämisse zu entfernen.
JdeBP

Ok, ich kann es ändern. Es ist nicht wirklich eingefroren in dem Sinne, dass der Prozess keine Anweisungen mehr auf der CPU ausführen kann. Sie haben Recht, dass es nur wartet. Aber steckt es nicht fest? Es wartet auf Eingaben, die ich nicht bereitstellen kann. Was ist ein besserer Begriff, um dies kurz zu beschreiben? Entspricht es nicht dieser Beschreibung von hang when either a computer program or system ceases to respond to inputs
dosentmatter

1
Die Shell wartet nicht auf Eingaben. Es wartet auf seine Kinder. Diese Frage sollte besser einfach beschrieben werden, was passiert . Bilden Sie keine Hypothesen und Schlussfolgerungen wie "Meine Schale ist eingefroren" und fragen Sie dann nach den Schlussfolgerungen. Beschreiben Sie, was passiert, und fragen Sie danach: Die Eingabesequenzen für Sonderzeichen-Terminals (die normalerweise den Vordergrundjob aussetzen oder den Job unterbrechen oder beenden oder eine EOF-Anzeige an den vom Terminal gelesenen Prozess senden) haben keine Auswirkung. Was ist los? Warum? . Dies ist übrigens unter Debian Linux und FreeBSD / TrueOS replizierbar
JdeBP

1
Ich habe den Fehler auf der zsh Development Mailingliste gemeldet . Im Moment sollten Sie in der Lage sein, es zu umgehen, indem Sie es in eine Unterschale einwickeln(echo | $(echo vipe) | cat)
Stéphane Chazelas

1
Die Tatsache, dass Prozesssubstitutionen im Hintergrund gestartet werden, ist
meines Erachtens

Antworten:


0

Ich glaube, Ihr Problem läuft darauf hinaus, Ihre Erweiterungen falsch zu zitieren.

Zitat aus zsh: 14 Erweiterung

Ein Befehl in Klammern, dem ein Dollarzeichen vorangestellt $(...)ist oder mit gravierenden Akzenten wie ' ...' zitiert wird , wird durch seine Standardausgabe ersetzt, wobei alle nachfolgenden Zeilenumbrüche gelöscht werden. Wenn die Ersetzung nicht in doppelte Anführungszeichen eingeschlossen ist, wird die Ausgabe mithilfe des IFS-Parameters in Wörter unterteilt. Die Substitution $(cat foo)kann durch das Äquivalent ersetzt werden, jedoch schneller $(<foo). In beiden Fällen kann die Ausgabe für die Dateinamengenerierung aktiviert werden, wenn die Option GLOB_SUBST aktiviert ist.

Beachten Sie, dass Beispiel 2 in Ihrer Frage zu einem unendlichen Echo von NULL führt, und zwar aufgrund von:

Wenn die Ersetzung nicht in doppelte Anführungszeichen eingeschlossen ist, wird die Ausgabe mithilfe des IFS-Parameters in Wörter unterteilt.

Mit anderen Worten, die Shell wartet unendlich auf das echo, da das Standardtrennzeichen SPACE ist und das Echo niemals abgeschlossen wird. Siehe TLDP: Interne Variablen . Dadurch bleibt eine Rohrleitung für den catBefehl hängen .

Als Vermutung glaube ich, dass 4 und 5 aufgrund der Ausgabeumleitung funktionieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.