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 tenho acesso à pasta /path/e preciso de privilégios sudo, como posso obter esse mesmo comando que um usuário normal com direitos sudo?

eu tentei

sudo echo "something" > /path/foobar

mas isso não funciona, porque o sudo conta apenas editpara a parte correta
do>

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

echo "something" | sudo tee /path/foobar

Mas gostaria de encontrar uma solução em que possa trabalhar com a última linha como substituição via

sudo !!

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

rubo77
fonte
Isto não é uma duplicata. Eu extraí o Qeustion real e mudei o título. Agora é que eu realmente estou procurando
rubo77
Certamente era uma duplicata, mas agora é um pouco diferente. Parece-me que você reescreveu a pergunta à luz da resposta de Boogy, o que é bom - essa é uma boa resposta. Eu retirei meu voto próximo, mas ainda é inevitável (as pessoas geralmente votam automaticamente quando uma pergunta está na fila fechada sem prestar atenção ao problema): envie um comentário para @goldilocks quando ele for fechado e votarei para reabrir . Você também pode defender seu caso no chat assim que isso acontecer.
Goldilocks
Veja também Como posso alias sudo !!?
Gilles 'SO- stop be evil'

Respostas:

13

Você não pode simplesmente ficar sudona frente de um comando do shell; é necessário 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 muito bem, porque !!interpola o texto do comando anterior, caracteres especiais e tudo. Você precisa recuperar o texto do comando como uma sequência e passar isso como argumento para sh. Felizmente, da festa fcembutido permite que você faça that¹.

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

Ou ainda, para ter certeza de 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 variáveis ​​de ambiente (somente as que sudopreservam, lembre-se), mas não as variáveis ​​internas do shell. As opções de shell (por exemplo kshglob) e outras configurações também serão iniciadas a partir do padrão.

O mesmo comando² funciona em zsh e ksh, embora o ATT ksh93 exija que o número firste o lastnúmero 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 $0para designar o executável do shell em execução funcionará apenas se o shell tiver sido chamado por meio do $ PATH e o $ PATH não tiver sido alterado ou por um caminho absoluto.

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

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

Uma palavra final de aviso: sudoé para comandos potencialmente perigosos. Não facilite muito o uso!

¹ Há algum espaço em branco extra no começo e a substituição do comando retira novas linhas no final, mas a sintaxe do shell não se importa com isso.
² Não acho que zsh ou ksh tenham algo como o bash $BASH; $0só funciona quando é um caminho absoluto ou quando não contém barra e o caminho de busca do comando não foi alterado.
³ é um apelido para no ATT ksh, mas é tão bom quanto. fchist

Gilles 'SO- parar de ser mau'
fonte
9

Se você deseja refazer o mesmo comando com o sudo !! depois de executar 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 .

Isso é equivalente a sudo !! mas ajuda a ignorar as restrições de sudo para <e>. Porque o sudo não permite que você use [<,>].


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

echo "something" | sudo tee myfile

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

Se você deseja repetir o comando e anexar um texto ao arquivo, o comando tee possui a opção -a para anexar. Então você pode se lembrar do comando com

sudo !!

e o texto será anexado ao arquivo

exemplo:

echo "something" | sudo tee -a /path/file
sudo !!
Boogy
fonte
solução agradável, mas um pouco difícil de memorizar. Como posso criar um alias para um comando usando !! lembrar o último comando ?
rubo77
é -arealmente necessário? >irá substituir um arquivo, tee -airá acrescentar, o que seria>>
rubo77
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
deltab
fonte
3
Se o comando usou aspas, isso não é necessariamente equivalente. Considere o echo "foo bar"que seria o sh -c "echo "foo bar""que seria impresso em foovez de foo bar.
godlygeek
Tentei sudo sh -c '!!'vez se o seu comando, mas que não quer trabalhar
rubo77
Então, e se o seu comando usasse aspas simples e duplas? Ou aspas duplas e expansões variáveis? Se o usuário o fizesse: a=be então echo "$a" >filee, em seguida sudo sh -c '!!', expandiria para o sudo sh -c 'echo $a >file'qual imprimiria uma linha vazia em vez de bpara file.
godlygeek
Então, talvez exista uma solução ainda melhor?
rubo77
1
Eu não acho que exista uma solução que funcione 100% do tempo sem que você precise modificar o comando. Usar sudopara obter um shell raiz e, em seguida, copiar e colar o comando nele seria o mais próximo, mas falha se se espera que o comando use variáveis ​​definidas no seu shell não raiz. O uso sudo sh -c "!!"funciona bem para comandos simples, mas é complicado para comandos complexos. Penso que o melhor conselho é não esperar que exista algum comando que funcione 100% do tempo - aprenda algumas soluções possíveis e aplique cada uma delas quando for mais adequado.
godlygeek