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 abrirse /some/file
para escritura, luego hace que ese descriptor de archivo sea su salida estándar y solo entonces se ejecuta sudo
.
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 necesito sudo
en primer lugar; después de todo, ejecutar procesos innecesariamente como root es precisamente lo que sudo
se creó para evitar. Y correr 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
Agregué > /dev/null
al final porque tee
envía su salida tanto al archivo con nombre como a su propia salida estándar, y no necesito verlo en mi terminal. (El tee
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 shell arch
, 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 de cat
o echo
o printf
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
a 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
:
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 en printf
lugar de echo
; trata automáticamente su argumento como lo echo -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 de printf
o echo
) 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
-menos echo
:
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.