Erhalten Sie Root-Berechtigungen für eine Datei in vi? [geschlossen]

245

Während ich Bearbeitungsdateien bearbeite, öffne ich oft eine mit vi und stelle dann beim Speichern fest, dass ich nicht eingegeben habe

sudo vi filename

Gibt es eine Möglichkeit, vi sudo-Berechtigungen zum Speichern der Datei zu erteilen? Ich erinnere mich an etwas darüber, als ich vor einiger Zeit ein paar Dinge über vi nachgeschlagen habe, aber jetzt kann ich es nicht finden.

Paul Wicks
quelle
Vielleicht speichern Sie einfach eine Kopie in Ihrem Home-Verzeichnis und "sudo mv" es später
paan

Antworten:

296

% wird durch den aktuellen Dateinamen ersetzt, daher können Sie Folgendes verwenden:

:w !sudo tee %

( vimerkennt, dass die Datei geändert wurde, und fragt, ob sie neu geladen werden soll. Sagen Sie "Ja", indem Sie " [L]OK" wählen .)

Als Verknüpfung können Sie Ihren eigenen Befehl definieren. Geben Sie Folgendes in Ihre ein .vimrc:

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

Mit den oben genannten können Sie eingeben :W<Enter>, um die Datei zu speichern. Seit 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 eingeben :w!!und es wird bis zur vollständigen Befehlszeile erweitert, wobei der Cursor am Ende verbleibt, sodass Sie das bei Bedarf durch %einen eigenen Dateinamen ersetzen können .

Beroe
quelle
5
Funktioniert das in gvim? Durch Ausführen des Befehls fordert Vim zur Eingabe des Kennworts auf, akzeptiert jedoch keine Eingaben. Es sudo: 1 incorrect password attempt
läuft
ich würde keinen grund für gvim sehen, sich anders zu verhalten ... bist du sicher, dass sudo alleine richtig funktioniert?
Wenn Sie Root-Berechtigungen zum Speichern einer neuen Datei benötigen, ersetzen Sie% durch den Namen (einschließlich Pfad) der neuen Datei.
gvkv
Manchmal müssen Sie Ihren Benutzer zuerst zur Sudoer-Datei hinzufügen, den Root-Benutzer eingeben und die /etc/sudoersDatei öffnen , your_username ALL=(ALL) ALLunter der Zeile hinzufügen root ALL=(ALL) ALL, beenden und speichern.
coolste
1
@coolesting: 1) Es gibt ungefähr tausend andere Dinge, die Sie tun müssen ... wir können sie nicht alle auflisten. 2) Sie sollten immer verwenden visudo.
32

Im Allgemeinen können Sie die effektive Benutzer-ID des vi-Prozesses nicht ändern, aber Sie können dies tun:

:w !sudo tee myfile
Mark Harrison
quelle
1
:w !sudo tee % >/dev/nulloder :w !sudo dd of=%vermeiden Sie, dass der Inhalt der Datei beim Speichern der Datei wiedergegeben wird.
Jamessan
Können Sie erklären, wie das funktioniert? Ich habe nachgeschlagen teeund festgestellt, dass es sich um einen Unix-Pipe-Befehl handelt, und !einen Shell-Befehl eingefügt. Ist das :wSchreiben auf Standard out, was von weitergeleitet wird tee?
Eric Hu
4
@ Eric, das stimmt. Der Befehl "tee myfile" kopiert stdin in myfile. Das Ausführen von "sudo tee myfile" führt dasselbe aus, aber da der Tee-Prozess root gehört, gehört myfile ebenfalls root. Auf der vi-Seite leitet ": w! Some command line" alle Zeilen an "some command line" weiter.
Mark Harrison
16

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, :writeweil es den notwendigen Funktionsaufruf nicht verarbeitet.

!stellt den :!Befehl dar: den einzigen Befehl, der :writeakzeptiert. Akzeptiert normalerweise :writeeinen Dateipfad, in den geschrieben werden soll. :!führt alleine einen Befehl in einer Shell aus (z. B. using bash -c). Mit :writewird der Befehl in der Shell ausgeführt und anschließend die gesamte Datei in geschrieben stdin.

sudosollte 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.

teeleitet stdinan die angegebene Datei weiter. :writewird schreiben stdin, dann teeerhä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.

>NULund auf das >/dev/nullNullgerät stdoutder Plattform umleiten . Obwohl wir den Befehl zum Schweigen gebracht haben, möchten wir nicht, dass der gesamte Overhead, der mit dem Weiterleiten stdinan vim verbunden ist, am besten so früh wie möglich ausgegeben wird. NUList 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 ~/.vimrcDatei 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 ~/.vimrcDatei, die computerübergreifend synchronisiert wird. Daher habe ich meine plattformübergreifende Funktionalität hinzugefügt. Hier ist eine ~/.vimrcmit 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
Zenexer
quelle
Was ist, wenn Sie Windows auslösen, indem Sie tatsächlich eine weltweit beschreibbare Datei unter C: \ dev \ null erstellen?
Paul Stelian
1
@PaulStelian Möglich, aber unwahrscheinlich. Sie können diesen Code problemlos erweitern, um eine Vielzahl von Plattformen und Umständen zu berücksichtigen. In der Realität ist es unwahrscheinlich , dass Sie unter Windows auf eine Situation stoßen, in der es eine sudogibt, aber nicht /dev/null. Sie müssten also schicker werden, wenn Sie echte plattformübergreifende Unterstützung wünschen. Es ist eher eine Einführung - Denkanstöße. :)
Zenexer
11

Wenn Sie Vim verwenden , steht ein Skript mit dem Namen sudo.vim zur Verfügung . Wenn Sie feststellen, dass Sie eine Datei geöffnet haben, für deren Lesen Sie Root-Zugriff benötigen, geben Sie 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.

kurzlebig
quelle
4
Ich würde die Verwendung dieses Skripts nicht empfehlen, da es beim Enthalten von Dateinamen keine angemessenen Vorsichtsmaßnahmen trifft.
Jamessan
7

Ryans Rat ist im Allgemeinen gut. Wenn Sie jedoch Schritt 3 ausführen, verschieben Sie die temporäre Datei nicht. Es wird den falschen Besitz und die falschen Berechtigungen haben. Stattdessen sudoeditdie richtige Datei und den Inhalt (mit :roder ähnlichem) der temporären Datei einlesen .

Wenn Sie Schritt 2 ausführen :w!, erzwingen Sie das Schreiben der Datei.

Chris Jester-Young
quelle
3

Wenn Sie für eine Datei, für deren Bearbeitung Sie einen Sudo-Zugriff benötigen, in den Einfügemodus wechseln, wird eine Statusmeldung angezeigt

-- INSERT -- W10: Warning: Changing a readonly file

Wenn ich das vermisse, tue ich das 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.

dbr
quelle
cat $ tmp> $ target ist kreativ, aber gibt es einen Grund, die Datei nicht einfach zu sudo mv?
Ojrac
Guter Punkt. Es gab auch ein großes Problem mit sudo cat. Etwas> / etc / blah - das verwendet sudo, um die Datei zu katzen, und dann den normalen Benutzer, um in / etc / blah zu schreiben (was nicht funktioniert). Es wurde behoben die Antwort und fügte Ihren besseren sudo mv Vorschlag hinzu ..
dbr
Der mv-Vorschlag behält keine Berechtigungen bei.
Paul Stelian
1

Ein kurzer Google scheint diesen Rat zu geben:

  1. Versuchen Sie nicht zu bearbeiten, wenn es schreibgeschützt ist.
  2. Möglicherweise können Sie die Berechtigungen für die Datei ändern. (Ob Sie damit sparen können oder nicht, hängt vom Experimentieren ab.)
  3. Wenn Sie trotzdem bearbeitet haben, speichern Sie diese in einer temporären Datei und verschieben Sie sie.

http://ubuntuforums.org/showthread.php?t=782136

Ryan Fox
quelle
1

Hier ist ein weiteres Plugin, das seit Beantwortung dieser Frage aufgetaucht ist, ein Plugin namens SudoEdit, das SudoRead- und SudoWrite-Funktionen bereitstellt, die standardmäßig zuerst sudo und su verwenden, wenn dies fehlschlägt: http://www.vim.org/scripts/ script.php? script_id = 2709

James Snyder
quelle
0

Ich habe dies in meinem ~ / .bashrc:

alias svim='sudo vim'

Wenn ich jetzt eine Konfigurationsdatei bearbeiten muss, öffne ich sie einfach mit svim.

Pisswillis
quelle
2
Der sudoeditBefehl sollte bevorzugt werden, da vim nicht als root ausgeführt werden muss.
Jamessan
2
Dies hindert Sie immer noch nicht daran, vim anstelle von svim zu binden, was dem OP entgangen ist.
ScaryAardvark
3
-1, Dies bedeutet nur "Denken Sie daran, beim Öffnen einer Datei sudo einzugeben". Das OP möchte wissen, wie sie Root-Berechtigungen in vi erhalten können.
Brad Koch
-2

Ein schneller Hack, den Sie in Betracht ziehen können, besteht darin, einen chmod für die zu bearbeitende Datei durchzufü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 einige Sekunden jeder die Datei lesen / ändern kann, ohne dass Sie es merken.

num1
quelle