Obtener permisos de root en un archivo dentro de vi?


A menudo mientras edito archivos de configuración, abriré uno con vi y luego cuando vaya a guardarlo me doy cuenta de que no escribí

sudo vi filename

¿Hay alguna forma de dar privilegios a vi sudo para guardar el archivo? Parece que recuerdo haber visto algo sobre esto mientras buscaba algunas cosas sobre vi hace un tiempo, pero ahora no puedo encontrarlo.

 231
Author: Paul Wicks, 2008-08-04

11 answers

% se sustituye por el nombre del archivo actual, por lo que puede utilizar:

:w !sudo tee %

(vim se detecta que el archivo ha sido cambiado y le preguntará si desea ser recargado.)

Como atajo, puede definir su propio comando. Ponga lo siguiente en su .vimrc:

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

Con lo anterior puede escribir :W<Enter> para guardar el archivo. Desde que escribí esto, he encontrado una manera más agradable (en mi opinión) de hacer esto:

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

De esta manera puede escribir :w!! y se expandirá a la línea de comandos completa, dejando el cursor al final, para que pueda reemplazar el % con un nombre de archivo propio, si lo desea.

 279
Author: Lai Jiangshan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-14 09:15:27

En general, no puede cambiar el id de usuario efectivo del proceso vi, pero puede hacer esto:

:w !sudo tee myfile
 30
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-04 06:52:32

Advertencias comunes

El método más común para evitar el problema del archivo de solo lectura es abrir una tubería al archivo actual como superusuario utilizando una implementación de sudo tee. Sin embargo, todas las soluciones más populares que he encontrado en Internet tienen una combinación de varias advertencias potenciales:

  • El archivo completo se escribe en la terminal, así como el archivo. Esto puede ser lento para archivos grandes, especialmente en redes lentas relación.
  • El archivo pierde sus modos y atributos similares.
  • Es posible que las rutas de archivo con caracteres o espacios inusuales no se manejen correctamente.

Soluciones

Para solucionar todos estos problemas, puede usar el siguiente 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'

Estos pueden ser acortados, respetuosamente:

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

Explicación

: comienza el comando; necesitará escribir este carácter en modo normal para comenzar a ingresar un comando. Debería ser omitido en scripts.

sil[ent] suprime la salida del comando. En este caso, queremos detener el prompt similar a Press any key to continue que aparece después de ejecutar el comando :!.

exec[ute] ejecuta una cadena como un comando. No podemos simplemente ejecutar :write porque no procesará la llamada a la función necesaria.

! representa el comando :!: el único comando que :write acepta. Normalmente, :write acepta una ruta de archivo a la que escribir. :! por su cuenta ejecuta un comando en un shell (para ejemplo, usando bash -c). Con :write, ejecutará el comando en el shell, y luego escribirá el archivo completo en stdin.

sudo debería ser obvio, ya que es por eso que estás aquí. Ejecute el comando como superusuario. Hay mucha información en la red sobre cómo funciona.

tee canaliza stdin al archivo dado. :write escribirá a stdin, luego el superusuario tee recibirá el contenido del archivo y lo escribirá. No creará un nuevo archivo just simplemente sobrescribir se conservarán los modos y atributos del archivo contents so so.

shellescape() escapa caracteres especiales en la ruta de archivo dada según corresponda para el shell actual. Con un solo parámetro, normalmente encerraría la ruta entre comillas según sea necesario. Dado que estamos enviando a una línea de comandos de shell completa, desearemos pasar un valor distinto de cero como segundo argumento para habilitar el escape de barra invertida de otros caracteres especiales que de otra manera podrían hacer tropezar el shell.

@% lee el contenido del registro %, que contiene el nombre de archivo del búfer actual. No es necesariamente una ruta absoluta, así que asegúrese de que no ha cambiado el directorio actual. En algunas soluciones, verá el símbolo comercial-at omitido. Dependiendo de la ubicación, % es una expresión válida, y tiene el mismo efecto que leer el registro %. Sin embargo, anidado dentro de otra expresión, el acceso directo generalmente no está permitido: como en este caso.

>NUL y >/dev/null redireccionar stdout al dispositivo nulo de la plataforma. A pesar de que hemos silenciado el comando, no queremos que toda la sobrecarga asociada con la tubería stdin vuelva a vim best lo mejor es volcarlo lo antes posible. NUL es el dispositivo nulo en DOS, MS-DOS y Windows, no es un archivo válido. A partir de Windows 8, las redirecciones a NUL no dan lugar a que se escriba un archivo llamado NUL. Intente crear un archivo en su escritorio llamado NUL, con o sin una extensión de archivo: no podrá hacerlo. (Hay varios otros nombres de dispositivos en Windows que podrían valer la pena conocer.)

~/.vimrc

Dependiente de la Plataforma

Por supuesto, todavía no quieres memorizarlos y escribirlos cada vez. Es mucho más fácil asignar el comando apropiado a un comando de usuario más simple. Para hacer esto en POSIX, puede agregar la siguiente línea a su archivo ~/.vimrc, creándolo si aún no existe:

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

Esto le permitirá escribir el comando :W (distingue entre mayúsculas y minúsculas) para escribir el archivo actual con permisos de superusuario much mucho más fácil.

Independiente de la plataforma

Uso un archivo ~/.vimrc independiente de la plataforma que se sincroniza entre computadoras, por lo que agregué la funcionalidad multiplataforma a la mía. Aquí hay un ~/.vimrc con solo los ajustes 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
 14
Author: Zenexer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-13 06:54:18

Si estás usando Vim, hay un script disponible llamado sudo.vim . Si encuentra que ha abierto un archivo que necesita acceso root para leer, escriba

:e sudo:%
Vim reemplaza el % con el nombre del archivo actual, y sudo: indica el sudo.vim script para hacerse cargo de la lectura y la escritura.
 10
Author: ephemient,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-20 07:22:36

El consejo de Ryan es generalmente bueno, sin embargo, si sigue el paso 3, no mueva el archivo temporal; tendrá la propiedad y los permisos incorrectos. En su lugar, sudoedit el archivo correcto y leído en el contenido (usando :r o similar) del archivo temporal.

Si sigue el paso 2, use :w! para forzar la escritura del archivo.

 7
Author: Chris Jester-Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-04 04:04:52

Cuando entra en modo de inserción en un archivo que necesita acceso sudo para editar, obtiene un mensaje de estado que dice

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

Si echo de menos eso, generalmente lo hago

:w ~/edited_blah.tmp
:q

..entonces..

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

..o..

sudo mv edited_blah.tmp /etc/blah

Probablemente hay una forma menos indirecta de hacerlo, pero funciona.

 3
Author: dbr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-15 06:49:03

Un Google rápido parece dar este consejo:

  1. No intentes editar si es de solo lectura.
  2. Es posible que pueda cambiar los permisos del archivo. (Si te permitirá ahorrar o no depende de la experimentación.)
  3. Si todavía editó de todos modos, guarde en un archivo temporal y luego muévalo.

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

 1
Author: Ryan Fox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-04 03:39:31

Aquí hay otro que ha aparecido desde que se respondió a esta pregunta, un complemento llamado SudoEdit que proporciona las funciones SudoRead y SudoWrite, que por defecto intentarán usar sudo primero y su si eso falla: http://www.vim.org/scripts/script.php?script_id=2709

 1
Author: James Snyder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-29 17:21:29

Tengo esto en mi ~/.bashrc:

alias svim='sudo vim'

Ahora, cada vez que necesito editar un archivo de configuración, simplemente lo abro con svim.

 0
Author: pisswillis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-19 12:51:48

Un truco rápido que puede considerar es hacer un chmod en el archivo que está editando, guardar con vim, y luego chmod volver a lo que el archivo era 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)

Por supuesto, no recomiendo este enfoque en un sistema donde está preocupado por la seguridad, ya que durante unos segundos cualquiera puede leer/cambiar el archivo sin que se dé cuenta.

 -2
Author: num1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-05 22:20:58

Uso gksudo en lugar de sudo para GVim es decir,

cmap w!! w !gksudo tee >/dev/null %
 -7
Author: ryfm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-30 06:33:11