Solución:
Como explicó @geekosaur, el shell realiza la redirección antes de ejecutar el comando. Cuando escribe esto:
sudo foo >/some/file
Su proceso de shell actual hace una copia de sí mismo que primero intenta abrir /some/file
para escribir, entonces, si tiene éxito, hace que el descriptor de archivo sea su salida estándar, y solo si tiene éxito, se ejecuta sudo
. Esto está fallando en el primer paso.
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 una buena solución en general es usar | sudo tee
en lugar de >
y | sudo tee -a
en lugar de >>
. Eso es especialmente útil si la redirección es la única razón por la que necesito sudo
en primer lugar; después de todo, ejecutar procesos innecesariamente como root es precisamente lo que sudo
fue creado para evitar. Y corriendo echo
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
yo añadí > /dev/null
al final porque tee
envía su salida a ambos el archivo nombrado y su propia salida estándar, y no necesito verla en mi terminal. (Los tee
El comando actúa como un conector “T” en una canalización 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 tuve que poner una barra invertida delante de la $
en $arch
. (Sin las comillas ni la barra invertida, $arch
sería reemplazado por el valor del parámetro de shell arch
, que probablemente no existe, en cuyo caso el $arch
es reemplazado 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 alimentar un documento aquí en el anterior sudo tee
mando; entonces no hay necesidad de cat
o echo
o printf
o cualquier otro comando. 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 queda 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:
Puedes quedarte con uno echo
por línea, pero agrúpelos todos juntos en una subcapa, por lo que solo tiene que agregarlos 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
al echo
(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/$archn ' |
sudo tee -a /etc/pacman.conf >/dev/null
Pero como dice arriba, ese no es un comportamiento especificado por POSIX; tu caparazón podría simplemente hacer eco de un literal -e
seguido de una cadena con un montón de literal n
s en su lugar. La forma POSIX de hacerlo es usar printf
en lugar de echo
; trata automáticamente su argumento como echo -e
lo hace, pero no agrega automáticamente una nueva línea al final, por lo que debe agregar un n
ahí también:
printf '[archlinuxfr]nServer = http://repo.archlinux.fr/$archn n' |
sudo tee -a /etc/pacman.conf >/dev/null
Con cualquiera de esas soluciones, lo que obtiene el comando como una cadena de argumentos contiene la secuencia de dos caracteres n
, y depende del programa de comando en sí (el código dentro printf
o echo
) para traducir eso en una nueva línea. En muchos shells modernos, tiene la opción de usar comillas ANSI $'
…'
, que traducirá secuencias como n
dentro literal nuevas líneas antes de que el programa de comando vea la cadena. Eso significa que tales cadenas funcionan con cualquier comando, incluido el antiguo -e
-menos echo
:
echo $'[archlinuxfr]nServer = http://repo.archlinux.fr/$archn ' |
sudo tee -a /etc/pacman.conf >/dev/null
Pero, aunque es más portátil que echo -e
, Las cotizaciones ANSI siguen siendo una extensión que no es POSIX.
Y de nuevo, si bien esas son todas las opciones, prefiero la recta tee <<EOF
solución anterior.
El problema es que la redirección está siendo procesada por su shell original, no por sudo
. Los caparazones no son capaces de leer la mente y no saben que ese particular >>
está destinado a la sudo
y no por eso.
Necesitas:
- cite la redirección (por lo que se pasa a
sudo)
-
y usar
sudo -s
(así que esosudo
usa un shell para procesar la redirección entre comillas).
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.
$ sudo cat /root/example.txt | gzip> /root/example.gz
-bash: /root/example.gz: Permiso denegado
Tenga en cuenta que es el segundo comando (el comando gzip) en la canalización el que causa el error. Ahí es donde entra nuestra técnica de usar bash con la opción -c.
$ sudo bash -c ‘cat /root/example.txt | gzip> /root/example.gz ‘
$ sudo ls /root/example.gz
/root/example.gz
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.
$ sudo rm /root/example.gz
$ echo “cat /root/example.txt | gzip> /root/example.gz” | sudo bash
$ sudo ls /root/example.gz
/root/example.gz