web-dev-qa-db-fra.com

Comment fonctionne le truc vim "write with Sudo"?

Beaucoup d'entre vous ont probablement déjà vu la commande qui vous permet d'écrire sur un fichier nécessitant une autorisation root, même lorsque vous avez oublié d'ouvrir vim avec Sudo:

:w !Sudo tee %

Le fait est que je ne comprends pas ce qui se passe exactement ici.

J'ai déjà compris ceci: w est pour cela

                                                        *: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 |:!|.

il passe donc toutes les lignes en entrée standard.

La partie !Sudo tee appelle tee avec des privilèges d'administrateur.

Pour que tous aient un sens, le % doit générer le nom du fichier (en tant que paramètre pour tee), mais je ne trouve pas de références dans l'aide concernant ce comportement.

tl; dr Quelqu'un pourrait-il m'aider à disséquer cette commande?

1306
Doppelganger

Dans :w !Sudo tee %...

% signifie "le fichier actuel"

Comme eugene y a souligné , % signifie en effet "le nom du fichier actuel". Une autre utilisation de ceci dans Vim est dans les commandes de substitution. Par exemple, :%s/foo/bar signifie " dans le fichier actuel , remplacez les occurrences de foo par bar." Si vous mettez du texte en surbrillance avant de taper :s, vous verrez que les lignes en surbrillance remplacent % en tant que plage de substitution.

:w ne met pas à jour votre fichier

Une partie déroutante de cette astuce est que vous pourriez penser que :w modifie votre fichier, mais ce n’est pas le cas. Si vous ouvriez et modifiiez file1.txt, puis exécutiez :w file2.txt, ce serait un "enregistrer sous"; file1.txt ne serait pas modifié, mais le contenu actuel du tampon 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 un accès Sudo, son :w ne peut pas modifier un fichier protégé, mais s’il transmet le contenu du tampon au shell, une commande dans celui-ci peut être exécuté avec Sudo . Dans ce cas, nous utilisons tee.

Comprendre le tee

Comme pour tee, décrivez la commande tee comme un tuyau en forme de T dans une situation de tuyauterie normale: elle dirige la sortie vers le (s) fichier (s) spécifié (s) et envoie également sur la sortie standard , qui peut être capturée par la commande piped suivante.

Par exemple, dans ps -ax | tee processes.txt | grep 'foo', la liste des processus sera écrite dans un fichier texte et transmise à grep.

     +-----------+    tee     +------------+
     |           |  --------  |            |
     | ps -ax    |  --------  | grep 'foo' |
     |           |     ||     |            |
     +-----------+     ||     +------------+
                       ||   
               +---------------+
               |               |
               | processes.txt |
               |               |
               +---------------+

(Diagramme créé avec Asciiflow .)

Voir le tee page de manuel pour plus d’informations.

Tee comme un hack

Dans la situation décrite par votre question, utiliser tee est un bidouillage, car nous ignorons la moitié de ce qu’elle fait . Sudo tee écrit dans notre fichier et envoie également le contenu du tampon à la sortie standard, mais nous ignorons la sortie standard . Dans ce cas, il n'est pas nécessaire de transmettre quoi que ce soit à une autre commande canalisée. nous utilisons simplement tee comme autre moyen d'écrire un fichier et de pouvoir l'appeler avec Sudo.

Rendre cette astuce facile

Vous pouvez ajouter ceci à votre .vimrc pour rendre cette astuce facile à utiliser: il vous 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 partie > /dev/null explicitement jette la sortie standard, car, comme je l'ai dit, il n'est pas nécessaire de passer quoi que ce soit à une autre commande piped .

1485
Nathan Long

Dans la ligne de commande exécutée, _%_ représente le nom de fichier actuel . 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_ dirige le contenu du tampon actuel vers une autre commande. Ce que tee copie les entrées standard dans un ou plusieurs fichiers, ainsi que dans la sortie standard. Par conséquent, _:w !Sudo tee % > /dev/null_ écrit efficacement le contenu du tampon actuel dans le fichier actuel tout en étant root . Une autre commande pouvant être utilisée à cet effet est dd :

_:w !Sudo dd of=% > /dev/null
_

En tant que raccourci, vous pouvez ajouter ce mappage à 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 en tant que root.

93
Eugene Yarmash

Cela fonctionne aussi bien:

:w !Sudo sh -c "cat > %"

Ceci est inspiré par le commentaire de @Nathan Long.

NOTICE:

" doit être utilisé à la place de ' parce que nous voulons que % soit développé avant de passer à Shell.

18
feihu

:w - Écrivez un fichier.

!Sudo - Appelez la commande Shell Sudo.

tee - Le résultat de la commande write (vim: w) redirigée à l'aide de tee. Le% n'est rien d'autre que le nom de fichier actuel, à savoir /etc/Apache2/conf.d/mediawiki.conf. En d'autres termes, la commande tee est exécutée en tant que root. Elle utilise l'entrée standard et l'écrit dans un fichier représenté par%. Cependant, cela invitera à recharger à nouveau le fichier (appuyez sur L pour charger les modifications dans vim lui-même):

lien vers le tutoriel

16
kev

La réponse acceptée couvre tout, donc je vais simplement donner un autre exemple de raccourci que j'utilise, pour l'enregistrement.

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 ligne de commande.
  • w!!: le raccourci lui-même.
  • execute '...': une commande qui exécute la chaîne suivante.
  • silent!: l'exécuter en silence
  • 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 également la commande edit pour recharger le tampon et éviter les messages tels que le tampon a changé. <bar> est comment écrire le symbole pipe pour séparer deux commandes ici.

J'espère que ça aide. Voir aussi pour d'autres problèmes:

6
Dr Beco

Je voudrais suggérer une autre approche au "Oups, j'ai oublié d'écrire Sudo lors de l'ouverture de mon fichier" :

Au lieu de recevoir un permission denied et de devoir taper :w!!, je trouve plus élégant d'avoir une commande conditionnelle vim effectuant Sudo vim si le propriétaire du fichier est root.

C'est aussi facile à mettre en œuvre (il pourrait même y avoir des implémentations plus élégantes, je ne suis clairement pas un bash-guru):

function vim(){
  OWNER=$(stat -c '%U' $1)
  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’une vim- afin que tout le monde ne l’aime pas.

Bien sûr:

  • il y a des cas d'utilisation où cela va échouer (lorsque le propriétaire du fichier n'est pas root mais nécessite Sudo, mais la fonction peut être modifiée quand même)
  • cela n'a aucun sens d'utiliser vim pour la lecture d'un fichier uniquement (en ce qui me concerne, j'utilise tail ou cat pour les petits fichiers)

Mais je trouve que cela apporte beaucoup mieux expérience utilisateur dev, ce qui est quelque chose que l’on ne peut oublier à mon humble avis lorsque l’on utilise bash. :-)

4
Augustin Riedinger