Muitos de vocês provavelmente já viram o comando que permite gravar em um arquivo que precisa de permissão root, mesmo quando você esqueceu de abrir o vim com o sudo:
:w !sudo tee %
O problema é que eu não entendo exatamente o que está acontecendo aqui.
Eu já percebi isso:
w
é para isso
*:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
Execute {cmd} with [range] lines as standard input
(note the space in front of the '!'). {cmd} is
executed like with ":!{cmd}", any '!' is replaced with
the previous command |:!|.
então passa todas as linhas como entrada padrão.
A !sudo tee
parte chama tee
com privilégios de administrador.
Para que todos façam sentido, o %
deve exibir o nome do arquivo (como parâmetro para tee
), mas não consigo encontrar referências na ajuda para esse comportamento.
tl; dr Alguém poderia me ajudar a dissecar esse comando?
:w !sudo cat > %
Não funcionaria tão bem e não poluiria a saída padrão?sudo
é aplicado acat
, mas não a>
, portanto, não é permitido. Você pode tentar executar o comando inteiro em um subshell sudo, como:w !sudo sh -c "cat % > yams.txt"
, mas isso também não funcionará, porque no subshell,%
é nulo; você esvaziará o conteúdo do seu arquivo.:w !sudo sh -c "cat >%"
realmente funciona tão bem quantosudo tee %
porque o Vim substitui o nome do arquivo%
antes que ele chegue ao subshell. No entanto, nenhum deles funcionará se o nome do arquivo tiver espaços; você tem que fazer:w !sudo sh -c "cat >'%'"
ou:w !sudo tee "%"
consertar isso.Respostas:
Em
:w !sudo tee %
...%
significa "o arquivo atual"Como apontado por eugene ,
%
na verdade significa "o nome do arquivo atual", que é passado paratee
que ele saiba qual arquivo substituir.(Nos comandos de substituição, é um pouco diferente; como
:help :%
mostra, éequal to 1,$ (the entire file)
(obrigado a @Orafu por apontar que isso não é avaliado pelo nome do arquivo). Por exemplo,:%s/foo/bar
significa " no arquivo atual , substitua as ocorrênciasfoo
porbar
". Se você destacar algum texto antes de digitar:s
, você verá que as linhas destacadas%
substituem seu intervalo de substituição.):w
não está atualizando seu arquivoUma parte confusa desse truque é que você pode pensar que
:w
está modificando seu arquivo, mas não está. Se você abriu e modificoufile1.txt
, em seguida, executou:w file2.txt
, seria um "salvar como";file1.txt
não seria modificado, mas o conteúdo atual do buffer seria enviado parafile2.txt
.Em vez de
file2.txt
, você pode substituir um comando do shell para receber o conteúdo do buffer . Por exemplo,:w !cat
apenas exibirá o conteúdo.Se o Vim não foi executado com acesso ao sudo, ele
:w
não pode modificar um arquivo protegido, mas se ele passar o conteúdo do buffer para o shell, um comando no shell poderá ser executado com o sudo . Neste caso, usamostee
.T compreensivo
Quanto a
tee
, imagine otee
comando como um tubo em forma de T em uma situação de tubulação bash normal: ele direciona a saída para o (s) arquivo (s) especificado (s) e também o envia para a saída padrão , que pode ser capturada pelo próximo comando de tubulação.Por exemplo, em
ps -ax | tee processes.txt | grep 'foo'
, a lista de processos será gravada em um arquivo de texto e repassada paragrep
.(Diagrama criado com o Asciiflow .)
Veja a
tee
página de manual para mais informações.Tee como um hack
Na situação que sua pergunta descreve, o uso
tee
é um truque, porque estamos ignorando metade do que ele faz .sudo tee
grava em nosso arquivo e também envia o conteúdo do buffer para a saída padrão, mas ignoramos a saída padrão . Não precisamos passar nada para outro comando canalizado neste caso; estamos apenas usandotee
como uma maneira alternativa de escrever um arquivo e para que possamos chamá-lo comsudo
.Tornando este truque fácil
Você pode adicionar isso ao seu
.vimrc
para tornar esse truque fácil de usar: basta digitar:w!!
.A
> /dev/null
parte joga explicitamente fora a saída padrão, pois, como eu disse, não precisamos passar nada para outro comando canalizado.fonte
tee
sua capacidade de gravar stdin em um arquivo. Estou surpreso que não exista um programa cujo trabalho seja fazer isso (encontrei um programa que nunca ouvi falarsponge
que faz isso). Eu acho que o típico "gravar um fluxo em um arquivo" é executado por um shell interno. O Vim!{cmd}
não bifurca uma concha (bifurcandocmd
)? Talvez algo mais óbvio seja usar alguma variante de trabalho emsh -c ">"
vez detee
.sponge
faz parte domoreutils
pacote em praticamente todas as distribuições, exceto nas distros baseadas no Debian.moreutils
tem algumas ferramentas bastante agradáveis que estão a par de ferramentas mais comuns comoxargs
etee
.cat
é executado como root e a saída é redirecionada pelo shell, que não é executado como root. É o mesmo queecho hi > /read/only/file
.Na linha de comando executada,
%
representa o nome do arquivo atual . Isso está documentado em:help cmdline-special
:Como você já descobriu,
:w !cmd
canaliza o conteúdo do buffer atual para outro comando. O quetee
faz é copiar a entrada padrão para um ou mais arquivos e também para a saída padrão. Portanto,:w !sudo tee % > /dev/null
efetivamente grava o conteúdo do buffer atual no arquivo atual enquanto é root . Outro comando que pode ser usado para isso édd
:Como atalho, você pode adicionar esse mapeamento ao seu
.vimrc
:Com o exposto acima, você pode digitar
:w!!<Enter>
para salvar o arquivo como root.fonte
:help _%
mostra o que você digitou, mas:help %
mostra a chave de correspondência de chaves. Eu não teria pensado em tentar o prefixo de sublinhado, isso é algum tipo de padrão na documentação do vim? Existem outras coisas "especiais" para tentar ao procurar ajuda?help
comando salta para uma tag. Você pode ver as tags disponíveis com:h help-tags
. Você também pode usar a conclusão de linha de comando para ver as tags correspondentes::h cmdline<Ctrl-D>
(ou:h cmdline<Tab>
se você definirwildmode
em conformidade)cmap w!! w !sudo tee % > /dev/null
no meu arquivo .vimrc para fazer isso funcionar. O%
extraviado está na resposta acima? (Nenhum especialista vim aqui.)sudo tee > /dev/null /path/to/current/file
qual realmente não faz sentido. (Indo para editar isso)Isso também funciona bem:
Isso é inspirado no comentário de @Nathan Long.
AVISO :
"
deve ser usado em vez de'
porque queremos%
ser expandidos antes de passar para o shell.fonte
tee
por/usr/bin/tee
para impedir ataques de modificação de PATH.:w
- Escreva um arquivo.!sudo
- Chame o comando shell sudo.tee
- A saída do comando write (vim: w) redirecionada usando tee. O% não passa de um nome de arquivo atual, ou seja, /etc/apache2/conf.d/mediawiki.conf. Em outras palavras, o comando tee é executado como root e recebe a entrada padrão e a grava em um arquivo representado por%. No entanto, isso solicitará o recarregamento do arquivo novamente (pressione L para carregar as alterações no próprio vim):link do tutorial
fonte
A resposta aceita cobre tudo, então vou dar outro exemplo de atalho que eu uso, para o registro.
Adicione-o ao seu
etc/vim/vimrc
(ou~/.vimrc
):cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!
Onde:
cnoremap
: informa ao vim que o seguinte atalho deve ser associado na linha de comando.w!!
: o próprio atalho.execute '...'
: um comando que executa a seguinte sequência.silent!
: execute silenciosamentewrite !sudo tee % >/dev/null
: a pergunta OP, adicionou um redirecionamento de mensagensNULL
para fazer um comando limpo<bar> edit!
: esse truque é a cereja do bolo: ele também chama oedit
comando para recarregar o buffer e evitar mensagens como a alteração do buffer .<bar>
é como escrever o símbolo de barra vertical para separar dois comandos aqui.Espero que ajude. Veja também para outros problemas:
fonte
Gostaria de sugerir outra abordagem para "Oups que esqueci de escrever
sudo
ao abrir meu arquivo" :Em vez de receber um
permission denied
e ter que digitar:w!!
, acho mais elegante ter umvim
comando condicional quesudo vim
se o proprietário do arquivo forroot
.Isso é tão fácil de implementar (pode haver implementações ainda mais elegantes, eu claramente não sou um guru do bash):
E funciona muito bem.
Essa é uma
bash
abordagem mais centrada do que umavim
para que nem todos gostem.Claro:
root
mas exigirsudo
, mas a função pode ser editada de qualquer maneira)vim
somente um arquivo para leitura (no que me diz respeito, usotail
oucat
para arquivos pequenos)Mas acho que isso traz uma experiência muito melhor para o desenvolvedor , que é algo que o IMHO tende a ser esquecido ao usar
bash
. :-)fonte
root
a senha é consultada.PARA NEOVIM
Devido a problemas com chamadas interativas ( https://github.com/neovim/neovim/issues/1716 ), estou usando isso para o neovim, com base na resposta do Dr. Beco:
Isso abrirá uma caixa de diálogo usando
ssh-askpass
a senha do sudo.fonte