Estou tentando automatizar a adição de uma fonte de repositório no arquivo pacman.conf do meu arch, mas usando o echo
comando em meu script de shell. No entanto, ele falha assim: -
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
Se eu fizer alterações em /etc/pacman.conf manualmente usando o vim,
sudo vim /etc/pacman.conf
e sair do vim com :wq
, tudo funciona bem e meu pacman.conf foi atualizado manualmente sem reclamações de "permissão negada".
Porque isto é assim? E como faço sudo echo
para trabalhar? (aliás, eu tentei usar sudo cat
também, mas falhou com permissão negada também)
Respostas:
O problema é que o redirecionamento está sendo processado pelo shell original, não pelo
sudo
. As conchas não são capazes de ler mentes e não sabem que esse particular>>
se destina a elesudo
e não a ele.Você precisa:
sudo)
sudo -s
(para quesudo
use um shell para processar o redirecionamento entre aspas.)fonte
sudo -s
(2) echo "# test" >> /etc/pacman.conf funciona. Mas é possível fazer isso em uma única linha?sudo -s 'echo "# test" >>/etc/pacman.conf'
é o que eu estava tentando transmitir a você.sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directory
por isso tentei posteriormente o processo manual de 2 etapas.echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
sudo
desativação da configuração-s
? visudo?Como @geekosaur explicou, o shell faz o redirecionamento antes de executar o comando. Quando você digita:
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 é executadosudo
.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 precisosudo
; afinal, a execução desnecessária de processos como root é exatamente o quesudo
foi criado para evitar. E executarecho
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, porquetee
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. (Otee
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 shellarch
, 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 decat
ouecho
ouprintf
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
aoecho
(e estiver usando um shell que suporte essa extensão não POSIX), poderá incorporar novas linhas diretamente na string usando\n
:# NON-POSIX - NOT RECOMMENDED 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 emprintf
vez deecho
; ele trata automaticamente seu argumento como oecho -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 deprintf
ouecho
) 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
-lessecho
: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.fonte
sudo bash -c 'foo >/some/file'
funciona para mim no osx :-)cat <<EOF | sudo tee -a /some/file > /dev/null ...
cat
processo estranho . :)http://www.innovationsts.com/blog/?p=2758
Como as instruções acima não são tão claras, estou usando as instruções dessa postagem do blog. Com exemplos, fica mais fácil ver o que você precisa fazer.
Observe que é o segundo comando (o comando gzip) no pipeline que causa o erro. É aí que entra a nossa técnica de usar o bash com a opção -c.
Podemos ver na saída do comando ls que a criação do arquivo compactado foi bem-sucedida.
O segundo método é semelhante ao primeiro no sentido de que estamos passando uma string de comando para o bash, mas estamos fazendo isso em um pipeline via sudo.
fonte
sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
fonte
PASSO 1 criar uma função em um arquivo 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ão interpretará$arch
variável.Arquivo bash de origem STE2
$ source write_pacman.sh
PASSO 3 execute a função
fonte
anexar arquivos (sudo cat):
anexar echo ao arquivo (sudo echo):
echo <origin> | sudo tee -a <target-file>
(EXTRA) desconsiderar a saída:
echo >origin> | sudo tee -a <target-file> >/dev/null
fonte