Vim: guardar como superusuario usando sudo y tee

Publicado por Diego Córdoba en

Reactivando el blog! Hoy una entrada respondiendo consultas de alumnos de mis cursos. Veremos cómo se puede guardar con vim y tee un archivo con privilegios restringidos, y hacerlo desde una instancia de vim corriendo como usuario común con la ayuda de sudo y tee.

¿Cuántas veces hemos editado un archivo en línea de comandos usando vim, y luego de realizar las modificaciones, nos damos cuenta que no tenemos privilegios de escritura para guardarlo? Este mensaje será conocido para varios (el formato depende de los plugins que tengas instalados):

 error readonly

A mi me ha ocurrido un montón de veces, por suerte, cuando son modificaciones pequeñas uno cierra el editor, lo abre nuevamente usando sudo, y vuelve a editar.

Ahora, cuando editamos pasamos varios minutos editando un archivo y luego no podemos guardarlo, lo primero que nos viene a la mente es: «lo guardo en /tmp y luego muevo los cambios a la posición original con sudo«.

Hay soluciones más elegantes 🙂

El comando tee al rescate

Un comando quizás poco utilizado y entendido es tee, sin embargo es una herramienta muy útil, especialmente en tareas como la que comentamos hoy.

El comando tee tiene por objetivo leer desde la entrada estándar y escribir lo que lee directamente en la salida estándar y, de manera opcional, en uno o varios archivos simultáneamente.

Veamos un ejemplo: supongamos que necesitamos ejecutar un comando cualquiera que escriba algo en pantalla… como el comando date, que imprime la fecha y la hora actuales.

Supongamos ahora que deseamos ejecutar un comando que guarde la fecha y la hora en un archivo, por ejemplo, /tmp/fecha.txt. Podríamos hacer esta redirección de salida:

$ date > /tmp/fecha.txt

Ahora bien, si además necesitamos mostrar ese dato por pantalla, una solución un tanto poco elegante podría ser:

$ date > /tmp/fecha.txt && cat /tmp/fecha.txt

El primer comando, date, escribe su salida en el archivo /tmp/fecha.txt mediante una redirección de salida, y si todo sale correcto, el comando cat lee el contenido de dicho archivo y lo muestra por pantalla.

Una solución más elegante podría ser la siguiente:

$ date | tee /tmp/fecha.txt

Aquí se ejecuta el comando date, y su salida es enviada, mediante un pipe o tubería de línea de comandos, al comando tee, que lo muestra por pantalla y además lo guarda en el archivo /tmp/fecha.txt.

Vim: guardar con sudo y tee

Podemos aprovecharnos del comportamiento de tee, combinarlo con sudo, y lograr que Vim almacene su contenido con privilegios de superusuario, sin ser un proceso de superusuario en sí.

Si estamos editando, por ejemplo, el archivo /etc/fstab, y abrimos vim como usuario común, el comando :w no podrá almacenar los cambios porque el proceso vim no tiene privilegios suficientes.

El comando :w sirve para guardar el contenido en el archivo. Se puede pasar por argumento un nombre de archivo si es que se prefiere almacenar una copia en otra ubicación o con otro nombre. Este comando brinda otras posibilidades… veamos un fragmento del comando :help :w dentro de Vim:

vim guardar sudo tee help :w

Esto significa que podemos ejecutar cosas como :w !cmd, de modo que el comando de guardar le pasará como entrada estándar el contenido de todo el archivo (o un rango del mismo) al comando cmd.

Este comando a su vez puede ejecutarse con privilegios de superusuario, es decir, se puede invocar a sudo para su lanzamiento:

:w !sudo cmd

Esta ejecución estará enviando el contenido completo del archivo (se omitió el rango de líneas) como entrada estándar a sudo cmd.

A su vez, sabemos que en Vim el símbolo % en un comando hace referencia al nombre del archivo actual… veamos si es cierto. Por ejemplo, si estamos editando el archivo /tmp/archivo.txt, cuyo contenido es «hola mundo«, al hacer esto:

:w ! echo %

Estaremos mostrando por pantalla (salida estándar) el nombre del archivo actual:

 echo

Mientras que si hacemos esto:

:w ! cat %

Estaremos leyendo el contenido del archivo:

cat

Al grano de una vez…

Ahora bien, si estamos editando un archivo restringido sin haber lanzado al editor vim con sudo, podríamos guardar de la siguiente manera:

:w ! sudo tee %

Este comando enviará el contenido del archivo como entrada a sudo tee, que corre convenientemente con privilegios de root. El comando tee enviará su contenido a la salida estándar, y también lo enviará al archivo actual, y como corre bajo sudo, podrá almacenar el contenido sin problemas.

Al ejecutar este comando se guardará el contenido, y el editor nos preguntará si deseamos cargar la nueva versión del archivo, dado que nuestra instancia de vim no fue, realmente, quien lo guardó en disco. No tenemos mas que dar Enter, o L para cargar el archivo modificado.

El siguiente gif muestra el proceso completo (no pide la password del sudo de usuario porque en mi /etc/sudoers ese usuario no requiere password)

vim guardar sudo tee gif

En el caso de que el usuario tenga password para sudo, la solicitará como paso intermedio, tal y como se ve en este gif:

Conclusión

Esta es una de las formas que existen para salir del paso y poder guardar el contenido modificado de un archivo cuando se abrió el editor sin ser usuario root.

Pueden haber otras formas de hacerlo. Esta me resulta muy práctica, y fácil implementar y recordar. Si conocés otras formas de hacerlo, o estás acostumbrad@ a guardar como root de otra manera, sos bienvenid@ a comentar el artículo! Seguro a más de uno de los visitantes del blog se servirá.

Finalmente, si quieren aprender más sobre Vim, les recuerdo que tengo publicado un curso completo y práctico del editor, al que pueden acceder desde nuestra sección de cursos con las promociones vigentes! Los espero!!

Como siempre, espero les sea de utilidad, y desde ya quedo a disposición en la caja de comentarios o en nuestras redes sociales y grupo en Telegram!

Hasta la próxima!

Fuentes:

¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!

Categorías: Aplicaciones

Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador