Allgemeine Vorsichtsmaßnahmen
Die häufigste Methode, um das Problem mit schreibgeschützten Dateien zu umgehen, besteht darin, eine Pipe zur aktuellen Datei als Superuser mithilfe einer Implementierung von zu öffnen sudo tee
. Alle gängigen Lösungen, die ich im Internet gefunden habe, haben jedoch eine Kombination aus mehreren möglichen Einschränkungen:
- Die gesamte Datei wird in das Terminal geschrieben, ebenso wie die Datei. Dies kann bei großen Dateien langsam sein, insbesondere bei langsamen Netzwerkverbindungen.
- Die Datei verliert ihre Modi und ähnliche Attribute.
- Dateipfade mit ungewöhnlichen Zeichen oder Leerzeichen werden möglicherweise nicht richtig behandelt.
Lösungen
Um all diese Probleme zu umgehen, können Sie den folgenden Befehl verwenden:
" On POSIX (Linux/Mac/BSD):
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
" Depending on the implementation, you might need this on Windows:
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Diese können respektvoll gekürzt werden:
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Erläuterung
:
beginnt den Befehl; Sie müssen dieses Zeichen im normalen Modus eingeben, um einen Befehl eingeben zu können. Es sollte in Skripten weggelassen werden.
sil[ent]
Unterdrückt die Ausgabe des Befehls. In diesem Fall möchten wir die Press any key to continue
ähnliche Eingabeaufforderung stoppen, die nach dem Ausführen des :!
Befehls angezeigt wird .
exec[ute]
führt eine Zeichenfolge als Befehl aus. Wir können nicht einfach laufen, :write
weil es den notwendigen Funktionsaufruf nicht verarbeitet.
!
stellt den :!
Befehl dar: den einzigen Befehl, der :write
akzeptiert. Akzeptiert normalerweise :write
einen Dateipfad, in den geschrieben werden soll. :!
führt alleine einen Befehl in einer Shell aus (z. B. using bash -c
). Mit :write
wird der Befehl in der Shell ausgeführt und anschließend die gesamte Datei in geschrieben stdin
.
sudo
sollte offensichtlich sein, denn deshalb bist du hier. Führen Sie den Befehl als Superuser aus. Es gibt viele Informationen im Internet darüber, wie das funktioniert.
tee
leitet stdin
an die angegebene Datei weiter. :write
wird schreiben stdin
, dann tee
erhält der Superuser den Dateiinhalt und schreibt die Datei. Es wird keine neue Datei erstellt - überschreiben Sie einfach den Inhalt -, sodass die Dateimodi und -attribute erhalten bleiben.
shellescape()
maskiert Sonderzeichen im angegebenen Dateipfad entsprechend der aktuellen Shell. Mit nur einem Parameter wird der Pfad normalerweise nach Bedarf in Anführungszeichen gesetzt. Da wir an eine vollständige Shell-Befehlszeile senden, möchten wir einen Wert ungleich Null als zweites Argument übergeben, um das Backslash-Escapezeichen anderer Sonderzeichen zu ermöglichen, die andernfalls die Shell auslösen könnten.
@%
liest den Inhalt des %
Registers, das den Dateinamen des aktuellen Puffers enthält. Es ist nicht unbedingt ein absoluter Pfad. Stellen Sie daher sicher, dass Sie das aktuelle Verzeichnis nicht geändert haben. In einigen Lösungen wird das Werbesymbol weggelassen. Ist je nach Speicherort %
ein gültiger Ausdruck und hat den gleichen Effekt wie das Lesen des %
Registers. In einem anderen Ausdruck verschachtelt, ist die Verknüpfung jedoch im Allgemeinen nicht zulässig: wie in diesem Fall.
>NUL
und auf das >/dev/null
Nullgerät stdout
der Plattform umleiten . Obwohl wir den Befehl zum Schweigen gebracht haben, möchten wir nicht, dass der gesamte Overhead, der mit dem Weiterleiten stdin
an vim verbunden ist, am besten so früh wie möglich ausgegeben wird. NUL
ist das Nullgerät unter DOS, MS-DOS und Windows, keine gültige Datei. Ab Windows 8 führen Umleitungen zu NUL nicht dazu, dass eine Datei mit dem Namen NUL geschrieben wird. Versuchen Sie, auf Ihrem Desktop eine Datei mit dem Namen NUL mit oder ohne Dateierweiterung zu erstellen. Dies ist nicht möglich. (Es gibt mehrere andere Gerätenamen in Windows, die es wert sein könnten, kennengelernt zu werden.)
~ / .vimrc
Plattformabhängig
Natürlich möchten Sie diese immer noch nicht auswendig lernen und jedes Mal abtippen. Es ist viel einfacher, den entsprechenden Befehl einem einfacheren Benutzerbefehl zuzuordnen. Um dies unter POSIX zu tun, können Sie Ihrer ~/.vimrc
Datei die folgende Zeile hinzufügen und sie erstellen, falls sie noch nicht vorhanden ist:
command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
Auf diese Weise können Sie den Befehl: W (Groß- und Kleinschreibung beachten) eingeben, um die aktuelle Datei mit Superuser-Berechtigungen zu schreiben - viel einfacher.
Plattformunabhängig
Ich verwende eine plattformunabhängige ~/.vimrc
Datei, die computerübergreifend synchronisiert wird. Daher habe ich meine plattformübergreifende Funktionalität hinzugefügt. Hier ist eine ~/.vimrc
mit nur den relevanten Einstellungen:
#!vim
" Use za (not a command; the keys) in normal mode to toggle a fold.
" META_COMMENT Modeline Definition: {{{1
" vim: ts=4 sw=4 sr sts=4 fdm=marker ff=unix fenc=utf-8
" ts: Actual tab character stops.
" sw: Indentation commands shift by this much.
" sr: Round existing indentation when using shift commands.
" sts: Virtual tab stops while using tab key.
" fdm: Folds are manually defined in file syntax.
" ff: Line endings should always be <NL> (line feed #09).
" fenc: Should always be UTF-8; #! must be first bytes, so no BOM.
" General Commands: User Ex commands. {{{1
command W call WriteAsSuperUser(@%) " Write file as super-user.
" Helper Functions: Used by user Ex commands. {{{1
function GetNullDevice() " Gets the path to the null device. {{{2
if filewritable('/dev/null')
return '/dev/null'
else
return 'NUL'
endif
endfunction
function WriteAsSuperUser(file) " Write buffer to a:file as the super user (on POSIX, root). {{{2
exec '%write !sudo tee ' . shellescape(a:file, 1) . ' >' . GetNullDevice()
endfunction
" }}}1
" EOF