Aaron Fischer Ingenieur, Vater, Heimwerker, Problemlöser

20 Oktober, 2009

Sudo, damn!

TL;DR:

Ich glaube jeder der unter Linux mit Vim arbeitet ist es schon so gegangen: Eine Datei wird geöffnet, mühsam editiert und beim Speichern stellt man fest, dass man nicht in diese Datei schreiben darf.

Offensichtlich gab es immer nur zwei Auswege. Entweder man verwarf die Änderungen, öffnete die Datei mit den Sudo-Rechten und machte alle Änderungen ein zweites mal oder aber man speicherte die Datei unter einem anderen Namen und verschob sie dann mit Sudo-Rechten.

Es gibt aber noch eine weitere sehr elegante Möglichkeit, nämlich folgende:

:w !sudo tee % > /dev/null

Was passiert hier jetzt genau? :w steht für Datei schreiben, das ist klar, doch wie geht es weiter? Erster Schritt ist immer die Hilfe aufrufen. Unter w[rite] sind einige Möglichkeiten aufgelistet, wie man den Befehl write verwenden kann. Die folgende Möglichkeit passt zum obigen Aufruf:

:[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 |:!|.

Alles in eckigen Klammern können wir weglassen. mit :w !{cmd} kann man also einen Befehl ausführen, der den Inhalt des Buffers als Standard Input bekommt. In unserem Falle ist das der Befehl tee, zu dem wir in der Manpage folgendes lesen:

TEE(1)

NAME
       tee - read from standard input and write to standard output and files

Wir können also per stdin etwas in tee schreiben, welches dann in eine Datei geschrieben wird und zugleich aus stdout ausgegeben wird. Ideal also für unser Problem, bis auf das Feature, dass alles was in stdin reinkommt nochmal ausgegeben wird. Dafür leiten wir wiederum mit >> die Standardausgabe nach /dev/null um.

visualisation

Zusammengenommen passierrt nun folgendes bei dem obigen Aufruf: Wir fordern Vim auf, die Datei zu speichern und leiten zudem die Ausgabe an den Befehl sudo tee % weiter (das % steht für den aktuellen Dateinamen). Dieser Befehl ruft tee mit Sudo-Rechten auf und leitet den Inhalt des Buffers in die Datei, die gerade bearbeitet wird. Der Schreibvorgang, der darauf von Vim selbst erfolgt, schlägt fehl, da Vim merkt, dass sich die Datei in der Zwischenzeit geändert hat. Mit einem l (kleines L) kann man nun den Inhalt der geänderten Datei wieder in Vim einlesen und weiter editieren.

Es steckt also hinter jedem komplizierten Befehl immer eine Logische Erklärung und sobald man diese verstanden hat, ist der Befehl trivial.

Wer den Befehl öfters braucht, kann auch ein Mapping erstellen, das alles mit einem Tastendruck erledigt.

command W w !sudo tee % >>/dev/null

Notiz auf dem CheatSheet: