Comment fonctionne l'astuce "écrire avec sudo"?
beaucoup d'entre vous ont probablement vu la commande qui vous permet d'écrire sur un fichier qui nécessite la permission de root, même si vous avez oublié d'ouvrir vim avec sudo:
:w !sudo tee %
la chose est que je ne comprends pas ce qui se passe exactement ici.
j'ai déjà compris:
w
est pour ce
*:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
Execute {cmd} with [range] lines as standard input
(note the space in front of the '!'). {cmd} is
executed like with ":!{cmd}", any '!' is replaced with
the previous command |:!|.
donc il passe toutes les lignes en entrée standard.
la partie !sudo tee
appelle tee
avec privilèges d'administrateur.
pour que tout cela ait un sens, le %
devrait afficher le nom du fichier (comme paramètre pour tee
), mais je ne trouve pas de références sur l'aide pour ce comportement.
tl; dr Quelqu'un pourrait-il m'aider à disséquer cette commande?
6 réponses
Dans :w !sudo tee %
...
%
signifie "le fichier courant"
comme eugeney a souligné , %
signifie en effet"le nom de fichier actuel". Une autre utilisation pour cela dans Vim est dans les commandes de substitution. Par exemple, :%s/foo/bar
signifie dans le fichier courant , remplacer foo
par bar
."Si vous mettez en surbrillance un texte avant de taper :s
, vous verrez que les lignes surlignées prennent la place de %
comme Plage de substitution.
:w
n'est pas la mise à jour de votre fichier
une partie confuse de cette astuce est que vous pourriez penser que :w
modifie votre fichier, mais ce n'est pas le cas. Si vous ouvrez et modifiez file1.txt
, puis lancez :w file2.txt
, ce serait un "Enregistrer sous"; file1.txt
ne serait pas modifié, mais le contenu du tampon actuel serait envoyé à file2.txt
.
au lieu de file2.txt
, vous pouvez substituer une commande shell pour recevoir le contenu du tampon . Par exemple, :w !cat
affichera simplement le contenu.
Si Vim n'a pas été exécuté avec sudo access, son :w
ne peut pas modifier un fichier protégé, mais s'il passe le contenu du tampon au shell, une commande dans le shell peut être exécuté avec sudo . Dans ce cas, nous utilisez tee
.
Compréhension tee
comme pour tee
, représentez la commande tee
comme un tuyau en forme de T dans une situation normale de tuyauterie bash: elle dirige la sortie vers le(S) fichier (s) spécifié (s) et l'envoie aussi vers la sortie standard , qui peut être saisi par la commande pipée suivante.
Par exemple, dans ps -ax | tee processes.txt | grep 'foo'
, la liste des processus sera écrit dans un fichier texte et passe à grep
.
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(diagramme créé avec Asciiflow .)
Voir la tee
l'homme page pour plus d'info.
Té comme un hack
dans la situation que votre question décrit, en utilisant tee
est un piratage parce que nous ignorons la moitié de ce qu'il fait . sudo tee
écrit à notre fichier et envoie également le contenu du tampon à la sortie standard, mais nous ignorons la sortie standard . Nous n'avons pas besoin de passer quoi que ce soit à une autre commande pipée dans ce cas; nous utilisons juste tee
comme une autre façon d'écrire un fichier et pour que nous puissions l'appeler avec sudo
.
Faire ce truc facile
vous pouvez ajouter ceci à votre .vimrc
pour rendre cette astuce facile à l'utilisation: il suffit de taper :w!!
.
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
la > /dev/null
part explicitement rejette la sortie standard, puisque, comme je l'ai dit, nous n'avons pas besoin de passer quoi que ce soit à une autre commande pipée.
dans la ligne de commande exécutée, %
signifie nom du fichier courant . Ceci est documenté dans :help cmdline-special
:
In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
% Is replaced with the current file name.
comme vous l'avez déjà découvert, :w !cmd
renvoie le contenu du tampon courant à une autre commande. Ce que tee
fait est de copier l'entrée standard vers un ou plusieurs fichiers, et aussi vers la sortie standard. Par conséquent, :w !sudo tee % > /dev/null
effectivement écrit le contenu du tampon courant dans le fichier courant tout en étant root . Une autre commande qui peut être utilisée pour cela est dd
:
:w !sudo dd of=% > /dev/null
comme raccourci, vous pouvez ajouter ce mapping à votre .vimrc
:
" Force saving files that require root permission
cnoremap w!! w !sudo tee > /dev/null %
avec ce qui précède, vous pouvez taper :w!!<Enter>
pour enregistrer le fichier comme root.
cela fonctionne aussi bien:
:w !sudo sh -c "cat > %"
c'est inspiré par le commentaire de @Nathan Long.
AVIS :
"
doit être utilisé au lieu de '
parce que nous voulons que %
soit étendu avant de passer à shell.
:w
- Ecrire un fichier.
!sudo
- Appelons-shell commande sudo.
tee
- la sortie de la commande write (vim :w) redirigée en utilisant tee. Le % n'est rien d'autre que le nom du fichier courant i.e. /etc/apache2/conf.d / mediawiki.conf. En d'autres termes, la commande tee est exécutée en tant que root et elle prend une entrée standard et l'écrit dans un fichier représenté par %. Cependant, cela vous incitera à recharger le fichier (cliquez sur L pour charger les changements dans vim lui-même).):
la réponse acceptée couvre tout, donc je vais juste donner un autre exemple d'un raccourci que j'utilise, pour le dossier.
ajoutez-le à votre etc/vim/vimrc
(ou ~/.vimrc
):
-
cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!
où:
-
cnoremap
: indique vim que le raccourci suivant doit être associé à la commande ligne. -
w!!
: le raccourci lui-même. -
execute '...'
: une commande qui exécute la chaîne suivante. -
silent!
: exécuter en mode silencieux -
write !sudo tee % >/dev/null
: la question OP, a ajouté une redirection de messages àNULL
pour faire une commande propre -
<bar> edit!
: cette astuce est la cerise sur le gâteau: elle appelle aussi la commandeedit
pour recharger le tampon et puis évitez les messages tels que le tampon a changé .<bar>
est la façon d'écrire le pipe symbole pour séparer deux commandes ici.
j'Espère que ça aide. Voir aussi pour d'autres problèmes:
j'aimerais suggérer une autre approche au " Oups j'ai oublié d'écrire sudo
en ouvrant mon fichier" issue:
au lieu de recevoir un permission denied
, et d'avoir à taper :w!!
, je trouve plus élégant d'avoir une commande conditionnelle vim
qui fait sudo vim
si le propriétaire du fichier est root
.
c'est aussi facile à mettre en œuvre (il pourrait même y avoir des mises en œuvre plus élégantes, je suis clairement pas un bash-guru):
function vim(){
OWNER=$(stat -c '%U' )
if [[ "$OWNER" == "root" ]]; then
sudo /usr/bin/vim $*;
else
/usr/bin/vim $*;
fi
}
Et ça marche vraiment bien.
c'est une approche plus bash
- centrée qu'un vim
- un donc pas tout le monde pourrait aimer.
bien sûr:
- Il ya des cas d'utilisation où il va échouer (lorsque le propriétaire du fichier n'est pas
root
mais nécessitesudo
, mais la fonction peut être éditée de toute façon) - il n'est pas faites du sens lorsque vous utilisez
vim
pour la lecture-seulement un fichier (en ce qui me concerne, j'utilisetail
oucat
pour les petits fichiers)
mais je trouve que cela apporte une bien meilleure dev expérience utilisateur , qui est quelque chose que IMHO tend à être oublié en utilisant bash
. :- )