Das Terminal war kaputt, nachdem Vim mit xargs aufgerufen worden war

30

Ich habe manchmal versucht, Vim folgendermaßen aufzurufen xargs:

find . -name '*.java' | xargs vim

… Welche Art von Arbeiten:

  1. Beim Start von Vim wird die folgende Warnung kurz angezeigt:

    Vim: Warning: Input is not from a terminal
    
  2. Das Bearbeiten funktioniert - :fileslistet alle .javaDateien wie erwartet korrekt auf .
  3. Ich kann sparen und kündigen.

Nach dem Verlassen von Vim ist mein Terminal jedoch nicht mehr erreichbar:

  • Was auch immer ich an der Shell-Eingabeaufforderung eingebe, wird nicht wiedergegeben.
  • Wagenrückläufe werden überhaupt nicht angezeigt, und Zeilenvorschübe werden nur manchmal angezeigt.

Dies geht so lange weiter, bis ich einen reset(1)Befehl zum Reinitialisieren des Terminals erteile.

Ist dies ein Vim-Fehler oder gibt es eine zufriedenstellendere Erklärung für die Interaktion mit dem Terminal? Ich habe es auf Vim bis Version 7.3 (die Version scheint keine Rolle zu spielen) unter Linux und verschiedenen Unices gesehen.

Ich kenne eine Problemumgehung, nämlich vim $(find . -name '*.java'). Andere Problemumgehungen wären willkommen, obwohl das nicht meine Hauptfrage ist.

200_erfolg
quelle
Ich habe den Wunsch, diese Site mit so vielen Fragen wie möglich zu füllen, aber ... diese Frage wurde im Laufe der Jahre auf SO / SU und anderswo Dutzende Male beantwortet: xargsVerwendet einen Dummy stdin, der von Vim nicht verwendet werden kann, und bricht ab alles danach.
Romainl
1
@romainl Ich bin auf diesen Websites nicht aktiv, und ich habe dort noch nie gefragt gesehen - ehrlich.
200_success
Related: superuser.com/questions/336016/… - vielleicht kann jemand die Top-Antworten zu einer großartigen Antwort zusammenfassen.
muru
2
Gute Frage - das ist mir schon oft passiert. Ich verwende auch keine anderen SO-Sites - wenn es mit Vim zusammenhängt, würde ich es gerne hier finden.
Craigp

Antworten:

21

Dies passiert, wenn vim aufgerufen wird und mit der Ausgabe der vorherigen Pipeline verbunden ist, anstatt mit dem Terminal, und wenn es andere unerwartete Eingaben empfängt (wie z. B. NULs). Das gleiche passiert , wenn Sie laufen: vim < /dev/null, so resetBefehl in diesem Fall hilft. Dies erklärt sich auch durch die Grawity beim Superuser .

Wenn Sie findzum Übergeben von Dateinamen zum Bearbeiten verwenden, müssen Sie nicht Folgendes xargsverwenden -exec:

find . -name '*.java' -exec vim {} +

Wenn Sie verwenden möchten xargs, sollten Sie unter Unix / macOS -oParameter verwenden, wie:

find . -name '*.java' | xargs -o vim

-oÖffnen Sie stdin als / dev / tty im untergeordneten Prozess erneut, bevor Sie den Befehl ausführen. Dies ist nützlich, wenn xargs eine interaktive Anwendung ausführen soll.

oder:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

Hinweis: Die Verwendung von -print0/ -0unterstützt Dateinamen mit Leerzeichen.


find+ BSDxargs

Unter Unix / macOS können Sie die folgende Problemumgehung ausprobieren:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

Sie können auch die Befehlssubstitutionssyntax verwenden , zum Beispiel:

vim $(find . -name '*.java')
vim `find . -name '*.java`

Verwenden Sie alternativ GNU parallelanstelle von xargs, um die Zuweisung von tty zu erzwingen. Beispiel:

find . -name '*.java' | parallel -X --tty vi

Hinweis: Unter parallelUnix / OSX funktioniert es nicht, da es andere Parameter hat und tty nicht unterstützt.

Viele andere beliebte Befehle bieten ebenfalls eine Pseudotty-Zuweisung (wie -tin ssh). Suchen Sie daher nach Hilfe.

Ein anderer Vorschlag wäre:

Verbunden:

Kenorb
quelle
Meine GNU xargshat nicht -J. Dies scheint eine MacOS (BSD) -Option zu sein, die in der GNU-Version nicht vorhanden ist.
Bis auf weiteres angehalten.
12

Umgehungsvorschlag: Verwenden Sie einen Puffer als Dateisystemnavigator

Verwenden Sie den vim -Befehl, um eine Liste der Pfade von stdin zu lesen. Vims :help --erklärt dies: 1

Beginnen Sie mit der Bearbeitung eines neuen Puffers, der mit Text gefüllt ist, der aus stdin gelesen wird. Die Befehle, die normalerweise von stdin gelesen werden, werden jetzt von stderr gelesen. Beispiel:

find . -name "*.c" -print | vim -

Sie können dann gfoder verwenden Ctrl-wCtrl-f, um zu der Datei im selben Puffer oder in einem neuen geteilten Fenster zu navigieren.

Umgehungsvorschlag: Argumentliste

Eine andere gute Möglichkeit ist die Verwendung der Argumentliste des Vim. Der :argadd **/*.javaBefehl füllt die Argumentliste von Vim rekursiv mit allen im aktuellen Verzeichnis gefundenen Java-Dateien. Sie können dann mit :nextund :prevzwischen den Dateien wechseln.


1 Der erste -teilt Vim mit, dass Sie in der Hilfe nach einer Befehlszeilenoption suchen möchten, der zweite ist das Befehlszeilenflag, nach dem Sie suchen. Lesen Sie :help help-contextweitere Tricks wie diese.

akshay
quelle
8

Außerdem resetkönnen Sie versuchen:

stty sane

Damit sollte Ihr Terminal auch wieder einsatzbereit sein.

Erläuterungen dazu finden Sie hier . Und irgendwie kann dies als vim Fehlverhalten angesehen werden, zumindest hat Neovim dieses Problem im Moment nicht.

ryenus
quelle
Dies beantwortet die Frage nicht genau, aber es hat mir geholfen, also +1.
Setzen Sie Monica iamnotmaynard
Dies beantwortet meine Frage;) Obwohl ich nach dem Lesen des OP mehr denke, resetsollte auch.
Sridhar Sarnobat
1

Der Grund dafür ist , dass xargsSätze stdinauf der /dev/nullErwägung, dass vimBedürfnisse stdinzu sein /dev/tty.


BSD xargs(zB Mac) Lösung:

echo -e 'file1\nfile2' | xargs -o vim

-odie Sätze stdinKind Prozess von xarg ( vimin diesem Fall) dev/tty.


GNU xargs(zB Linux) Lösung:

GNU xargshat keine -oOption. Stattdessen müssen Sie eine kompliziertere Problemumgehung verwenden. (Hinweis: Es ist sehr wichtig, die nachfolgende zeroZeichenfolge zu haben. Vergessen Sie sie nicht.)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

Sie können es auch zu einem Alias ​​machen:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

Detaillierte Erklärung der GNU xargs-Lösung

Lassen Sie es uns Schritt für Schritt aufschlüsseln:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargsHängt einfach das stdinan das Ende der Zeichenkette an und xargsführt dies aus:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2. Das Format für bash -cist bash -c 'COMMAND_STRING' $0 $1 $2 etc.

"$@"wird zu den Positionsparametern "$1", "$2"usw. erweitert. "$ 0" ist nicht enthalten, da dies ein spezieller Parameter für den Skriptnamen und kein Positionsparameter ist. Aus diesem Grund müssen wir die Dummy-Zeichenfolge hinzufügen zero(es kann sich um eine beliebige Zeichenfolge handeln), für die Platz genommen werden soll $0. Andernfalls verlieren Sie die erste Datei.

Nachdem Sie also expandiert haben "$@", erhalten Sie:

    bash -c '</dev/tty vim file1 file2' 

3. bash -cführt den COMMAND_STRING aus:

    </dev/tty vim file1 file2 

</dev/ttysetzt das stdinauf, /dev/ttydamit vimim interaktiven Modus gearbeitet werden kann.

weises Glück
quelle
+1 Dies scheint ein Duplikat der Antwort mit der höchsten Stimmenzahl zu sein, ist es aber nicht. Der $0Platzhalter (hier "Null") ist der Schlüssel.
Bis auf weiteres angehalten.
0

Ich habe festgestellt, dass all diese Antworten fehlen. Nach dem Durcharbeiten des xargs-Problems ist für mich der einfachste Weg, diese Such- und Öffnungsvorgänge für ein generisches Feld durchzuführen, der folgende:

vim -O `grep -lir mySearchTerm *`

Ich habe kein Problem findmit xargsund grep, aber ich finde die Syntax ärgerlich. Und als täglicher Programmierer, der vimund das Terminal als IDE verwendet und Dateien ständig nach Eigenschaften durchsucht, habe ich dies verwendet.

Es gibt eine Zeit und einen Ort für das find . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTermÖffnen von Dateien über vim und andere Methoden. Für mich ist das selten.

Hoffe das hilft jemandem.

Gavin
quelle
2
FWIW wird empfohlen, die ältere Backticks-Notation nicht zu verwenden und $(...)stattdessen zu verwenden . Es ist in Ihrer Befehlszeile nicht so wichtig wie in einem Skript, aber ich denke, es ist immer noch besser, dies in Ihren Antworten zu verwenden :) (Verweise hier und hier )
statox