Como @geekosaur explicou, o shell faz o redirecionamento antes de executar o comando. Quando você digita:
sudo foo >/some/file
Seu processo shell atual faz uma cópia de si mesmo que primeiro tenta abrir /some/file
para gravação, depois torna o descritor de arquivo sua saída padrão e só então é executado sudo
.
Se você tiver permissão (configurações de sudoer geralmente impedem a execução de shells), você pode fazer algo assim:
sudo bash -c 'foo >/some/file'
Mas acho que uma boa solução em geral é usar em | sudo tee
vez de >
e em | sudo tee -a
vez de >>
. Isso é especialmente útil se o redirecionamento for o único motivo de que preciso sudo
; afinal, a execução desnecessária de processos como root é exatamente o que sudo
foi criado para evitar. E executar echo
como root é simplesmente idiota.
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
Eu adicionei > /dev/null
no final, porque tee
envia sua saída para ambos o arquivo chamado e sua própria saída padrão, e eu não preciso vê-lo no meu terminal. (O tee
comando atua como um conector "T" em um pipeline físico, que é de onde vem seu nome.) E eu mudei para aspas simples ( '
... '
) em vez de duplas ( "
... "
) para que tudo seja literal e eu não precisou colocar uma barra invertida na frente do $
dentro $arch
. (Sem as aspas ou barra invertida, $arch
seria substituído pelo valor do parâmetro do shell arch
, que provavelmente não existe, caso em que o $arch
é substituído por nada e simplesmente desaparece.)
Então isso cuida de gravar arquivos como root usando sudo
. Agora, para uma longa digressão sobre as maneiras de produzir texto contendo nova linha em um script de shell. :)
Para BLUF, como eles dizem, minha solução preferida seria apenas alimentar um here-document no sudo tee
comando acima ; então não há necessidade de cat
ou echo
ou printf
ou quaisquer outros comandos. As aspas simples foram movidas para a introdução da sentinela <<'EOF'
, mas têm o mesmo efeito lá: o corpo é tratado como texto literal, portanto, $arch
é deixado sozinho:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch
EOF
Mas enquanto eu faria isso, existem alternativas. Aqui estão alguns:
Você pode ficar com um echo
por linha, mas agrupar todos eles em um subshell, então você só precisa anexar ao arquivo uma vez:
(echo '[archlinuxfr]'
echo 'Server = http://repo.archlinux.fr/$arch'
echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
Se você adicionar -e
ao echo
(e estiver usando um shell que suporte essa extensão não POSIX), poderá incorporar novas linhas diretamente na string usando \n
:
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
Mas, como dito acima, esse não é um comportamento especificado pelo POSIX; seu shell pode apenas ecoar um literal -e
seguido por uma string com um monte de literais \n
. A maneira POSIX de fazer isso é usar em printf
vez de echo
; ele trata automaticamente seu argumento como o echo -e
faz, mas não acrescenta automaticamente uma nova linha no final, então você também precisa colocar um extra \n
:
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' |
sudo tee -a /etc/pacman.conf >/dev/null
Com qualquer uma dessas soluções, o que o comando obtém como uma string de argumento contém a sequência de dois caracteres \n
, e cabe ao próprio programa de comando (o código dentro de printf
ou echo
) traduzir isso em uma nova linha. Em muitos shells modernos, você tem a opção de usar aspas ANSI $'
... '
, o que traduzirá as sequências \n
em novas linhas literais antes que o programa de comando veja a string. Isso significa que essas strings funcionam com qualquer comando, incluindo o plain old -e
-less echo
:
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
Mas, embora mais portáteis do que echo -e
, as aspas ANSI ainda são uma extensão não POSIX.
E, novamente, embora essas sejam todas opções, prefiro a tee <<EOF
solução direta acima.