Pourquoi sudo cat donne une permission refusée mais sudo vim fonctionne bien?

J’essaie d’automatiser l’ajout d’une source de référentiel dans le fichier pacman.conf de mon arch mais en utilisant la commande echo dans mon script shell. Cependant, cela échoue comme ceci: –

 sudo echo "[archlinuxfr]" >> /etc/pacman.conf sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf sudo echo " " >> /etc/pacman.conf -bash: /etc/pacman.conf: Permission denied 

Si je modifie manuellement /etc/pacman.conf en utilisant vim,

 sudo vim /etc/pacman.conf 

et quitter vim avec :wq , tout fonctionne bien et mon pacman.conf a été mis à jour manuellement sans plaintes “Permission denied”.

Pourquoi cela est-il ainsi? Et comment puis-je faire fonctionner sudo echo ? (d’ailleurs, j’ai aussi essayé d’utiliser sudo cat mais cela a échoué avec Permission denied aussi)

Le problème est que la redirection est en cours de traitement par votre shell d’origine, pas par sudo . Les obus ne sont pas capables de lire les esprits et ne savent pas que ce particulier >> est destiné au sudo et non à lui.

Tu dois:

  1. citer la redirection (elle est donc transmise à sudo)
  2. et utilisez sudo -s (afin que sudo utilise un shell pour traiter la redirection citée).

Comme @geekosaur l’a expliqué, le shell effectue la redirection avant d’exécuter la commande. Lorsque vous tapez ceci:

 sudo foo >/some/file 

Votre processus shell actuel effectue une copie de lui-même qui tente d’abord d’ouvrir /some/file pour l’écriture, puis rend ce descripteur de fichier standard et exécute ensuite sudo .

Si vous êtes autorisé (les sudoer configs empêchent souvent l’exécution de shells), vous pouvez faire quelque chose comme ceci:

 sudo bash -c 'foo >/some/file' 

Mais je trouve une bonne solution en général est d’utiliser | sudo tee | sudo tee au lieu de > et | sudo tee -a | sudo tee -a au lieu de >> . C’est particulièrement utile si la redirection est la seule raison pour laquelle j’ai besoin de sudo . après tout, exécuter des processus inutilement en tant que root est précisément ce que sudo été créé pour éviter. Et courir echo tant que root est tout simplement idiot.

 echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null 

J’ai ajouté > /dev/null à la fin car tee envoie sa sortie au fichier nommé et à sa propre sortie standard, et je n’ai pas besoin de le voir sur mon terminal. (La commande tee agit comme un connecteur “T” dans un pipeline physique, d’où son nom.) Et je suis passé à des guillemets simples ( '' ) au lieu de doubles ( "" ) pour que tout est littéral et je n’ai pas eu à mettre une barre oblique inverse devant le $ in $arch .

Donc, cela prend soin d’écrire dans les fichiers en tant que root en utilisant sudo . Maintenant, une longue digression sur les moyens de générer du texte contenant une nouvelle ligne dans un script shell. 🙂

Tout d’abord, vous pouvez simplement regrouper tous les echo dans un sous-shell, il vous suffit donc d’effectuer la redirection une seule fois:

 (echo '[archlinuxfr] echo 'Server = http://repo.archlinux.fr/$arch' echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null 

Ou utilisez printf au lieu de echo , de sorte que vous pouvez incorporer des newlines directement dans la chaîne en utilisant \n :

 printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

En bash , vous pouvez obtenir le même résultat avec echo -e :

 # BASH ONLY - NOT RECOMMENDED echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

Mais la plupart des shells vont simplement sortir le -e quand vous essayez cela, donc ce n’est pas recommandé.

Avec printf et echo -e , ce que la commande obtient en tant que chaîne d’argument contient une barre oblique inverse littérale suivie d’un littéral N chaque fois que vous tapez \n , et c’est au programme de commande lui-même (le code dans printf ou echo ) de le traduire. dans une nouvelle ligne. Dans de nombreux shells modernes, vous avez la possibilité d’utiliser des guillemets ANSI $'' , qui traduiront des séquences comme \n en lignes littérales avant que le programme de commandes ne voie la chaîne, ce qui signifie que ces chaînes fonctionnent avec n’importe quelle commande:

 echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

Mais, bien que plus portables que echo -e , les devis ANSI restnt une extension non POSIX.

Ma façon préférée de procéder serait d’utiliser un document ici et d’éviter tout besoin d’ echo ou de printf :

 sudo tee -a /etc/pacman.conf >/dev/null < <'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/$arch EOF 

http://www.innovationsts.com/blog/?p=2758

Comme les instructions ne sont pas claires ci-dessus, j’utilise les instructions de cet article. Avec des exemples, il est plus facile de voir ce que vous devez faire.

$ sudo cat /root/example.txt | gzip> /root/example.gz
-bash: /root/example.gz: autorisation refusée

Notez que c’est la deuxième commande (la commande gzip) dans le pipeline qui provoque l’erreur. C’est là qu’intervient notre technique d’utilisation de bash avec l’option -c

$ sudo bash -c ‘cat /root/example.txt | gzip> /root/example.gz ‘
$ sudo ls /root/example.gz
/root/example.gz

Nous pouvons voir la sortie de la commande ls que la création du fichier compressé a réussi.

La deuxième méthode est similaire à la première en ce sens que nous passons une chaîne de commande à bash, mais nous le faisons dans un pipeline via sudo.

$ sudo rm /root/example.gz
$ echo “cat /root/example.txt | gzip> /root/example.gz” | sudo bash
$ sudo ls /root/example.gz
/root/example.gz

 sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf' 

STEP 1 crée une fonction dans un fichier bash ( write_pacman.sh )

 #!/bin/bash function write_pacman { tee -a /etc/pacman.conf > /dev/null < < 'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/\$arch EOF } 

'EOF' n'interprétera pas la variable $arch .

STE2 source bash file

 $ source write_pacman.sh 

STEP 3 exécute la fonction

 $ write_pacman