Frage Wie funktioniert der vim "write with sudo" Trick?


Viele von Ihnen haben wahrscheinlich den Befehl gesehen, mit dem Sie auf eine Datei schreiben können, die root-Berechtigung benötigt, selbst wenn Sie vergessen haben, vim mit sudo zu öffnen:

:w !sudo tee %

Die Sache ist, dass ich nicht verstehe, was genau hier passiert.

Das habe ich mir 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 |:!|.

Es übergibt alle Zeilen als Standardeingabe.

Das !sudo tee Teil Anrufe tee mit Administratorrechten.

Damit alle einen Sinn haben, ist die % sollte den Dateinamen ausgeben (als Parameter für tee), aber ich kann keine Hinweise auf die Hilfe für dieses Verhalten finden.

tl; dr Könnte jemand mir helfen, diesen Befehl zu sezieren?


1148
2018-04-08 14:36


Ursprung


Antworten:


% bedeutet "die aktuelle Datei"

Wie eugene y wies darauf hin, % bedeutet in der Tat "der aktuelle Dateiname". Eine andere Verwendung dafür in Vim sind Substitutionsbefehle. Beispielsweise, :%s/foo/bar meint "in der aktuellen Datei, ersetzen Sie Vorkommen von foo mit bar. "Wenn Sie vor der Eingabe einen Text markieren :sSie werden sehen, dass die hervorgehobenen Linien den Platz einnehmen % als dein Ersatzbereich.

:w aktualisiert Ihre Datei nicht

Ein verwirrender Teil dieses Tricks ist, dass Sie vielleicht denken :w ändert Ihre Datei, ist es aber nicht. Wenn Sie geöffnet und geändert haben file1.txt, dann lief :w file2.txtes wäre ein "Speichern als"; file1.txt würde nicht geändert, aber der aktuelle Pufferinhalt würde an gesendet werden file2.txt.

Anstatt von file2.txt, Sie können Ersetzen Sie einen Shell-Befehl, um den Pufferinhalt zu empfangen. Zum Beispiel, :w !cat zeigt nur den Inhalt an.

Wenn Vim nicht mit sudo-Zugriff ausgeführt wurde, ist es :w kann eine geschützte Datei nicht ändern, aber wenn sie den Pufferinhalt an die Shell weitergibt, ein Befehl in der Shell kann mit sudo ausgeführt werden. In diesem Fall verwenden wir tee.

T-Shirt verstehen

Wie für tee, Bild der tee Befehl als ein T-förmiges Rohr in einer normalen Bash-Rohrleitungssituation: es leitet die Ausgabe zu spezifizierten Dateien und sendet es auch an die Standardausgabe, die vom nächsten Piped-Befehl erfasst werden können.

Zum Beispiel, in ps -ax | tee processes.txt | grep 'foo'Die Liste der Prozesse wird in eine Textdatei geschrieben und ging zu grep.

     +-----------+    tee     +------------+
     |           |  --------  |            |
     | ps -ax    |  --------  | grep 'foo' |
     |           |     ||     |            |
     +-----------+     ||     +------------+
                       ||   
               +---------------+
               |               |
               | processes.txt |
               |               |
               +---------------+

(Diagramm erstellt mit Asciiflow.)

Siehe die tee Man Seite Für mehr Information.

T-Shirt als Hack

In der Situation, die deine Frage beschreibt, verwenden tee ist ein Hack, weil wir die Hälfte dessen ignorieren, was es tut. 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 Piped-Befehl übergeben. wir benutzen nur tee als eine alternative Art, eine Datei zu schreiben und damit wir sie aufrufen können sudo.

Machen Sie diesen Trick einfach

Sie können dies zu Ihrem hinzufügen .vimrc um diesen Trick benutzerfreundlich zu machen: einfach eingeben :w!!.

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

Das > /dev/nullTeil ausdrücklich Die Standardausgabe wird verworfen, da wir, wie gesagt, nichts an einen anderen Piped-Befehl übergeben müssen.


1272
2017-08-16 12:49



In der ausgeführten Befehlszeile % steht für die aktueller Dateiname. Dies ist in dokumentiert :help cmdline-special:

In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
        %       Is replaced with the current file name.

Wie du bereits herausgefunden hast, :w !cmd leitet den Inhalt des aktuellen Puffers an einen anderen Befehl weiter. Was tee does kopiert die Standardeingabe in eine oder mehrere Dateien und auch in die Standardausgabe. Deshalb, :w !sudo tee % > /dev/null schreibt effektiv den Inhalt des aktuellen Puffers in die aktuelle Datei während er root ist. Ein anderer Befehl, der dafür verwendet werden kann, ist dd:

:w !sudo dd of=% > /dev/null

Als Abkürzung können Sie dieses Mapping zu Ihrem hinzufügen .vimrc:

" Force saving files that require root permission 
cnoremap w!! w !sudo tee > /dev/null %

Mit dem oben genannten können Sie eingeben :w!!<Enter> um die Datei als root zu speichern.


88
2018-04-08 14:45



Das funktioniert auch gut:

:w !sudo sh -c "cat > %"

Dies ist inspiriert durch den Kommentar von @Nathan Long.

BEACHTEN:

" muss statt verwendet werden ' weil wir wollen % vor dem Übergang in die Shell erweitert werden.


18
2017-07-29 08:08



:w - Schreibe 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, z. B. /etc/apache2/conf.d/mediawiki.conf. Mit anderen Worten, der Befehl tee wird als root ausgeführt und benötigt die Standardeingabe und schreibt sie in eine Datei, die durch% repräsentiert wird. Dies führt jedoch dazu, dass Sie die Datei erneut laden müssen (drücken Sie L, um die Änderungen in vim selbst zu laden):

Tutorial-Link


16
2018-06-04 06:02



Die akzeptierte Antwort deckt alles ab, also gebe ich nur ein weiteres Beispiel für eine Abkürzung das benutze ich für die Aufzeichnung.

Fügen Sie es zu Ihrem hinzu etc/vim/vimrc (oder ~/.vimrc):

  • cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!

Woher:

  • 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!: Lauf es still
  • write !sudo tee % >/dev/null: die OP-Frage, eine Umleitung von Nachrichten hinzugefügt NULL um einen sauberen Befehl zu machen
  • <bar> edit!: Dieser Trick ist die Kirsche des Kuchens: Er nennt auch die edit Befehl, den Puffer neu zu laden und dann Nachrichten wie Der Puffer hat sich geändert. <bar> Wie schreibt man das? Rohr Symbol, um hier zwei Befehle zu trennen.

Ich hoffe es hilft. Siehe auch für andere Probleme:


3
2018-01-13 07:12



Ich würde gerne einen anderen Ansatz vorschlagen "Oups, ich habe vergessen zu schreiben sudo während ich meine Datei öffne " Problem:

Anstatt einen zu erhalten permission deniedund muss tippen :w!!, Ich finde es eleganter, eine Bedingung zu haben vim Befehl, der das tut sudo vim wenn der Dateibesitzer ist root.

Das ist so einfach zu implementieren (es könnte sogar elegantere Implementierungen geben, ich bin definitiv kein Bash-Guru):

function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

Und es funktioniert wirklich gut.

Dies ist ein mehr bash-zentrierten Ansatz als a vim-ein, damit nicht jeder es mag.

Na sicher:

  • Es gibt Anwendungsfälle, in denen es fehlschlägt (wenn der Dateieigentümer nicht ist) root aber erfordert sudo, aber die Funktion kann trotzdem bearbeitet werden)
  • Es macht keinen Sinn, wenn man es benutzt vim für das Lesen nur einer Datei (soweit ich mich interessiere, benutze ich tail oder cat für kleine Dateien)

Aber ich finde das bringt viel besser Entwickler-ErfahrungDas ist etwas, das IMHO dazu neigt, bei der Verwendung vergessen zu werden bash. :-)


1
2018-02-28 18:21