Avertissements courants
La méthode la plus courante pour contourner le problème des fichiers 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 ont une combinaison de 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 avec des caractères ou des espaces inhabituels peuvent ne pas être géré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 à entrer une commande. Il doit être omis dans les scripts.
sil[ent]
supprime la sortie de la commande. Dans ce cas, nous voulons arrêter l' Press any key to continue
invite -like qui apparaît après l'exécution de la :!
commande.
exec[ute]
exécute une chaîne en tant que commande. Nous ne pouvons pas simplement exécuter :write
car il ne traitera pas l'appel de fonction nécessaire.
!
représente la :!
commande: la seule commande qui :write
accepte. Normalement, :write
accepte un chemin de fichier dans lequel écrire. :!
seule 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 le fichier entier dans stdin
.
sudo
devrait être évident, car c'est pourquoi vous êtes ici. Exécutez la commande en tant que super-utilisateur. Il y a beaucoup d'informations sur le net sur la façon dont cela fonctionne.
tee
tuyaux stdin
vers le fichier donné. :write
va écrire dans stdin
, puis le super-utilisateur tee
recevra le contenu du fichier et écrit le fichier. Il ne créera pas de nouveau fichier - juste écraser le contenu - ainsi les modes et attributs de fichier seront préservés.
shellescape()
échappe les caractères spéciaux dans le chemin d'accès au fichier donné, comme approprié pour le 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 complète du shell, nous souhaitons passer une valeur non nulle comme deuxième argument pour permettre l'échappement de 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, assurez-vous donc que vous n'avez pas changé le répertoire courant. Dans certaines solutions, le symbole commercial-at sera omis. Selon l'emplacement, %
est une expression valide et a le même effet que la lecture du %
registre. Cependant, imbriqué dans une autre expression, le raccourci est généralement interdit: comme dans ce cas.
>NUL
et >/dev/null
redirigez stdout
vers le périphérique nul de la plate-forme. Même si nous avons réduit la commande au silence, nous ne voulons pas que tous les frais généraux associés à la tuyauterie soient stdin
renvoyés à vim - le mieux est de la vider le plus tôt possible. NUL
est le périphérique nul sous DOS, MS-DOS et Windows, pas 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 être utiles.)
~ / .vimrc
Dépendant de la plateforme
Bien sûr, vous ne voulez toujours pas les mémoriser et les taper à chaque fois. Il est beaucoup plus facile de mapper la commande appropriée à une commande utilisateur plus simple. Pour ce faire sur POSIX, vous pouvez ajouter la ligne suivante à votre ~/.vimrc
fichier, en la créant si elle 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 des autorisations de super-utilisateur - beaucoup plus facile.
Indépendant de la plateforme
J'utilise un ~/.vimrc
fichier indépendant de la plate-forme qui se synchronise entre les ordinateurs, j'ai donc ajouté une fonctionnalité multi-plate-forme 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