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?

1168
demandé sur Yamaneko 2010-04-08 18:36:50

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.

1308
répondu Nathan Long 2018-08-06 15:43:51

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.

89
répondu Eugene Yarmash 2017-06-24 23:02:25

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.

18
répondu feihu 2014-07-29 08:08:07

: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).):

tutoriel lien

16
répondu kev 2011-06-04 06:02:49

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 commande edit 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:

3
répondu Dr Beco 2018-01-13 07:12:59

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écessite sudo , 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'utilise tail ou cat 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 . :- )

1
répondu Augustin Riedinger 2018-02-28 18:21:56