¿Obtener permisos de root en un archivo dentro de vi? [cerrado]

245

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

sudo vi filename

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

Paul Wicks
fuente
tal vez solo guarde una copia en su directorio personal y "sudo mv" luego
paan

Respuestas:

296

% se reemplaza con el nombre del archivo actual, por lo que puede usar:

:w !sudo tee %

( vimdetectará que el archivo ha cambiado y le preguntará si desea que se vuelva a cargar. Diga sí eligiendo en [L]lugar de Aceptar).

Como acceso directo, 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 mejor manera (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 comando completa, dejando el cursor al final, para que pueda reemplazarlo %con un nombre de archivo propio, si lo desea.

beroe
fuente
55
¿Funciona esto en gvim? La ejecución del comando hace que Vim solicite la contraseña pero no acepte la entrada. Con el tiempo, el tiempo de espera en dos intentos y dice:sudo: 1 incorrect password attempt
cmcginty
no vería ninguna razón para que gvim se comporte de manera diferente ... ¿estás seguro de que sudo por sí solo funciona correctamente?
Si necesita privilegios de root para guardar un nuevo archivo, reemplace% con el nombre (incluida la ruta) del nuevo archivo.
gvkv
En algún momento, primero debe agregar su usuario al archivo sudoer, ingresar el usuario raíz y abrir el /etc/sudoersarchivo, agregar your_username ALL=(ALL) ALLdebajo de la línea root ALL=(ALL) ALL, salir y guardar.
refrescante
1
@coolesting: 1) hay otras mil cosas que debes hacer ... no podemos enumerarlas todas. 2) siempre debes usar visudo.
32

En general, no puede cambiar la identificación de usuario efectiva del proceso vi, pero puede hacer esto:

:w !sudo tee myfile
Mark Harrison
fuente
1
:w !sudo tee % >/dev/nullo :w !sudo dd of=%evite que el contenido del archivo se repita mientras se guarda el archivo.
jamessan
¿Puedes explicar cómo funciona esto? Miré hacia arriba teey vi que es un comando de tubería Unix, e !inserta un comando de shell. ¿La :wescritura es estándar, que se canaliza tee?
Eric Hu
44
@Eric, eso es correcto. el comando "tee myfile" copiará stdin a myfile. ejecutar "sudo tee myfile" hará lo mismo, pero dado que el proceso tee es propiedad de root, myfile también será propiedad de root. En el lado vi, ": w! Alguna línea de comando" canalizará todas las líneas a "alguna línea de comando".
Mark Harrison
16

Advertencias comunes

El método más común para solucionar el problema del archivo de solo lectura es abrir una canalización 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:

  • Todo el archivo se escribe en el terminal, así como el archivo. Esto puede ser lento para archivos grandes, especialmente en conexiones de red lentas.
  • El archivo pierde sus modos y atributos similares.
  • Las rutas de archivo con caracteres o espacios inusuales podrían no manejarse 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 se pueden acortar, 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. Debe omitirse en los scripts.

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

exec[ute]ejecuta una cadena como un comando. No podemos simplemente ejecutarlo :writeporque no procesará la llamada de función necesaria.

!representa el :!comando: el único comando que :writeacepta. Normalmente, :writeacepta una ruta de archivo en la que escribir. :!por sí solo ejecuta un comando en un shell (por ejemplo, usando bash -c). Con :write, ejecutará el comando en el shell y luego escribirá todo el archivo stdin.

sudodeberí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 eso.

teetuberías stdinal archivo dado. :writeescribirá en stdin, luego el superusuario teerecibirá el contenido del archivo y escribirá el archivo. No creará un nuevo archivo, simplemente sobrescribirá el contenido, de modo que se conservarán los modos y atributos del archivo.

shellescape()escapa caracteres especiales en la ruta de archivo dada según corresponda para el shell actual. Con solo un parámetro, normalmente solo encerraría la ruta entre comillas según sea necesario. Como estamos enviando a una línea de comando de shell completa, queremos pasar un valor distinto de cero como el segundo argumento para permitir el escape de barra invertida de otros caracteres especiales que de otro modo podrían disparar el shell.

@%lee el contenido del %registro, que contiene el nombre del archivo del búfer actual. No es necesariamente una ruta absoluta, así que asegúrese de no haber cambiado el directorio actual. En algunas soluciones, verá el símbolo comercial en 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.

>NULy >/dev/nullredirigir stdoutal dispositivo nulo de la plataforma. Aunque hemos silenciado el comando, no queremos que toda la sobrecarga asociada con la tubería stdinvuelva a vim, lo mejor es volcarlo lo antes posible. NULes el dispositivo nulo en DOS, MS-DOS y Windows, no es un archivo válido. A partir de las redirecciones de Windows 8 a NUL, no se genera 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 vale 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 ~/.vimrcarchivo, creándola 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, mucho más fácil.

Plataforma independiente

Utilizo un ~/.vimrcarchivo independiente de la plataforma que se sincroniza entre computadoras, así que agregué la funcionalidad multiplataforma a la mía. Aquí hay una ~/.vimrccon solo la configuración relevante:

#!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
fuente
¿Qué pasa si tropiezas con Windows al crear un archivo de escritura mundial en C: \ dev \ null?
Paul Stelian
1
@PaulStelian Posible, pero poco probable. Puede extender fácilmente este código para tener en cuenta una variedad de plataformas y circunstancias. En realidad, es poco probable que encuentre una situación en Windows donde sudoexista pero no /dev/null, por lo que necesitaría ser más sofisticado si quisiera un verdadero soporte multiplataforma. Es más una introducción: algo para pensar. :)
Zenexer
11

Si está utilizando Vim , hay un script disponible llamado sudo.vim . Si encuentra que ha abierto un archivo que necesita acceso raíz para leer, escriba

: e sudo:%
Vim reemplaza el% con el nombre del archivo actual e sudo:indica al script sudo.vim que se haga cargo de la lectura y escritura.

efímero
fuente
44
No recomendaría usar este script, ya que no toma las precauciones adecuadas con los nombres de archivo de escape.
jamessan
7

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 cambio, sudoeditel archivo correcto y leer en el contenido (utilizando :ro similar) del archivo temporal.

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

Chris Jester-Young
fuente
3

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

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

Si extraño eso, generalmente lo hago

:w ~/edited_blah.tmp
:q

..luego..

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

..o..

sudo mv edited_blah.tmp /etc/blah

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

dbr
fuente
cat $ tmp> $ target es creativo, pero ¿hay alguna razón para no simplemente sudo mv el archivo?
Ojrac
Buen punto ... También hubo un gran problema con sudo cat algo> / etc / blah - que usará sudo para capturar el archivo, luego el usuario normal para escribir en / etc / blah (que no funcionará). la respuesta, y agregó su mejor sugerencia de sudo mv ..
dbr
La sugerencia de mv no conserva los permisos.
Paul Stelian
1

Un rápido Google parece dar este consejo:

  1. No intente editar si es de solo lectura.
  2. Es posible que pueda cambiar los permisos en el archivo. (El hecho de que te permita ahorrar o no depende de la experimentación).
  3. Si aún así editó, guárdelo en un archivo temporal y luego muévalo.

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

Ryan Fox
fuente
0

Tengo esto en mi ~ / .bashrc:

alias svim='sudo vim'

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

meadas
fuente
2
Se sudoeditdebe preferir el comando ya que no requiere ejecutar vim como root.
jamessan
2
Esto todavía no te impide vincular vim en lugar de svim, que es a lo que el OP eludió.
ScaryAardvark
3
-1, esto solo dice "recuerda escribir sudo al abrir un archivo", el OP quiere saber cómo pueden obtener privilegios de root dentro de vi.
Brad Koch
-2

Un truco rápido que puede considerar es hacer un chmod en el archivo que está editando, guardar con vim y luego volver a chmod a lo que era originalmente el archivo.

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 le preocupa la seguridad, ya que durante unos segundos cualquiera puede leer / cambiar el archivo sin que se dé cuenta.

num1
fuente