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 continue
indicador similar que aparece después de ejecutar el :!
comando.
exec[ute]
ejecuta una cadena como un comando. No podemos simplemente ejecutarlo :write
porque no procesará la llamada de función necesaria.
!
representa el :!
comando: el único comando que :write
acepta. Normalmente, :write
acepta 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
.
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 eso.
tee
tuberías stdin
al archivo dado. :write
escribirá en stdin
, luego el superusuario tee
recibirá 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.
>NUL
y >/dev/null
redirigir stdout
al dispositivo nulo de la plataforma. Aunque hemos silenciado el comando, no queremos que toda la sobrecarga asociada con la tubería stdin
vuelva a vim, 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 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 ~/.vimrc
archivo, 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 ~/.vimrc
archivo independiente de la plataforma que se sincroniza entre computadoras, así que agregué la funcionalidad multiplataforma a la mía. Aquí hay una ~/.vimrc
con 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