Estoy tratando de automatizar la adición de una fuente de repositorio en el archivo pacman.conf de mi arco, pero usando el echo
comando en mi script de shell. Sin embargo, falla así: -
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 realizo cambios en /etc/pacman.conf manualmente usando vim, haciendo
sudo vim /etc/pacman.conf
y salir de vim con :wq
, todo funciona bien y mi pacman.conf se ha actualizado manualmente sin quejas de "Permiso denegado".
¿Por qué esto es tan? ¿Y cómo llego sudo echo
al trabajo? (por cierto, intenté usar sudo cat
también pero falló con el permiso denegado también)
Respuestas:
El problema es que la redirección está siendo procesada por su shell original, no por
sudo
. Los shells no son capaces de leer la mente y no saben que ese particular>>
está destinado a élsudo
y no a él.Necesitas:
sudo)
sudo -s
(de modo quesudo
use un shell para procesar la redirección citada).fuente
sudo -s
(2) echo "# test" >> /etc/pacman.conf funciona. Pero, ¿es posible ejecutar esto en una sola línea?sudo -s 'echo "# test" >>/etc/pacman.conf'
es lo que estaba tratando de transmitirles.sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directory
por eso probé posteriormente el proceso manual de 2 pasos.echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
sudo
desactivación de la configuración-s
? visudo?Como explicó @geekosaur, el shell realiza la redirección antes de ejecutar el comando. Cuando escribe esto:
Su proceso de shell actual hace una copia de sí mismo que primero intenta abrirse
/some/file
para escritura, luego hace que ese descriptor de archivo sea su salida estándar y solo entonces se ejecutasudo
.Si está permitido (las configuraciones de sudoer a menudo impiden ejecutar shells), puede hacer algo como esto:
sudo bash -c 'foo >/some/file'
Pero encuentro que una buena solución en general es usar en
| sudo tee
lugar de>
y en| sudo tee -a
lugar de>>
. Eso es especialmente útil si la redirección es la única razón que necesitosudo
en primer lugar; después de todo, ejecutar procesos innecesariamente como root es precisamente lo quesudo
se creó para evitar. Y correrecho
como root es una tontería.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
Agregué
> /dev/null
al final porquetee
envía su salida tanto al archivo con nombre como a su propia salida estándar, y no necesito verlo en mi terminal. (Eltee
comando actúa como un conector "T" en una tubería física, que es de donde obtiene su nombre). Y cambié a comillas simples ('
...'
) en lugar de dobles ("
..."
) para que todo sea literal y no tener que poner una barra invertida delante de la$
en$arch
. (Sin las comillas o la barra invertida,$arch
sería reemplazado por el valor del parámetro de shellarch
, que probablemente no existe, en cuyo caso$arch
se reemplaza por nada y simplemente desaparece).Entonces eso se encarga de escribir en archivos como root usando
sudo
. Ahora, para una larga digresión sobre las formas de generar texto que contiene una nueva línea en un script de shell. :)Para BLUF, como dicen, mi solución preferida sería simplemente introducir un documento aquí en el
sudo tee
comando anterior ; entonces no hay necesidad decat
oecho
oprintf
o cualquier otro comando en absoluto. Las comillas simples se han trasladado a la introducción centinela<<'EOF'
, pero tienen el mismo efecto allí: el cuerpo se trata como texto literal, por lo que$arch
se deja solo:sudo tee -a /etc/pacman.conf >/dev/null <<'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/$arch EOF
Pero aunque así es como lo haría, hay alternativas. A continuación, presentamos algunos:
Puede quedarse con uno
echo
por línea, pero agruparlos todos en una subcapa, por lo que solo tiene que agregar al archivo una vez:(echo '[archlinuxfr]' echo 'Server = http://repo.archlinux.fr/$arch' echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
Si agrega
-e
aecho
(y está usando un shell que admite esa extensión que no es POSIX), puede incrustar nuevas líneas directamente en la cadena usando\n
:# NON-POSIX - NOT RECOMMENDED echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
Pero como dice arriba, ese no es un comportamiento especificado por POSIX; su shell podría simplemente repetir un literal
-e
seguido de una cadena con un montón de literales en\n
su lugar. La forma POSIX de hacerlo es usar enprintf
lugar deecho
; trata automáticamente su argumento como loecho -e
hace, pero no agrega automáticamente una nueva línea al final, por lo que también debe agregar un extra\n
allí:printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | sudo tee -a /etc/pacman.conf >/dev/null
Con cualquiera de esas soluciones, lo que el comando obtiene como una cadena de argumento contiene la secuencia de dos caracteres
\n
, y depende del programa de comando en sí (el código dentro deprintf
oecho
) traducir eso en una nueva línea. En muchos shells modernos, tiene la opción de usar comillas ANSI$'
...'
, que traducirán secuencias como\n
en líneas nuevas literales antes de que el programa de comando vea la cadena. Eso significa que este tipo de cadenas funcionan con cualquier comando que sea, incluyendo a secas-e
-menosecho
:echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
Pero, aunque son más portátiles que
echo -e
, las citas ANSI siguen siendo una extensión que no es POSIX.Y nuevamente, si bien esas son todas las opciones, prefiero la
tee <<EOF
solución directa anterior.fuente
sudo bash -c 'foo >/some/file'
funciona para mí en osx :-)cat <<EOF | sudo tee -a /some/file > /dev/null ...
cat
proceso extraño . :)http://www.innovationsts.com/blog/?p=2758
Como las instrucciones no son tan claras arriba, estoy usando las instrucciones de esa publicación de blog. Con ejemplos para que sea más fácil ver lo que necesita hacer.
Observe que es el segundo comando (el comando gzip) en la canalización el que causa el error. Ahí es donde entra en juego nuestra técnica de usar bash con la opción -c.
Podemos ver en la salida del comando ls que la creación del archivo comprimido tuvo éxito.
El segundo método es similar al primero en que le estamos pasando una cadena de comando a bash, pero lo estamos haciendo en una canalización a través de sudo.
fuente
sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
fuente
PASO 1 crea una función en un archivo 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'
no interpretará la$arch
variable.Archivo bash fuente STE2
$ source write_pacman.sh
PASO 3 ejecutar la función
fuente
añadir archivos (sudo cat):
añadir eco al archivo (sudo echo):
echo <origin> | sudo tee -a <target-file>
(EXTRA) ignore la salida:
echo >origin> | sudo tee -a <target-file> >/dev/null
fuente