Execute uma linha de comandos com um sudo

21

Por exemplo, se eu quiser criar um arquivo e inserir texto em uma linha, posso redirecionar a saída para um arquivo com o uso do operador > :

echo "something" > /path/foobar

mas se eu não tiver acesso à pasta /path/ e precisar de privilégios de sudo, como posso conseguir esse mesmo comando como um usuário normal com direitos de sudo?

Eu tentei

sudo echo "something" > /path/foobar

mas isso não funciona, porque o sudo só conta para o edit , mas não para a parte certa | do >

Claro, eu poderia me tornar root antes com sudo su ou usar tee :

echo "something" | sudo tee /path/foobar

Mas eu gostaria de encontrar uma solução onde eu possa trabalhar com a última linha como substituto via

sudo !!

Não existe uma maneira de "reciclar" a última linha e apenas adicionar sudo na frente?

    
por rubo77 20.06.2014 / 15:50

3 respostas

12

Você não pode simplesmente colocar sudo na frente de um comando shell, você tem que invocar um shell para avaliar esse comando novamente (fazendo coisas como expandir variáveis, abrir arquivos para operadores de redirecionamento, etc.). Então é isso

sudo bash -c !!

exceto que isso não funciona, porque !! interpola o texto do comando anterior, caracteres especiais e todos. Você precisa recuperar o texto do comando como uma string e passar isso como um argumento para sh . Felizmente, o fc builtin do bash permite que você faça isso.

sudo bash -c "$(fc -ln -1)"

Ou mesmo, para invocar a mesma versão do bash atualmente em execução:

sudo "$BASH" -c "$(fc -ln -1)"

Observe que, como o comando é executado em um processo de shell separado, ele herda as variáveis de ambiente (apenas as que sudo preserva, importa), mas não as variáveis internas do shell. As opções de shell (por exemplo, kshglob ) e outras configurações serão iniciadas a partir do padrão.

O mesmo comando² funciona em zsh e ksh, embora o ATT ksh93 requeira que os números first e last sejam passados para fc ³ (que também funciona no bash, zsh e pdksh / mksh):

sudo zsh -c "$(fc -ln -1)"
sudo ksh -c "$(fc -ln -1 -1)"
sudo "$0" -c "$(fc -ln -1 -1)"

Usar $0 para designar o executável do shell em execução funciona apenas se o shell tiver sido invocado por meio do $ PATH e se o $ PATH não tiver sido alterado ou por meio de um caminho absoluto.

Aqui está outro método em zsh que é um pouco mais claro, mas mais longo:

sudo zsh -c $history[$[HISTCMD-1]]

Uma última palavra de aviso: sudo é para comandos potencialmente perigosos. Não seja muito fácil usá-lo!

¹ Há um espaço em branco extra no início e a substituição do comando retira as novas linhas no final, mas a sintaxe do shell não se importa com isso.
² Eu não acho que zsh ou ksh tenham algo como $BASH do bash; $0 só funciona quando é um caminho absoluto ou quando não contém nenhuma barra e o caminho de pesquisa do comando não foi alterado.
³ fc é um alias para hist em ATT ksh, mas isso é bom.

    
por 20.06.2014 / 23:06
9

Se você quiser refazer o mesmo comando com sudo !! depois de fazer um comando como este:

echo "something">/path/file

Você usa a sintaxe de substituição global para recuperar o comando:

!!:gs/>/|sudo tee -a /

Use um espaço após o parâmetro -a .

Isto é o equivalente a sudo !! , mas ajuda-o a ultrapassar as restrições de sudo para o < e > Porque o sudo não permite que você use [& lt ;, >].

Para ignorar restrições de sudo em geral para redirecionamentos, você pode usá-lo assim:

echo "something" | sudo tee myfile

O comando tee permitirá que você leia a entrada padrão e grave na saída e nos arquivos padrão

Se você quiser repetir o comando e anexar um texto ao arquivo, o comando tee terá a opção -a para anexar. Então você pode lembrar o comando com

sudo !!

e o texto será anexado no arquivo

exemplo:

echo "something" | sudo tee -a /path/file
sudo !!
    
por 20.06.2014 / 15:56
3

Parece ser tão simples quanto sudo sh -c "!!" :

$ cd /
$ echo hello > foo
bash: foo: Permission denied
$ sudo sh -c "!!"
sudo sh -c "echo hello > foo"
$ ls -l foo
-rw-r--r-- 1 root root 6 Jun 20 16:21 foo
    
por 20.06.2014 / 17:22