Viele von Ihnen haben wahrscheinlich den Befehl gesehen, mit dem Sie in eine Datei schreiben können, für die Root-Berechtigungen erforderlich sind, auch wenn Sie vergessen haben, vim mit sudo zu öffnen:
:w !sudo tee %
Die Sache ist, dass ich nicht verstehe, was genau hier passiert.
Ich habe mir das schon gedacht:
w
ist dafür
*:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
Execute {cmd} with [range] lines as standard input
(note the space in front of the '!'). {cmd} is
executed like with ":!{cmd}", any '!' is replaced with
the previous command |:!|.
Daher werden alle Zeilen als Standardeingabe übergeben.
Der !sudo tee
Teil ruft tee
mit Administratorrechten auf.
Damit alle Sinn machen, %
sollte der Dateiname (als Parameter für tee
) ausgegeben werden , aber ich kann keine Referenzen in der Hilfe für dieses Verhalten finden.
tl; dr Könnte mir jemand helfen sezieren diesen Befehl?
:w !sudo cat > %
nicht so gut funktionieren und die Standardausgabe nicht verschmutzen?sudo
wird auf angewendetcat
, aber nicht auf>
, daher ist dies nicht zulässig. Sie könnten versuchen, den gesamten Befehl in einer sudo-Subshell auszuführen,:w !sudo sh -c "cat % > yams.txt"
aber das funktioniert auch nicht, da in der Subshell%
null ist. Sie werden den Inhalt Ihrer Datei ausblenden.:w !sudo sh -c "cat >%"
tatsächlich genauso gut,sudo tee %
weil Vim den Dateinamen ersetzt,%
bevor er jemals in die Subshell gelangt. Keiner von ihnen funktioniert jedoch, wenn der Dateiname Leerzeichen enthält. Sie müssen das tun:w !sudo sh -c "cat >'%'"
oder:w !sudo tee "%"
beheben.Antworten:
In
:w !sudo tee %
...%
bedeutet "die aktuelle Datei"Wie eugene y hervorhob ,
%
bedeutet dies in der Tat "den aktuellen Dateinamen", der übergeben wird,tee
damit er weiß, welche Datei überschrieben werden muss.(Bei Substitutionsbefehlen ist dies etwas anders. Wie
:help :%
gezeigt, ist dies derequal to 1,$ (the entire file)
Fall (danke an @Orafu für den Hinweis, dass dies nicht als Dateiname ausgewertet wird).:%s/foo/bar
" in der aktuellen Datei Vorkommen vonfoo
durch ersetzenbar
". Wenn Sie markieren Wenn:s
Sie vor dem Eingeben Text eingeben , werden Sie feststellen, dass die hervorgehobenen Zeilen den Platz von einnehmen%
Ihres Substitutionsbereichs .):w
aktualisiert Ihre Datei nichtEin verwirrender Teil dieses Tricks ist, dass Sie vielleicht denken
:w
Ihre Datei ändern, aber das ist es nicht. Wenn Sie geöffnet und geändertfile1.txt
und dann ausgeführt haben:w file2.txt
, ist dies ein "Speichern unter".file1.txt
würde nicht geändert, aber der aktuelle Pufferinhalt würde an gesendetfile2.txt
.Anstatt
file2.txt
können Sie einen Shell-Befehl ersetzen, um den Pufferinhalt zu erhalten . Zum Beispiel,:w !cat
wird nur der Inhalt angezeigt.Wenn Vim nicht mit sudo-Zugriff ausgeführt wurde,
:w
kann eine geschützte Datei nicht geändert werden. Wenn der Pufferinhalt jedoch an die Shell übergeben wird, wird ein Befehl in der Shell ausgeführt kann mit sudo ausgeführt werden . In diesem Fall verwenden wirtee
.Tee verstehen
Was
tee
, Bild , um dietee
Befehls als ein T-förmiges Rohr in einer normalen Situation bash Verrohrung: es Ausgang angegebener Datei (en) leitet , und sendet es auch an der Standardausgabe , die durch den nächsten Befehl verrohrt erfaßt werden kann.In wird beispielsweise
ps -ax | tee processes.txt | grep 'foo'
die Liste der Prozesse in eine Textdatei geschrieben und an weitergeleitetgrep
.(Mit Asciiflow erstelltes Diagramm .)
Weitere Informationen finden Sie auf der
tee
Manpage .Tee als Hack
In der Situation, die Ihre Frage beschreibt, ist die Verwendung
tee
ein Hack, da wir die Hälfte dessen ignorieren, was sie bewirkt .sudo tee
schreibt in unsere Datei und sendet auch den Pufferinhalt an die Standardausgabe, aber wir ignorieren die Standardausgabe . In diesem Fall müssen wir nichts an einen anderen Pipeline-Befehl übergeben. Wir verwenden nurtee
eine alternative Methode zum Schreiben einer Datei, damit wir sie aufrufen könnensudo
.Diesen Trick einfach machen
Sie können dies zu Ihrem hinzufügen
.vimrc
, um diesen Trick benutzerfreundlich zu machen: Geben Sie einfach ein:w!!
.Der
> /dev/null
Teil wirft die Standardausgabe explizit weg, da wir, wie gesagt, nichts an einen anderen Pipeline-Befehl übergeben müssen.quelle
tee
seine Fähigkeit, stdin in eine Datei zu schreiben. Ich bin überrascht, dass es kein Programm gibt, dessen Aufgabe es ist, das zu tun (ich habe ein Programm gefunden, von dem ich noch nie gehört habe,sponge
das dies tut). Ich denke, das typische "Schreiben eines Streams in eine Datei" wird von einer eingebauten Shell ausgeführt. Gabelt Vim!{cmd}
keine Muschel (cmd
stattdessen Gabeln )? Vielleicht ist etwas Offensichtlicheres, eine funktionierende Variante vonsh -c ">"
anstatt zu verwendentee
.sponge
ist Teil desmoreutils
Pakets für so ziemlich jede Distribution außer Debian-basierten Distributionen.moreutils
hat einige ziemlich nette Werkzeuge, die mit allgemeineren Werkzeugen wiexargs
und vergleichbar sindtee
.cat
als root ausgeführt und die Ausgabe wird von der Shell umgeleitet, die nicht als root ausgeführt wird. Es ist das gleiche wieecho hi > /read/only/file
.%
Steht in der ausgeführten Befehlszeile für den aktuellen Dateinamen . Dies ist dokumentiert in:help cmdline-special
:Wie Sie bereits herausgefunden haben,
:w !cmd
leitet der Inhalt des aktuellen Puffers an einen anderen Befehl weiter. Wastee
tut , ist die Standardeingabe in einer oder mehr Dateien zu kopieren, und auch auf der Standardausgabe.:w !sudo tee % > /dev/null
Schreibt daher effektiv den Inhalt des aktuellen Puffers in die aktuelle Datei, während Sie root sind . Ein weiterer Befehl, der dafür verwendet werden kann, istdd
:Als Verknüpfung können Sie diese Zuordnung zu Ihrem hinzufügen
.vimrc
:Mit dem oben genannten können Sie eingeben
:w!!<Enter>
, um die Datei als root zu speichern.quelle
:help _%
, was Sie eingegeben haben, zeigt aber:help %
den Klammer-Matching-Schlüssel an. Ich hätte nicht gedacht, das Unterstrichpräfix zu versuchen. Ist das ein Muster in der vim-Dokumentation? Gibt es noch andere "besondere" Dinge, die Sie bei der Suche nach Hilfe ausprobieren sollten?help
Befehl springt zu einem Tag. Sie können verfügbare Tags mit anzeigen:h help-tags
. Sie können auch die Befehlszeilenvervollständigung verwenden, um übereinstimmende Tags:h cmdline<Ctrl-D>
:h cmdline<Tab>
wildmode
cmap w!! w !sudo tee % > /dev/null
in meiner .vimrc-Datei verwenden, damit dies funktioniert. Ist das%
in der obigen Antwort falsch platziert? (Kein vim Experte hier.)sudo tee > /dev/null /path/to/current/file
dass dies nicht wirklich Sinn macht. (Das funktioniert auch gut:
Dies ist inspiriert von dem Kommentar von @Nathan Long.
HINWEIS :
"
muss verwendet werden, anstatt'
weil wir erweitert werden möchten%
, bevor wir zur Shell übergehen.quelle
tee
werden/usr/bin/tee
, um Angriffe mit PATH-Modifikation zu verhindern.:w
- Schreiben Sie eine Datei.!sudo
- Rufen Sie den Befehl shell sudo auf.tee
- Die Ausgabe des Befehls write (vim: w) wird mit tee umgeleitet. Das% ist nichts anderes als der aktuelle Dateiname, dh /etc/apache2/conf.d/mediawiki.conf. Mit anderen Worten, der Befehl tee wird als root ausgeführt und nimmt die Standardeingabe entgegen und schreibt sie in eine durch% dargestellte Datei. Dies führt jedoch dazu, dass die Datei erneut geladen wird (drücken Sie L, um Änderungen in vim selbst zu laden):Tutorial Link
quelle
Die akzeptierte Antwort deckt alles ab, daher gebe ich nur ein weiteres Beispiel für eine Verknüpfung , die ich für die Aufzeichnung verwende.
Fügen Sie es Ihrem
etc/vim/vimrc
(oder~/.vimrc
) hinzu:cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!
Wo:
cnoremap
: erzählt vim dass die folgende Verknüpfung in der Befehlszeile zugeordnet werden soll.w!!
: die Verknüpfung selbst.execute '...'
: Ein Befehl, der die folgende Zeichenfolge ausführt.silent!
: Lass es leise laufenwrite !sudo tee % >/dev/null
: Die OP-Frage hat eine Umleitung von Nachrichten zu hinzugefügtNULL
, um einen sauberen Befehl auszuführen<bar> edit!
: Dieser Trick ist die Kirsche des Kuchens: Er ruft auch denedit
Befehl auf, den Puffer neu zu laden und dann zu vermeiden, dass sich Nachrichten wie der Puffer geändert haben .<bar>
Hier erfahren Sie, wie Sie das Pipe- Symbol schreiben , um zwei Befehle zu trennen.Ich hoffe es hilft. Siehe auch für andere Probleme:
quelle
Ich möchte einen anderen Ansatz für die "Oups, die ich
sudo
beim Öffnen meiner Datei vergessen habe zu schreiben" vorschlagen. :Anstatt ein zu empfangen
permission denied
und eingeben zu müssen:w!!
, finde ich es eleganter, einen bedingtenvim
Befehl zu haben, der ausführt,sudo vim
wenn der Dateieigentümer dies istroot
.Dies ist genauso einfach zu implementieren (es könnte sogar elegantere Implementierungen geben, ich bin eindeutig kein Bash-Guru):
Und es funktioniert wirklich gut.
Dies ist ein
bash
zentrierterer Ansatz als ein Ansatz,vim
sodass es möglicherweise nicht jedem gefällt.Na sicher:
root
erfordertsudo
, die Funktion jedoch trotzdem bearbeitet werden kann).vim
eine Datei nur zum Lesen zu verwenden (soweit es mich betrifft, verwende ich sietail
odercat
für kleine Dateien).Aber ich finde, dass dies eine viel bessere Benutzererfahrung für Entwickler mit sich bringt , was meiner Meinung nach bei der Verwendung häufig vergessen wird
bash
. :-)quelle
root
das Passwort abgefragt.FÜR NEOVIM
Aufgrund von Problemen mit interaktiven Anrufen ( https://github.com/neovim/neovim/issues/1716 ) verwende ich dies für neovim, basierend auf der Antwort von Dr. Beco:
Dies öffnet einen Dialog,
ssh-askpass
in dem Sie nach dem sudo-Passwort gefragt werden.quelle