Obtendo permissões de root em um arquivo dentro do vi? [fechadas]

245

Frequentemente, ao editar os arquivos de configuração, vou abrir um com o vi e, quando for salvá-lo, percebo que não digitei

sudo vi filename

Existe alguma maneira de dar privilégios ao vi sudo para salvar o arquivo? Eu me lembro de ter visto algo sobre isso enquanto procurava algumas coisas sobre o vi há um tempo atrás, mas agora não consigo encontrá-lo.

Paul Wicks
fonte
talvez apenas salvar uma cópia em seu diretório home e "sudo mv"-lo mais tarde
paan

Respostas:

296

% é substituído pelo nome do arquivo atual, portanto, você pode usar:

:w !sudo tee %

( vimdetectará que o arquivo foi alterado e perguntará se você deseja que ele seja recarregado. Diga sim escolhendo em [L]vez de OK.)

Como atalho, você pode definir seu próprio comando. Coloque o seguinte em seu .vimrc:

command W w !sudo tee % >/dev/null

Com o exposto acima, você pode digitar :W<Enter>para salvar o arquivo. Desde que escrevi isso, achei uma maneira melhor (na minha opinião) de fazer isso:

cmap w!! w !sudo tee >/dev/null %

Dessa forma, você pode digitar :w!!e será expandido para a linha de comando completa, deixando o cursor no final, para que você possa substituí-lo %por um nome de arquivo próprio, se desejar.

beroe
fonte
5
Isso funciona no gvim? A execução do comando faz com que o Vim solicite a senha, mas não aceite a entrada. Ele eventualmente expira em duas tentativas e diz:sudo: 1 incorrect password attempt
cmcginty
eu não veria nenhuma razão para o gvim se comportar de maneira diferente ... você tem certeza que o sudo por si só funciona corretamente?
Se você precisar de privilégios de root para salvar um novo arquivo, substitua% pelo nome (incluindo o caminho) do novo arquivo.
precisa saber é o seguinte
Em algum momento, você precisa adicionar seu usuário ao arquivo sudoer primeiro, inserir o usuário raiz e abrir o /etc/sudoersarquivo, adicionar your_username ALL=(ALL) ALLabaixo da linha root ALL=(ALL) ALL, sair e salvar.
coolesting 25/10/11
1
@coolesting: 1) existem milhares de outras coisas que você precisa fazer ... não podemos listar todas. 2) você deve sempre usar visudo.
32

Em geral, você não pode alterar o ID do usuário efetivo do processo vi, mas pode fazer isso:

:w !sudo tee myfile
Mark Harrison
fonte
1
:w !sudo tee % >/dev/nullou :w !sudo dd of=%evite que o conteúdo do arquivo seja repetido à medida que o arquivo é salvo.
jamessan
Você pode explicar como isso funciona? Olhei para cima teee vi que era um comando de canal Unix e !insere um comando de shell. A :wescrita está padronizada tee?
Eric Hu
4
@ Eric, isso mesmo. o comando "tee myfile" copiará stdin para myfile. executar "sudo tee myfile" fará o mesmo, mas como o processo tee é de propriedade do root, o myfile também será de propriedade do root. No lado do vi, ": w! Alguma linha de comando" canalizará todas as linhas para "alguma linha de comando".
Mark-Harrison-
16

Advertências comuns

O método mais comum de solucionar o problema do arquivo somente leitura é abrir um canal no arquivo atual como superusuário usando uma implementação de sudo tee. No entanto, todas as soluções mais populares que eu encontrei na Internet têm uma combinação de várias advertências em potencial:

  • O arquivo inteiro é gravado no terminal, assim como o arquivo. Isso pode ser lento para arquivos grandes, especialmente em conexões de rede lentas.
  • O arquivo perde seus modos e atributos semelhantes.
  • Os caminhos de arquivo com caracteres ou espaços incomuns podem não ser manipulados corretamente.

Soluções

Para contornar todos esses problemas, você pode usar o seguinte comando:

" On POSIX (Linux/Mac/BSD):
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'

" Depending on the implementation, you might need this on Windows:
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >NUL'

Estes podem ser reduzidos, respeitosamente:

:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'

Explicação

:inicia o comando; você precisará digitar esse caractere no modo normal para começar a digitar um comando. Deve ser omitido nos scripts.

sil[ent]suprime a saída do comando. Nesse caso, queremos parar o Press any key to continueprompt -like que aparece após a execução do :!comando.

exec[ute]executa uma string como um comando. Não podemos simplesmente executar, :writeporque não processará a chamada de função necessária.

!representa o :!comando: o único comando que :writeaceita. Normalmente, :writeaceita um caminho de arquivo no qual gravar. :!por si só executa um comando em um shell (por exemplo, usando bash -c). Com :write, ele executará o comando no shell e gravará o arquivo inteiro em stdin.

sudodeve ser óbvio, já que é por isso que você está aqui. Execute o comando como superusuário. Há muita informação na rede sobre como isso funciona.

teecanaliza stdinpara o arquivo especificado. :writegravará em stdin, o superusuário teereceberá o conteúdo do arquivo e o gravará. Ele não criará um novo arquivo - apenas substitua o conteúdo - para que os modos e atributos do arquivo sejam preservados.

shellescape()escapa caracteres especiais no caminho do arquivo, conforme apropriado para o shell atual. Com apenas um parâmetro, normalmente apenas coloque o caminho entre aspas, conforme necessário. Como estamos enviando para uma linha de comando do shell completa, queremos passar um valor diferente de zero como o segundo argumento para permitir a fuga de barra invertida de outros caracteres especiais que, de outra forma, poderiam desarmar o shell.

@%lê o conteúdo do %registro, que contém o nome do arquivo do buffer atual. Não é necessariamente um caminho absoluto, portanto, verifique se você não alterou o diretório atual. Em algumas soluções, você verá o símbolo comercial em omitido. Dependendo da localização, %é uma expressão válida e tem o mesmo efeito que a leitura do% registro. Aninhado dentro de outra expressão, o atalho geralmente não é permitido: como neste caso.

>NULe >/dev/nullredirecione stdoutpara o dispositivo nulo da plataforma. Mesmo que tenhamos silenciado o comando, não queremos que toda a sobrecarga associada ao canal de stdinvolta ao vim - o melhor seja despejá-lo o mais cedo possível. NULé o dispositivo nulo no DOS, MS-DOS e Windows, não um arquivo válido. No Windows 8, os redirecionamentos para NUL não resultam na gravação de um arquivo chamado NUL. Tente criar um arquivo na área de trabalho chamado NUL, com ou sem uma extensão de arquivo: você não poderá fazer isso. (Existem vários outros nomes de dispositivos no Windows que valem a pena conhecer.)

~ / .vimrc

Dependente da plataforma

Obviamente, você ainda não deseja memorizá-las e digitá-las sempre. É muito mais fácil mapear o comando apropriado para um comando de usuário mais simples. Para fazer isso no POSIX, você pode adicionar a seguinte linha ao seu ~/.vimrcarquivo, criando-a se ela ainda não existir:

command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'

Isso permitirá que você digite o comando: W (diferencia maiúsculas de minúsculas) para gravar o arquivo atual com permissões de superusuário - muito mais fácil.

Plataforma independente

Eu uso um ~/.vimrcarquivo independente de plataforma que sincroniza entre computadores, então adicionei a funcionalidade de várias plataformas à minha. Aqui está um ~/.vimrccom apenas as configurações relevantes:

#!vim
" Use za (not a command; the keys) in normal mode to toggle a fold.
" META_COMMENT Modeline Definition: {{{1
" vim: ts=4 sw=4 sr sts=4 fdm=marker ff=unix fenc=utf-8
"   ts:     Actual tab character stops.
"   sw:     Indentation commands shift by this much.
"   sr:     Round existing indentation when using shift commands.
"   sts:    Virtual tab stops while using tab key.
"   fdm:    Folds are manually defined in file syntax.
"   ff:     Line endings should always be <NL> (line feed #09).
"   fenc:   Should always be UTF-8; #! must be first bytes, so no BOM.


" General Commands: User Ex commands. {{{1
    command W call WriteAsSuperUser(@%)         " Write file as super-user.


" Helper Functions: Used by user Ex commands. {{{1
    function GetNullDevice() " Gets the path to the null device. {{{2
        if filewritable('/dev/null')
            return '/dev/null'
        else
            return 'NUL'
        endif
    endfunction

    function WriteAsSuperUser(file) " Write buffer to a:file as the super user (on POSIX, root). {{{2
        exec '%write !sudo tee ' . shellescape(a:file, 1) . ' >' . GetNullDevice()
    endfunction


" }}}1
" EOF
Zenexer
fonte
E se você tropeçar no Windows criando um arquivo gravável mundial em C: \ dev \ null?
Paul Stelian
1
@PaulStelian Possível, mas improvável. Você pode facilmente estender esse código para explicar uma variedade de plataformas e circunstâncias. Na realidade, é improvável que você encontre uma situação no Windows em que sudoexista, mas não exista /dev/null; portanto, você precisará ficar mais sofisticado se quiser um verdadeiro suporte entre plataformas. É mais uma introdução - alimento para o pensamento. :)
Zenexer
11

Se você estiver usando o Vim , existe um script disponível chamado sudo.vim . Se você achar que abriu um arquivo que precisa de acesso root para ler, digite

: e sudo:%
O Vim substitui o% pelo nome do arquivo atual e sudo:instrui o script sudo.vim a assumir a leitura e gravação.

efémero
fonte
4
Eu não recomendaria o uso desse script, pois ele não toma as devidas precauções com nomes de arquivos que escapam.
jamessan
7

O conselho de Ryan geralmente é bom; no entanto, se seguir a etapa 3, não mova o arquivo temporário; terá a propriedade e as permissões incorretas. Em vez disso, sudoedito arquivo correto e leia o conteúdo (usando :rou semelhante) do arquivo temporário.

Se seguir a etapa 2, use :w!para forçar a gravação do arquivo.

Chris Jester-Young
fonte
3

Quando você entra no modo de inserção em um arquivo que precisa de acesso sudo para editar, você recebe uma mensagem de status dizendo

-- INSERT -- W10: Warning: Changing a readonly file

Se sinto falta disso, geralmente sinto

:w ~/edited_blah.tmp
:q

..então..

sudo "cat edited_blah.tmp > /etc/blah"

..ou..

sudo mv edited_blah.tmp /etc/blah

Provavelmente existe uma maneira menos indireta de fazê-lo, mas funciona.

dbr
fonte
cat $ tmp> $ target é criativo, mas existe algum motivo para não apenas sudo mv o arquivo?
ojrac
Bom ponto .. Também houve um grande problema com algo do sudo cat> / etc / blah - que usará o sudo para criar o arquivo do gato e, em seguida, o usuário comum gravará no / etc / blah (que não funcionará). a resposta, e acrescentou o seu melhor sugestão sudo mv ..
DBR
A sugestão mv não preserva permissões.
Paul Stelian
1

Um rápido Google parece dar este conselho:

  1. Não tente editar se for somente leitura.
  2. Você pode alterar as permissões no arquivo. (A opção de salvar ou não depende de experimentação.)
  3. Se você ainda editou mesmo assim, salve em um arquivo temporário e mova-o.

http://ubuntuforums.org/showthread.php?t=782136

Ryan Fox
fonte
1

Aqui está outro que apareceu desde que essa pergunta foi respondida, um plug-in chamado SudoEdit que fornece as funções SudoRead e SudoWrite, que por padrão tentam usar o sudo primeiro e su se isso falhar: http://www.vim.org/scripts/ script.php? script_id = 2709

James Snyder
fonte
0

Eu tenho isso no meu ~ / .bashrc:

alias svim='sudo vim'

Agora, sempre que preciso editar um arquivo de configuração, basta abri-lo com o svim.

pisswillis
fonte
2
O sudoeditcomando deve ser preferido, pois não requer a execução do vim como root.
jamessan
2
Isso ainda não impede que você amarre o vim em vez do svim, que é o que o OP evitou.
ScaryAardvark
3
-1, apenas dizendo "lembre-se de digitar sudo ao abrir um arquivo", o OP quer saber como eles podem obter privilégios de root dentro do vi.
Brad Koch
-2

Um hack rápido que você pode considerar é fazer um chmod no arquivo que você está editando, salvar com o vim e depois voltar ao que o arquivo estava originalmente.

ls -l test.file (to see the permissions of the file)
chmod 777 test.file
[This is where you save in vim]
chmod xxx test.file (restore the permissions you found in the first step)

É claro que eu não recomendo essa abordagem em um sistema em que você está preocupado com a segurança, pois por alguns segundos alguém pode ler / alterar o arquivo sem que você perceba.

num1
fonte