Obtenir les autorisations root sur un fichier à l'intérieur de vi ?
Question
Souvent, en éditant des fichiers de configuration, j'en ouvre un avec vi et puis quand je vais le sauvegarder, je me rends compte que je n'ai pas tapé
sudo vi filename
Existe-t-il un moyen d'accorder à vi sudo les privilèges pour enregistrer le fichier ?Il me semble avoir vu quelque chose à ce sujet en recherchant des informations sur vi il y a quelque temps, mais maintenant je ne le trouve pas.
La solution
%
est remplacé par le nom du fichier actuel, vous pouvez donc utiliser :
:w !sudo tee %
(vim
détectera que le fichier a été modifié et vous demandera si vous souhaitez qu'il soit rechargé.Dites oui en choisissant [L]
plutôt que OK.)
En guise de raccourci, vous pouvez définir votre propre commande.Mettez ce qui suit dans votre .vimrc
:
command W w !sudo tee % >/dev/null
Avec ce qui précède, vous pouvez taper :W<Enter>
pour enregistrer le fichier.Depuis que j'ai écrit ceci, j'ai trouvé une manière plus agréable (à mon avis) de procéder :
cmap w!! w !sudo tee >/dev/null %
De cette façon, vous pouvez taper :w!!
et il sera étendu à la ligne de commande complète, laissant le curseur à la fin, afin que vous puissiez remplacer le %
avec votre propre nom de fichier, si vous le souhaitez.
Autres conseils
En général, vous ne pouvez pas modifier l'ID utilisateur effectif du processus vi, mais vous pouvez le faire :
:w !sudo tee myfile
Mises en garde courantes
La méthode la plus courante pour contourner le problème du fichier en lecture seule consiste à ouvrir un canal vers le fichier actuel en tant que super-utilisateur à l'aide d'une implémentation de sudo tee
.Cependant, toutes les solutions les plus populaires que j’ai trouvées sur Internet combinent plusieurs mises en garde potentielles :
- Le fichier entier est écrit sur le terminal, ainsi que le fichier.Cela peut être lent pour les fichiers volumineux, en particulier sur les connexions réseau lentes.
- Le fichier perd ses modes et attributs similaires.
- Les chemins de fichiers contenant des caractères ou des espaces inhabituels peuvent ne pas être traités correctement.
Solutions
Pour contourner tous ces problèmes, vous pouvez utiliser la commande suivante :
" 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'
Ceux-ci peuvent être raccourcis, respectueusement :
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Explication
:
commence la commande ;vous devrez taper ce caractère en mode normal pour commencer à saisir une commande.Il doit être omis dans les scripts.
sil[ent]
supprime la sortie de la commande.Dans ce cas, nous voulons arrêter le Press any key to continue
-une invite semblable à celle qui apparaît après l'exécution de :!
commande.
exec[ute]
exécute une chaîne en tant que commande.Nous ne pouvons pas simplement courir :write
car il ne traitera pas l'appel de fonction nécessaire.
!
représente le :!
commande:la seule commande qui :write
accepte.Normalement, :write
accepte un chemin de fichier dans lequel écrire. :!
à lui seul, exécute une commande dans un shell (par exemple, en utilisant bash -c
).Avec :write
, il exécutera la commande dans le shell, puis écrira l'intégralité du fichier dans stdin
.
sudo
Cela devrait être évident, puisque c'est pour cela que vous êtes ici.Exécutez la commande en tant que super-utilisateur.Il existe de nombreuses informations sur le net sur la façon dont cela fonctionne.
tee
tuyaux stdin
au fichier donné. :write
j'écrirai à stdin
, alors le super-utilisateur tee
recevra le contenu du fichier et écrira le fichier.Il ne créera pas de nouveau fichier - écrasera simplement le contenu - afin que les modes et attributs du fichier soient préservés.
shellescape()
échappe les caractères spéciaux dans le chemin de fichier donné en fonction du shell actuel.Avec un seul paramètre, il suffit généralement de placer le chemin entre guillemets si nécessaire.Puisque nous envoyons vers une ligne de commande shell complète, nous voudrons transmettre une valeur non nulle comme deuxième argument pour permettre l'échappement par barre oblique inverse d'autres caractères spéciaux qui pourraient autrement déclencher le shell.
@%
lit le contenu du %
registre, qui contient le nom de fichier du tampon actuel.Ce n'est pas nécessairement un chemin absolu, alors assurez-vous de ne pas avoir modifié le répertoire actuel.Dans certaines solutions, le symbole commercial-at est omis.Selon l'emplacement, %
est une expression valide et a le même effet que la lecture du %
registre.Imbriqué dans une autre expression, le raccourci est généralement interdit, cependant :comme dans ce cas.
>NUL
et >/dev/null
réorienter stdout
au périphérique nul de la plateforme.Même si nous avons désactivé la commande, nous ne voulons pas que toute la surcharge associée à la tuyauterie stdin
revenons à vim - il est préférable de le vider le plus tôt possible. NUL
est le périphérique nul sous DOS, MS-DOS et Windows, et non un fichier valide.Depuis Windows 8, les redirections vers NUL n'entraînent pas l'écriture d'un fichier nommé NUL.Essayez de créer un fichier sur votre bureau nommé NUL, avec ou sans extension de fichier :vous ne pourrez pas le faire.(Il existe plusieurs autres noms de périphériques dans Windows qui pourraient valoir la peine d'être connus.)
~/.vimrc
Dépend de la plateforme
Bien sûr, vous ne voulez toujours pas les mémoriser et les saisir à chaque fois.Il est beaucoup plus facile de mapper la commande appropriée à une commande utilisateur plus simple.Pour ce faire sous POSIX, vous pouvez ajouter la ligne suivante à votre ~/.vimrc
fichier, en le créant s'il n'existe pas déjà :
command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
Cela vous permettra de taper la commande :W (sensible à la casse) pour écrire le fichier actuel avec les autorisations de super-utilisateur - beaucoup plus facilement.
Indépendant de la plateforme
J'utilise un outil indépendant de la plateforme ~/.vimrc
fichier qui se synchronise sur tous les ordinateurs, j'ai donc ajouté une fonctionnalité multiplateforme au mien.Voici un ~/.vimrc
avec uniquement les paramètres pertinents :
#!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
Si vous utilisez Vigueur, il existe un script disponible nommé sudo.vim.Si vous constatez que vous avez ouvert un fichier pour lequel vous avez besoin d'un accès root pour le lire, tapez
:e sudo:%Vim remplace le % par le nom du fichier actuel, et
sudo:
demande au script sudo.vim de prendre le relais pour la lecture et l'écriture.
Les conseils de Ryan sont généralement bons, cependant, si vous suivez l'étape 3, ne déplacez pas le fichier temporaire ;il aura la mauvaise propriété et les mauvaises autorisations.Plutôt, sudoedit
le bon fichier et lisez-en le contenu (en utilisant :r
ou similaire) du fichier temporaire.
Si vous suivez l'étape 2, utilisez :w!
pour forcer l'écriture du fichier.
Lorsque vous passez en mode insertion sur un fichier pour lequel vous avez besoin d'un accès sudo pour le modifier, vous recevez un message d'état indiquant
-- INSERT -- W10: Warning: Changing a readonly file
Si ça me manque, c'est généralement le cas
:w ~/edited_blah.tmp
:q
..alors..
sudo "cat edited_blah.tmp > /etc/blah"
..ou..
sudo mv edited_blah.tmp /etc/blah
Il existe probablement une manière moins détournée de procéder, mais cela fonctionne.
Un rapide Google semble donner ce conseil :
- N'essayez pas de modifier s'il est en lecture seule.
- Vous pourrez peut-être modifier les autorisations sur le fichier.(Que cela vous permette ou non d'économiser dépend de l'expérimentation.)
- Si vous avez quand même modifié, enregistrez-le dans un fichier temporaire, puis déplacez-le.
En voici un autre qui est apparu depuis la réponse à cette question, un plugin appelé SudoEdit qui fournit les fonctions SudoRead et SudoWrite, qui tenteront par défaut d'utiliser sudo en premier et su si cela échoue : http://www.vim.org/scripts/script.php?script_id=2709
J'ai ceci dans mon ~/.bashrc :
alias svim='sudo vim'
Désormais, chaque fois que j'ai besoin de modifier un fichier de configuration, je l'ouvre simplement avec svim.
Un hack rapide que vous pouvez envisager consiste à effectuer un chmod sur le fichier que vous modifiez, à l'enregistrer avec vim, puis à revenir à l'état d'origine du fichier.
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)
Bien sûr, je ne recommande pas cette approche dans un système où vous vous inquiétez de la sécurité, car pendant quelques secondes, n'importe qui peut lire/modifier le fichier sans que vous vous en rendiez compte.
utiliser gksudo au lieu de sudo pour GVim, c'est-à-dire
cmap w!! w !gksudo tee >/dev/null %