ti-enxame.com

Como eu uso o Sudo para redirecionar a saída para um local para o qual não tenho permissão para gravar?

Recebi o acesso do Sudo em uma das nossas caixas de desenvolvimento do RedHat, e parece que muitas vezes preciso redirecionar a saída para um local em que normalmente não tenho acesso de gravação.

O problema é que esse exemplo inventado não funciona:

Sudo ls -hal /root/ > /root/test.out

Acabei de receber a resposta:

-bash: /root/test.out: Permission denied

Como posso fazer isso funcionar?

760
Jonathan

Seu comando não funciona porque o redirecionamento é executado pelo seu Shell, que não tem permissão para gravar em /root/test.out. O redirecionamento da saída não é executado pelo Sudo.

Existem várias soluções:

  • Execute um Shell com Sudo e forneça o comando usando a opção -c:

    Sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Crie um script com seus comandos e execute esse script com o Sudo:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Execute Sudo ls.sh. Veja resposta de Steve Bennett se você não quiser criar um arquivo temporário.

  • Inicie um Shell com Sudo -s e execute seus comandos:

    [[email protected]]$ Sudo -s
    [[email protected]]# ls -hal /root/ > /root/test.out
    [[email protected]]# ^D
    [[email protected]]$
    
  • Use Sudo tee (se você tiver que escapar muito quando usar a opção -c):

    Sudo ls -hal /root/ | Sudo tee /root/test.out > /dev/null
    

    O redirecionamento para /dev/null é necessário para impedir que tee seja exibido na tela. Para append ao invés de sobrescrever o arquivo de saída (>>), use tee -a ou tee --append (o último é específico para GNU coreutils ).

Obrigado por ir para Jd , Adam J. Forster e Johnathan para a segunda, terceira e quarta soluções.

1068
Cristian Ciupitu

Alguém aqui acabou de sugerir sudoing tee:

Sudo ls -hal /root/ | Sudo tee /root/test.out > /dev/null

Isso também pode ser usado para redirecionar qualquer comando para um diretório ao qual você não tem acesso. Ele funciona porque o programa tee é efetivamente um programa "echo to a file", e o redirecionamento para/dev/null é para pará-lo também na tela para mantê-lo igual ao exemplo original inventado acima.

89
Jonathan

Um truque que eu descobri foi

Sudo ls -hal /root/ | Sudo dd of=/root/test.out
70
rhlee

O problema é que o command é executado sob Sudo, mas o redirection é executado sob seu usuário. Isso é feito pela Shell e há muito pouco que você possa fazer sobre isso.

Sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

As formas usuais de contornar isso são:

  • Enrole os comandos em um script que você chama em Sudo.

    Se os comandos e/ou arquivo de log forem alterados, você pode fazer com que o script Os use como argumentos. Por exemplo:

    Sudo log_script command /log/file.txt
    
  • Chame um Shell e passe a linha de comando como um parâmetro com -c

    Isso é especialmente útil para um dos comandos compostos off. Por exemplo:

    Sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    
41
dsm

Ainda outra variação sobre o tema:

Sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Ou claro:

echo 'ls -hal /root/ > /root/test.out' | Sudo bash

Eles têm a vantagem (minúscula) de que você não precisa se lembrar de nenhum argumento para Sudo ou sh/bash

19
Steve Bennett

Esclarecendo um pouco porque a opção tee é preferível

Supondo que você tenha a permissão apropriada para executar o comando que cria a saída, se você canalizar a saída do seu comando para tee, você só precisará elevar os privilégios do tee com Sudo e tee direto para escrever (ou anexar) ao arquivo em questão.

no exemplo dado na pergunta que significaria:

ls -hal /root/ | Sudo tee /root/test.out

para mais alguns exemplos práticos:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | Sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | Sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

Em cada um desses exemplos, você está obtendo a saída de um comando não privilegiado e gravando em um arquivo que geralmente só pode ser gravado por root, que é a Origem da sua pergunta.

É uma boa ideia fazê-lo desta forma porque o comando que gera a saída não é executado com privilégios elevados. Não parece importar aqui com echo, mas quando o comando source é um script no qual você não confia completamente, é crucial.

Observe que você pode usar a opção -a para tee para anexar o acréscimo (como >>) ao arquivo de destino em vez de substituí-lo (como >).

18
jg3

Faça o Sudo rodar um Shell, assim:

Sudo sh -c "echo foo > ~root/out"
15
Penfold

A maneira que eu iria sobre este assunto é:

Se você precisar gravar/substituir o arquivo:

echo "some text" | Sudo tee /path/to/file

Se você precisar anexar ao arquivo:

echo "some text" | Sudo tee -a /path/to/file
8
Nikola Petkanski

Que tal escrever um roteiro?

Nome do arquivo: myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Em seguida, use o Sudo para executar o script:

Sudo ./myscript
5
Jd

Eu faria assim:

Sudo su -c 'ls -hal /root/ > /root/test.out'
4
fardjad

Sempre que eu tenho que fazer algo assim eu acabei de me tornar root:

# Sudo -s
# ls -hal /root/ > /root/test.out
# exit

Provavelmente não é o melhor caminho, mas funciona.

3
Adam J. Forster

Não quero bater um cavalo morto, mas há muitas respostas aqui que usam tee, o que significa que você tem que redirecionar stdout para /dev/null a menos que queira ver uma cópia na tela. Uma solução mais simples é apenas usar cat assim:

Sudo ls -hal /root/ | Sudo bash -c "cat > /root/test.out"

Observe como o redirecionamento é colocado dentro de aspas para que seja avaliado por um Shell iniciado por Sudo em vez de o ser executado.

3
haridsv

Isso é baseado na resposta envolvendo tee. Para facilitar as coisas, escrevi um pequeno script (chamo de suwrite) e o coloquei em /usr/local/bin/ com a permissão +x:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "[email protected]" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
Sudo tee "[email protected]" > /dev/null

Como mostrado noUSAGEno código, tudo o que você precisa fazer é canalizar a saída para este script seguido pelo nome de arquivo acessível ao superusuário desejado e solicitará automaticamente sua senha, se necessário (já que inclui Sudo).

echo test | suwrite /root/test.txt

Observe que, como esse é um wrapper simples para tee, ele também aceita a opção -a de tee para anexar e também suporta a gravação em vários arquivos ao mesmo tempo.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

Ele também tem alguma proteção simplista contra a gravação em dispositivos /dev/, que foi uma preocupação mencionada em um dos comentários nesta página.

2
jamadagni

Talvez você tenha recebido acesso do Sudo a apenas alguns programas/caminhos? Então não há como fazer o que você quer. (a menos que você vá hackear de alguma forma)

Se não for o caso, então talvez você possa escrever um script bash:

cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out 

Pressione ctrl + d :

chmod a+x myscript.sh
Sudo myscript.sh

Espero que ajude.

1
user15453
Sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  
0
user8648126