Randnotiz: Sie können diesen Vorgang vollständig in vim ausführen, ohne findoder xargsüberhaupt zu verwenden. Öffnen Sie vim ohne Argumente und führen Sie :args **/*.txt<CR>den Befehl aus, um die Argumente von vim im Editor festzulegen.
Trevor Powell
3
@ Trevor Powell: In all den Jahren hat vim nie aufgehört, mich zu überraschen.
Wenn Sie ein Programm über aufrufen xargs, zeigt die Standardeingabe des Programms auf /dev/null. (Da xargs den ursprünglichen Standard nicht kennt , tut es das nächstbeste.)
$ true | xargs filan -s
0 chrdev / dev / null
1 tty / dev / pts / 1
2 tty / dev / pts / 1
$ true | xargs ls -l / dev / fd /
Vim geht davon aus, dass die stdin mit dem steuernden Terminal identisch ist, und führt verschiedene terminalbezogene Ioctls direkt auf stdin aus. Wenn dies mit /dev/null(oder einem anderen Dateideskriptor als tty) erledigt ist, sind diese Ioctls bedeutungslos und geben ENOTTY zurück, was unbemerkt ignoriert wird.
Ich vermute eine spezifischere Ursache: Beim Start liest und merkt sich Vim die alten Terminaleinstellungen und stellt sie beim Beenden wieder her. In unserer Situation empfängt Vim, wenn die "alten Einstellungen" für einen Nicht-tty-fd (Dateideskriptor) angefordert werden, alle leeren Werte und alle deaktivierten Optionen und legt diese achtlos auf Ihrem Terminal fest.
Sie können dies sehen, indem Sie ausführen vim < /dev/null, es beenden und dann ausführen stty, wodurch eine ganze Reihe von <undef>s ausgegeben werden . Unter Linux läuft stty sanedas Terminal nutzbar machen wieder (obwohl es wird solche Optionen verloren hat , wie iutf8, möglicherweise kleinere Ärgernisse später verursacht).
Sie können dies als Fehler in Vim betrachten, da es für die Terminalsteuerung geöffnet werden kann/dev/tty , dies jedoch nicht. (Irgendwann während des Startvorgangs dupliziert Vim seinen stderr in stdin, wodurch er Ihre Eingabebefehle lesen kann - von einem zum Schreiben geöffneten fd - aber selbst das wird nicht früh genug getan.)
+1 und für TL; DR-Leute einfach ausführenstty sane
doc_id
@rahmanisback: Die anderen Antworten und der Kommentar von Trevor boten alle Möglichkeiten, um Klemmenbrüche zu vermeiden. Ich habe die Antwort von grawity akzeptiert, weil meine Frage "Warum" war, nicht "Wie vermeide ich das?" - das wird von einer anderen Frage abgedeckt, aus der diese Frage tatsächlich hervorging .
DevSolar
@DevSolar Verstanden, aber denken Sie an frustrierte Leute wie mich, die nur googeln, um dieses Verhalten zu beseitigen. Leider haben sie jetzt genug Zeit, um das "Warum" zu studieren, was dennoch sehr interessant ist.
doc_id
4
Wenn mein Terminal so kaputt geht, benutze ich resetstattdessen stty saneund es funktioniert danach einwandfrei.
Capi Etheriel
137
(In Anlehnung an die Erklärung von grawity xargsverweist das stdinauf /dev/null.)
Die Lösung für dieses Problem besteht darin, den -oParameter hinzuzufügen xargs. Von man xargs:
-o
Öffnen Sie stdin erneut wie /dev/ttyim untergeordneten Prozess, bevor Sie den Befehl ausführen. Dies ist nützlich, wenn Sie xargseine interaktive Anwendung ausführen möchten .
Daher sollte die folgende Codezeile für Sie funktionieren:
finden . -name "* .txt" | xargs -o vim
GNU xargs unterstützt diese Erweiterung seit einiger Veröffentlichung im Jahr 2017 (mit dem langen Optionsnamen --open-tty).
Bei älteren oder anderen Versionen von xargs können Sie /dev/ttydas Problem explizit lösen, indem Sie Folgendes eingeben :
Wie würden Sie daraus einen Bash-Alias erstellen? $@Scheint, Argumente nicht richtig zu übersetzen.
Zanegray
1
@zanegray - Sie können keinen Alias erstellen, aber Sie können eine Funktion erstellen. Versuchen Sie:function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
Christopher
Eine detaillierte Erklärung, wie die GNU xargs-Lösung funktioniert und warum Sie den Dummy- ignoremeString benötigen , finden Sie unter vi.stackexchange.com/a/17813
wisbucky
@ zanegray, Du kannst es zu einem Alias machen. Die Zitate sind schwierig. Die Lösung finden Sie unter vi.stackexchange.com/a/17813
wisbucky
The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.(Es war für mich unter macOS nicht verfügbar, da ich xargs von Homebrew (der GNU-Version) installiert habe.)
Die Hauptfrage lautete "warum" und nicht "wie man es vermeidet" und wurde vor zweieinhalb Jahren zur Zufriedenheit beantwortet.
DevSolar
5
Dies funktioniert natürlich nicht richtig, wenn Dateinamen Leerzeichen oder andere Sonderzeichen enthalten, und ist auch ein Sicherheitsrisiko.
Dejay Clayton
1
Meine Lieblingsantwort, weil es für jeden Befehl funktioniert, der Dateien auflistet, nicht nur "Suchen" oder Platzhalter. Es erfordert ein wenig Vertrauen, wie Dejay betont.
Travis Wilson
1
Dies funktioniert nicht in vielen Anwendungsfällen, für die xargs entwickelt wurde: z. B. wenn die Anzahl der Pfade sehr hoch ist (cc @ TravisWilson)
Gute Person
21
Es sollte gut funktionieren, wenn Sie die Option -exec für find verwenden, anstatt in xargs zu leiten.
Huh ... der Trick dabei ist der +(anstelle von "dem Üblichen" \;), alle gefundenen Dateien in eine Vim-Sitzung zu bringen - eine Option, die ich immer wieder vergesse. Sie haben natürlich Recht und +1 dafür. Ich benutze vim $(find ...)einfach aus Gewohnheit. Tatsächlich fragte ich mich jedoch, warum die Pipe-Operation das Terminal versaut hat, und Grawity traf dies mit seiner Erklärung.
DevSolar
2
Dies ist die beste Antwort und funktioniert unter BSD / OSX / GNU / Linux.
Kevinarpe
1
Außerdem ist find nicht die einzige Möglichkeit, eine Liste der Dateien abzurufen, die von vim gleichzeitig bearbeitet werden müssen. Ich kann grep verwenden, um alle Dateien mit einem Muster zu finden und sie gleichzeitig zu bearbeiten.
Chandranshu
8
Verwenden Sie stattdessen GNU Parallel:
find . -name "*.txt" | parallel -j1 --tty vim
Oder wenn Sie alle Dateien auf einmal öffnen möchten:
Nicht überall verfügbar. Die meiste Zeit arbeite ich auf Servern, auf denen ich keine zusätzlichen Tools installieren kann. Aber trotzdem danke für den Hinweis.
DevSolar
Wenn es Ihnen freigestellt ist, 'cat> file zu machen; chmod + x file 'dann können Sie GNU Parallel installieren: Es ist einfach ein Perl-Skript. Wenn Sie Manpages und ähnliches wollen, können Sie diese unter Ihrem Homedir installieren: ./configure --prefix = $ HOME && make && make install
Ole Tange
2
OK, versucht das - aber parallel öffnet nicht alle Dateien, sondern öffnet sie nacheinander . Es ist auch ein ziemlicher Bissen für eine einfache Operation. vim $(find . -name "*.txt")ist einfacher, und Sie erhalten alle Dateien auf einmal geöffnet.
DevSolar
5
@ DevSolar: Etwas unabhängig, aber beide find | xargsund $(find)werden große Probleme mit Leerzeichen in Dateinamen haben.
Grawity
2
@grawity Richtig, aber es gibt keinen einfachen Weg (den ich kenne), um es zu umgehen. Sie würden mit zu beginnen haben das Hantieren $IFS, -print0und solche Sachen, und dann nach links Sie in das Reich der One-Shot - Befehlszeile - Lösung und einen Punkt erreicht , wo man mit einem Skript kommen sollte ... es gibt einen Grund , warum Leerzeichen in Dateinamen abgeraten .
DevSolar
0
Vielleicht nicht das beste, aber hier das Skript, das ich benenne vim-open:
find
oderxargs
überhaupt zu verwenden. Öffnen Sie vim ohne Argumente und führen Sie:args **/*.txt<CR>
den Befehl aus, um die Argumente von vim im Editor festzulegen.grep -l .. | xargs vim
generiert eine Warnung, warum? bei unix SEAntworten:
Wenn Sie ein Programm über aufrufen
xargs
, zeigt die Standardeingabe des Programms auf/dev/null
. (Da xargs den ursprünglichen Standard nicht kennt , tut es das nächstbeste.)Vim geht davon aus, dass die stdin mit dem steuernden Terminal identisch ist, und führt verschiedene terminalbezogene Ioctls direkt auf stdin aus. Wenn dies mit
/dev/null
(oder einem anderen Dateideskriptor als tty) erledigt ist, sind diese Ioctls bedeutungslos und geben ENOTTY zurück, was unbemerkt ignoriert wird.Ich vermute eine spezifischere Ursache: Beim Start liest und merkt sich Vim die alten Terminaleinstellungen und stellt sie beim Beenden wieder her. In unserer Situation empfängt Vim, wenn die "alten Einstellungen" für einen Nicht-tty-fd (Dateideskriptor) angefordert werden, alle leeren Werte und alle deaktivierten Optionen und legt diese achtlos auf Ihrem Terminal fest.
Sie können dies sehen, indem Sie ausführen
vim < /dev/null
, es beenden und dann ausführenstty
, wodurch eine ganze Reihe von<undef>
s ausgegeben werden . Unter Linux läuftstty sane
das Terminal nutzbar machen wieder (obwohl es wird solche Optionen verloren hat , wieiutf8
, möglicherweise kleinere Ärgernisse später verursacht).Sie können dies als Fehler in Vim betrachten, da es für die Terminalsteuerung geöffnet werden kann
/dev/tty
, dies jedoch nicht. (Irgendwann während des Startvorgangs dupliziert Vim seinen stderr in stdin, wodurch er Ihre Eingabebefehle lesen kann - von einem zum Schreiben geöffneten fd - aber selbst das wird nicht früh genug getan.)quelle
stty sane
reset
stattdessenstty sane
und es funktioniert danach einwandfrei.(In Anlehnung an die Erklärung von grawity
xargs
verweist dasstdin
auf/dev/null
.)Die Lösung für dieses Problem besteht darin, den
-o
Parameter hinzuzufügenxargs
. Vonman xargs
:Daher sollte die folgende Codezeile für Sie funktionieren:
GNU xargs unterstützt diese Erweiterung seit einiger Veröffentlichung im Jahr 2017 (mit dem langen Optionsnamen
--open-tty
).Bei älteren oder anderen Versionen von xargs können Sie
/dev/tty
das Problem explizit lösen, indem Sie Folgendes eingeben :(Das
ignoreme
ist da, um $ 0 aufzunehmen, so dass $ @ alle Argumente von xargs sind.)quelle
$@
Scheint, Argumente nicht richtig zu übersetzen.function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
ignoreme
String benötigen , finden Sie unter vi.stackexchange.com/a/17813The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.
(Es war für mich unter macOS nicht verfügbar, da ich xargs von Homebrew (der GNU-Version) installiert habe.)Der einfachste Weg:
quelle
Es sollte gut funktionieren, wenn Sie die Option -exec für find verwenden, anstatt in xargs zu leiten.
quelle
+
(anstelle von "dem Üblichen"\;
), alle gefundenen Dateien in eine Vim-Sitzung zu bringen - eine Option, die ich immer wieder vergesse. Sie haben natürlich Recht und +1 dafür. Ich benutzevim $(find ...)
einfach aus Gewohnheit. Tatsächlich fragte ich mich jedoch, warum die Pipe-Operation das Terminal versaut hat, und Grawity traf dies mit seiner Erklärung.Verwenden Sie stattdessen GNU Parallel:
Oder wenn Sie alle Dateien auf einmal öffnen möchten:
Es behandelt sogar Dateinamen wie:
Sehen Sie sich das Intro-Video an, um mehr zu erfahren: http://www.youtube.com/watch?v=OpaiGYxkSuQ
quelle
vim $(find . -name "*.txt")
ist einfacher, und Sie erhalten alle Dateien auf einmal geöffnet.find | xargs
und$(find)
werden große Probleme mit Leerzeichen in Dateinamen haben.$IFS
,-print0
und solche Sachen, und dann nach links Sie in das Reich der One-Shot - Befehlszeile - Lösung und einen Punkt erreicht , wo man mit einem Skript kommen sollte ... es gibt einen Grund , warum Leerzeichen in Dateinamen abgeraten .Vielleicht nicht das beste, aber hier das Skript, das ich benenne
vim-open
:wird mit
vim-open a b c
undls | vim-open
zum Beispiel arbeitenquelle