Por exemplo, se eu quiser criar um arquivo e inserir texto em uma linha, posso redirecionar a saída para um arquivo usando o >
operador:
echo "something" > /path/foobar
mas se eu não tiver acesso à pasta /path/
e precisar de privilégios de sudo, como posso obter esse mesmo comando que um usuário normal com direitos de sudo?
tentei
sudo echo "something" > /path/foobar
mas isso não funciona, porque o sudo só conta para a parte certa, edit
mas não para a parte
direita>
Claro, eu poderia me tornar root antes sudo su
ou usar tee
:
echo "something" | sudo tee /path/foobar
Mas gostaria de encontrar uma solução onde eu pudesse trabalhar com a última linha como substituição via
sudo !!
Não existe uma maneira de "reciclar" a última linha e apenas adicionar sudo
na frente?
Responder1
Você não pode simplesmente ficar sudo
na frente de um comando shell, você precisa 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, com caracteres especiais e tudo. Você precisa recuperar o texto do comando como uma string e passá-lo como argumento para sh
. Felizmente, o bashfc
construídas empermite que você faça isso¹.
sudo bash -c "$(fc -ln -1)"
Ou ainda, para ter certeza de invocar a mesma versão do bash que está em execução no momento:
sudo "$BASH" -c "$(fc -ln -1)"
Observe que, como o comando é executado em um processo de shell separado, ele herda variáveis de ambiente (apenas aquelas que sudo
preservam), mas não variáveis internas do shell. As opções de shell (por exemplo kshglob
, ) e outras configurações também começarão a partir do padrão.
O mesmo comando² funciona em zsh e ksh, embora ATT ksh93 exija que o número first
e last
seja passado para fc
³ (que também funciona em 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 foi invocado através do $PATH e o $PATH não foi alterado, ou através 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 advertência: sudo
destina-se a comandos potencialmente perigosos. Não torne muito fácil usá-lo!
¹ Há alguns espaços em branco extras no início e a substituição do comando remove novas linhas no final, mas a sintaxe do shell não se importa com isso.
² Não acho que zsh ou ksh tenham algo parecido com o bash $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.
³ é um apelido para ATT ksh, mas é igualmente bom. fc
hist
Responder2
Se você quiser refazer o mesmo comando comsudo!!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-aparâmetro.
Isto é o equivalente asudo!!mas ajuda a ignorar as restrições do 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 a entrada padrão e grave na saída e nos arquivos padrão
Se você quiser repetir o comando e acrescentar um texto ao arquivo, o comando tee tem o-aopção para anexar. Então você pode lembrar o comando com
sudo !!
e o texto será anexado ao arquivo
exemplo:
echo "something" | sudo tee -a /path/file
sudo !!
Responder3
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