Root-Berechtigungen für eine Datei innerhalb von vi erhalten?
Frage
Beim Bearbeiten von Konfigurationsdateien öffne ich oft eine mit vi und stelle dann beim Speichern fest, dass ich nichts eingegeben habe
sudo vi filename
Gibt es eine Möglichkeit, vi Sudo-Berechtigungen zum Speichern der Datei zu erteilen?Ich erinnere mich, dass ich vor einiger Zeit etwas dazu gesehen habe, als ich nach etwas über vi gesucht habe, aber jetzt kann ich es nicht finden.
Lösung
%
wird durch den aktuellen Dateinamen ersetzt, Sie können also Folgendes verwenden:
:w !sudo tee %
(vim
erkennt, dass die Datei geändert wurde und fragt, ob Sie sie neu laden möchten.Sagen Sie Ja, indem Sie wählen [L]
statt OK.)
Als Verknüpfung können Sie Ihren eigenen Befehl definieren.Tragen Sie Folgendes in Ihr ein .vimrc
:
command W w !sudo tee % >/dev/null
Mit dem Obigen können Sie tippen :W<Enter>
um die Datei zu speichern.Seitdem ich das geschrieben habe, habe ich (meiner Meinung nach) einen schöneren Weg gefunden, dies zu tun:
cmap w!! w !sudo tee >/dev/null %
Auf diese Weise können Sie tippen :w!!
und es wird auf die vollständige Befehlszeile erweitert, wobei der Cursor am Ende verbleibt, sodass Sie das ersetzen können %
mit einem eigenen Dateinamen, wenn Sie möchten.
Andere Tipps
Im Allgemeinen können Sie die effektive Benutzer-ID des vi-Prozesses nicht ändern, aber Sie können Folgendes tun:
:w !sudo tee myfile
Allgemeine Vorsichtsmaßnahmen
Die gebräuchlichste Methode, das Problem der schreibgeschützten Datei zu umgehen, besteht darin, als Superuser mithilfe einer Implementierung von eine Pipe zur aktuellen Datei zu öffnen sudo tee
.Allerdings weisen alle beliebtesten Lösungen, die ich im Internet gefunden habe, eine Kombination mehrerer potenzieller Einschränkungen auf:
- Die gesamte Datei wird auf 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 korrekt verarbeitet.
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 mit der Eingabe eines Befehls zu beginnen.Es sollte in Skripten weggelassen werden.
sil[ent]
unterdrückt die Ausgabe des Befehls.In diesem Fall wollen wir das stoppen Press any key to continue
-ähnliche Eingabeaufforderung, die nach dem Ausführen von angezeigt wird :!
Befehl.
exec[ute]
führt einen String als Befehl aus.Wir können nicht einfach rennen :write
weil der erforderliche Funktionsaufruf nicht verarbeitet wird.
!
repräsentiert die :!
Befehl:der einzige Befehl, der :write
akzeptiert.Normalerweise, :write
akzeptiert einen Dateipfad, in den geschrieben werden soll. :!
führt allein einen Befehl in einer Shell aus (z. B. using bash -c
).Mit :write
, führt es den Befehl in der Shell aus und schreibt dann die gesamte Datei hinein stdin
.
sudo
sollte klar sein, denn deshalb sind Sie hier.Führen Sie den Befehl als Superuser aus.Im Internet gibt es zahlreiche Informationen darüber, wie das funktioniert.
tee
Rohre stdin
zur angegebenen Datei. :write
Werde anschreiben stdin
, dann der Superuser tee
empfängt den Dateiinhalt und schreibt die Datei.Es wird keine neue Datei erstellt, sondern nur der Inhalt überschrieben, sodass die Dateimodi und -attribute erhalten bleiben.
shellescape()
maskiert Sonderzeichen im angegebenen Dateipfad entsprechend der aktuellen Shell.Bei nur einem Parameter wird der Pfad normalerweise nur bei Bedarf in Anführungszeichen gesetzt.Da wir an eine vollständige Shell-Befehlszeile senden, möchten wir als zweites Argument einen Wert ungleich Null übergeben, um das Backslash-Escape anderer Sonderzeichen zu ermöglichen, die andernfalls die Shell zum Absturz bringen könnten.
@%
liest den Inhalt der %
Register, das den Dateinamen des aktuellen Puffers enthält.Es handelt sich nicht unbedingt um einen absoluten Pfad. Stellen Sie daher sicher, dass Sie das aktuelle Verzeichnis nicht geändert haben.In einigen Lösungen wird das Commercial-at-Symbol weggelassen.Je nach Standort, %
ist ein gültiger Ausdruck und hat die gleiche Wirkung wie das Lesen von %
registrieren.In einem anderen Ausdruck verschachtelt ist die Verknüpfung im Allgemeinen jedoch nicht zulässig:wie in diesem Fall.
>NUL
Und >/dev/null
umleiten stdout
zum Nullgerät der Plattform.Obwohl wir den Befehl zum Schweigen gebracht haben, möchten wir nicht den gesamten mit der Weiterleitung verbundenen Aufwand verursachen stdin
Zurück zu vim – es ist am besten, es so früh wie möglich zu löschen. 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 zu erstellen, mit oder ohne Dateierweiterung:Sie werden dazu nicht in der Lage sein.(Es gibt mehrere andere Gerätenamen in Windows, die es wert sein könnten, sie kennenzulernen.)
~/.vimrc
Plattformabhängig
Natürlich möchten Sie diese trotzdem 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 die folgende Zeile zu Ihrem hinzufügen ~/.vimrc
Datei, erstellen Sie sie, falls sie noch nicht vorhanden ist:
command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
Dadurch können Sie den Befehl :W (Groß-/Kleinschreibung beachten) eingeben, um die aktuelle Datei mit Superuser-Berechtigungen zu schreiben – was viel einfacher ist.
Plattformunabhängig
Ich verwende eine plattformunabhängige ~/.vimrc
Datei, die computerübergreifend synchronisiert wird, daher habe ich meine um Multiplattform-Funktionalität erweitert.Hier ist ein ~/.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
Wenn Sie verwenden Vim, es ist ein Skript mit dem Namen verfügbar sudo.vim.Wenn Sie feststellen, dass Sie eine Datei geöffnet haben, für deren Lesen Sie Root-Zugriff benötigen, geben Sie Folgendes ein
:e sudo:%Vim ersetzt % durch den Namen der aktuellen Datei und
sudo:
weist das Skript sudo.vim an, das Lesen und Schreiben zu übernehmen.
Ryans Rat ist im Allgemeinen gut. Wenn Sie jedoch Schritt 3 befolgen, verschieben Sie die temporäre Datei nicht.Es wird den falschen Besitz und die falschen Berechtigungen haben.Stattdessen, sudoedit
die richtige Datei und lesen Sie den Inhalt ein (mit :r
oder Ähnliches) der temporären Datei.
Wenn Sie Schritt 2 befolgen, verwenden Sie :w!
um das Schreiben der Datei zu erzwingen.
Wenn Sie für eine Datei, für deren Bearbeitung Sie Sudo-Zugriff benötigen, in den Einfügemodus wechseln, erhalten Sie die Statusmeldung „
-- INSERT -- W10: Warning: Changing a readonly file
Wenn ich das vermisse, tue ich es im Allgemeinen
:w ~/edited_blah.tmp
:q
..Dann..
sudo "cat edited_blah.tmp > /etc/blah"
..oder..
sudo mv edited_blah.tmp /etc/blah
Es gibt wahrscheinlich einen weniger umständlichen Weg, aber es funktioniert.
Ein kurzer Google scheint diesen Rat zu geben:
- Versuchen Sie nicht, die Datei zu bearbeiten, wenn sie schreibgeschützt ist.
- Möglicherweise können Sie die Berechtigungen für die Datei ändern.(Ob Sie damit sparen können, bleibt dem Experiment überlassen.)
- Wenn Sie trotzdem etwas bearbeitet haben, speichern Sie es in einer temporären Datei und verschieben Sie sie dann.
Hier ist ein weiteres Plugin, das seit der Beantwortung dieser Frage aufgetaucht ist, ein Plugin namens SudoEdit, das die Funktionen SudoRead und SudoWrite bereitstellt, die standardmäßig versuchen, zuerst sudo und su zu verwenden, wenn dies fehlschlägt: http://www.vim.org/scripts/script.php?script_id=2709
Ich habe das in meinem ~/.bashrc:
alias svim='sudo vim'
Wenn ich jetzt eine Konfigurationsdatei bearbeiten muss, öffne ich sie einfach mit svim.
Ein schneller Hack, den Sie in Betracht ziehen können, besteht darin, ein chmod für die Datei, die Sie bearbeiten, auszuführen, mit vim zu speichern und dann chmod auf den ursprünglichen Zustand der Datei zurückzusetzen.
ls -l test.file (to see the permissions of the file)
chmod 777 test.file
[This is where you save in vim]
chmod xxx test.file (restore the permissions you found in the first step)
Natürlich empfehle ich diesen Ansatz nicht in einem System, in dem Sie sich Sorgen um die Sicherheit machen, da für ein paar Sekunden jeder die Datei lesen/ändern kann, ohne dass Sie es merken.
verwenden gksudo anstatt Sudo für GVim d.h.
cmap w!! w !gksudo tee >/dev/null %