vi en Linux — práctica con un ifcfg de verdad: activar la tarjeta, limpiar el archivo y mudarlo de red (sin tocar el ratón)

La segunda semana de redes ya sabía salir de vi, pero tardaba cinco minutos en cada cambio: flecha, flecha, flecha, borrar letra a letra, escribir… Un compañero me vio y me dijo: «¿por qué no haces cw?». Cambié una palabra entera con dos teclas y me di cuenta de que había estado usando vi como si fuera el bloc de notas. La lección: en vi no se edita letra a letra, se edita con órdenes que dicen qué cambiar y hasta dónde.

Esta práctica aplica lo de la teoría de vi a tres situaciones del laboratorio, todas sobre el archivo de configuración de una tarjeta de red, ifcfg-enp2s0: dejarlo listo para que la tarjeta arranque sola, limpiar un archivo lleno de restos y mudar la estación a otra red. Los tres son de nivel medio y usan archivos parecidos a los de verdad: con líneas repetidas, comentarios viejos y valores que hay que cambiar en varios sitios a la vez.

Antes de empezar

Conviene tener claro:

  • Los tres modos y que Esc te devuelve siempre al normal.
  • Los movimientos básicos (j, $, G, 5G, /texto, n).
  • La gramática operador + movimiento (dd, 3dd, cw, yy, p).
  • La diferencia entre :wq y :q!.

Si alguno te suena dudoso, repasa la teoría antes de seguir.

En este artículo, «el código» de cada programa son las teclas que pulsas dentro de vi, con un comentario que explica el porqué. <Esc> es Escape y <CR> es Enter. Practica siempre sobre una copia (cp ifcfg-enp2s0 prueba): así un error no te deja sin red.

Programa 1: activar la tarjeta al arrancar

La estación del laboratorio tiene este ifcfg-enp2s0. Tiene dos problemas: BOOTPROTO=dhcp (pide la IP a un servidor DHCP, pero en el lab la IP se pone a mano) y ONBOOT=no (la tarjeta no se activa al arrancar). Además falta la línea NETWORK con la dirección de la red.

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=dhcp
     3	ONBOOT=no
     4	IPADDR=192.168.2.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=192.168.2.1

La idea

Tres cambios, cada uno con la herramienta justa:

  1. Saltar a dhcp con una búsqueda y cambiar la palabra entera con cw.
  2. Saltar al =no con otra búsqueda, avanzar un carácter y cambiar no por yes.
  3. Ir a la última línea y abrir una nueva debajo con o.

Nada de flechas: las búsquedas te dejan el cursor exactamente donde quieres, aunque el archivo tenga cien líneas.

Antes de programar, piensa en dónde caerá el cursor. /=no deja el cursor sobre el =, no sobre la n: por eso hace falta la l antes del cw.

El código

/dhcp<CR>      # el cursor salta a la d de dhcp
cwnone<Esc>    # dirección fija: sin DHCP
/=no<CR>       # el cursor cae en el = de ONBOOT=no
lcwyes<Esc>    # un paso a la derecha y cambia no por yes
GoNETWORK=192.168.2.0<Esc>   # abre una línea al final y escribe la red
:wq<CR>        # guarda y sale

Fíjate en el zoom de la parte más delicada, la segunda búsqueda:

/=no<CR>       # el cursor cae en el = de ONBOOT=no
lcwyes<Esc>    # un paso a la derecha y cambia no por yes

¿Por qué buscar =no y no no? Porque no aparece también dentro de none, que acabamos de escribir en la línea 2. Buscando =no el patrón solo encaja en la línea 3. Y la l es necesaria porque cw cambia desde el cursor hasta el final de la palabra: si lo hiciéramos sobre el =, borraríamos el = (que para vi es una palabra en sí mismo).

Salida

Justo antes del :wq, la pantalla de vi:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.2.27
NETMASK=255.255.255.0
GATEWAY=192.168.2.1
NETWORK=192.168.2.0
~
~
                                                      7,19          All

Y el archivo en el disco después de guardar:

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=192.168.2.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=192.168.2.1
     7	NETWORK=192.168.2.0

Comprobación: había 6 líneas y o añadió una, 6 + 1 = 7. La posición 7,19 es la última letra de NETWORK=192.168.2.0 (19 caracteres). Las líneas 1, 4, 5 y 6 no se han tocado. En el dibujo se ve cada cambio con la orden que lo hizo:

El ifcfg-enp2s0 antes y después del programa 1Antes: BOOTPROTO=dhcp y ONBOOT=no. Después: BOOTPROTO=none, ONBOOT=yes y una línea nueva NETWORK=192.168.2.0, cada cambio con la orden que lo hizo.AntesDespués (:wq)DEVICE=enp2s0DEVICE=enp2s0BOOTPROTO=dhcpBOOTPROTO=nonecw noneONBOOT=noONBOOT=yesl cw yesIPADDR=192.168.2.27IPADDR=192.168.2.27NETMASK=255.255.255.0NETMASK=255.255.255.0GATEWAY=192.168.2.1GATEWAY=192.168.2.1NETWORK=192.168.2.0G o …
Tres cambios, tres órdenes: cw cambia una palabra y G + o abre una línea nueva al final.

Preguntas que te puedes hacer

¿Por qué cw y no x cuatro veces? Porque cw borra la palabra entera y te deja en inserción en un solo paso. Con x tendrías que contar letras (dhcp tiene 4, pero bootp tendría 5) y luego pulsar i.

¿Y si el archivo tuviera dos dhcp? /dhcp va a la primera. Tras cambiarla, n salta a la siguiente y . repite el último cambio (cwnone) sin volver a escribirlo.

¿Por qué G y luego o, y no o directamente? o abre la línea debajo de donde esté el cursor. Tras el segundo cw estábamos en la línea 3; sin G, NETWORK habría quedado entre ONBOOT e IPADDR. Al archivo le daría igual (el orden no importa en un ifcfg), pero queremos que quede ordenado.

¿Hace falta :wq o vale con :x? Valen los dos (y ZZ). La diferencia es que :x solo escribe si hay cambios: no toca la fecha de modificación si no has cambiado nada.

Buscar /no en lugar de /=no. Después de cambiar dhcp por none, la primera coincidencia de no está dentro de none y el cw destrozaría la línea 2.

Pruébalo tú

  • Sobre el archivo original, haz los dos primeros cambios con :%s en lugar de con búsquedas (pista: necesitas dos sustituciones).
  • Añade la línea DNS1=193.145.147.22 encima de GATEWAY usando O.

Programa 2: limpiar un archivo lleno de restos

Este ifcfg-enp2s0 lo han tocado tres personas: hay un IPADDR repetido, tres líneas comentadas con la configuración vieja y GATEWAY y NETMASK en el orden contrario al resto de archivos del aula. Y falta NETWORK.

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.1.27
     5	IPADDR=10.0.1.27
     6	#IPADDR=192.168.2.27
     7	#GATEWAY=192.168.2.1
     8	#NETMASK=255.255.255.0
     9	GATEWAY=10.0.1.1
    10	NETMASK=255.255.255.0

La idea

Borrar con número para no repetir órdenes, y mover líneas cortando y pegando:

  1. 5G + dd quita el IPADDR repetido (línea 5).
  2. Las tres líneas comentadas quedan seguidas en la 5, 6 y 7: un solo 3dd.
  3. ddp intercambia dos líneas: corta la del cursor y la pega debajo de la siguiente.
  4. G + o añade la línea que falta.

Antes de programar, piensa en cómo se renumeran las líneas. Después del primer dd, el comentario que estaba en la línea 6 pasa a ser la 5. Por eso el 3dd va justo después, sin moverse.

El código

5G             # la línea 5: el IPADDR repetido
dd             # fuera
3dd            # las tres líneas viejas comentadas
ddp            # GATEWAY baja debajo de NETMASK
GoNETWORK=10.0.1.0<Esc>   # la línea que faltaba
:wq<CR>

El truco del programa es ddp. Veámoslo con zoom:

ddp            # GATEWAY baja debajo de NETMASK

dd borra la línea GATEWAY y la guarda en el portapapeles de vi; al borrarla, NETMASK sube y el cursor queda sobre ella. p pega lo guardado debajo del cursor. Resultado: las dos líneas han cambiado de sitio. Son tres teclas que acabarás usando sin pensar.

Salida

Tras 5G y dd:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.0.1.27
#IPADDR=192.168.2.27
#GATEWAY=192.168.2.1
#NETMASK=255.255.255.0
GATEWAY=10.0.1.1
NETMASK=255.255.255.0
                                                      5,1           All

De 10 líneas a 9, y el cursor sigue en la línea 5, que ahora es el primer comentario. Tras 3dd:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.0.1.27
GATEWAY=10.0.1.1
NETMASK=255.255.255.0
~
~
~
3 fewer lines                                         5,1           All

3 fewer lines: 9 − 3 = 6. Tras ddp y la línea nueva:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.0.1.27
NETMASK=255.255.255.0
GATEWAY=10.0.1.1
NETWORK=10.0.1.0
~
~
                                                      7,16          All

El archivo final en el disco:

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.1.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=10.0.1.1
     7	NETWORK=10.0.1.0

Esta es la traza de las líneas que hay tras cada orden:

PasoOrdenLíneasCursorQué pasó
0(abrir)101archivo original
15G dd95fuera el IPADDR repetido
23dd65fuera los tres comentarios (6, 7 y 8 originales)
3ddp66GATEWAY y NETMASK intercambiadas
4G o…77NETWORK añadida al final

Y las tres fases dibujadas:

Las tres fases del programa 2Primero se borran la línea 5 repetida (dd) y las tres comentadas (3dd); después ddp baja GATEWAY debajo de NETMASK y G o añade NETWORK al final.1. Al abrirDEVICE=enp2s0BOOTPROTO=noneONBOOT=yesIPADDR=10.0.1.27IPADDR=10.0.1.27#IPADDR=192.168.2.27#GATEWAY=192.168.2.1#NETMASK=255.255.255.0GATEWAY=10.0.1.1NETMASK=255.255.255.02. Tras 5G dd y 3ddDEVICE=enp2s0BOOTPROTO=noneONBOOT=yesIPADDR=10.0.1.27GATEWAY=10.0.1.1NETMASK=255.255.255.03. Tras ddp y G oDEVICE=enp2s0BOOTPROTO=noneONBOOT=yesIPADDR=10.0.1.27NETMASK=255.255.255.0GATEWAY=10.0.1.1NETWORK=10.0.1.05G dd → 5 · 3dd → 6, 7, 8
Rojo: lo que borran dd y 3dd. Coral: la línea que mueve ddp. Verde: la que añade o.

Preguntas que te puedes hacer

¿Por qué no :g/^#/d para borrar los comentarios? Funcionaría (borra todas las líneas que empiezan por #) y es más potente, pero 3dd te enseña a contar líneas, que es lo que necesitas el 90 % de las veces. Tienes :g en el chuletario de los ejercicios.

¿Y si cuento mal y hago 4dd? Te llevas también GATEWAY. Pulsa u y vuelven las cuatro, porque 4dd es un único cambio.

¿ddp funciona en la última línea? No del todo: si borras la última línea, el cursor sube a la anterior y p la pega debajo… justo donde estaba. Para subir una línea se usa ddkP.

¿Dónde fue el IPADDR borrado? Al portapapeles de vi. Si justo después pulsaras p, volvería. Cada d sustituye lo que había guardado, igual que un «cortar».

Hacer el 3dd en la línea 6 «porque los comentarios empezaban en la 6». Después del primer dd todo ha subido una posición: estarías borrando dos comentarios y GATEWAY.

Pruébalo tú

  • Repite la limpieza en otro orden: primero 3dd en los comentarios y después el dd del repetido. ¿Qué número de línea tienes que usar ahora?
  • Copia la línea NETMASK con yy y pégala al final con G + p. Después bórrala con dd.

Programa 3: mudar la estación a otra red

El aula se reorganiza y la estación pasa de la red 10.0.1.x a la 10.0.5.x. Hay que cambiar la IP, la puerta de enlace y la dirección de red, sin tocar la máscara ni nada más:

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.1.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=10.0.1.1
     7	NETWORK=10.0.1.0

La idea

Primero localizar qué líneas llevan la red vieja (para saber qué esperar) y después cambiarlas todas de una vez con :%s, cuidando dos cosas: que los puntos sean puntos de verdad y que el patrón termine en punto, para no tocar números que solo empiecen igual.

Antes de programar, piensa en cuántas sustituciones deberían salir. Si vi te dice otro número, el patrón está mal.

El código

/GATEWAY<CR>   # comprueba dónde está la puerta de enlace
/10<CR>        # busca 10 desde ahí
n              # siguiente
n              # y otra vez (vuelve arriba)
:%s/10\.0\.1\./10.0.5./g<CR>
:w<CR>         # guarda sin salir
:q<CR>

La línea importante, desmontada:

:%s/10\.0\.1\./10.0.5./g

% para todas las líneas, \. para que el punto sea un punto (sin la barra, . encaja con cualquier carácter) y el punto final del patrón hace que solo cambie 10.0.1. seguido de algo, nunca un 10.0.10 o un 10.0.15. La g cambia todas las apariciones de cada línea (aquí hay una por línea, pero es buena costumbre).

Salida

Las búsquedas dejaron este rastro en la regla de vim:

TeclasPosiciónCarácterQué encontró
/GATEWAY Enter6,1Gla línea de la puerta de enlace
/10 Enter6,9110.0.1.1, justo detrás de GATEWAY= (8 caracteres)
n7,9110.0.1.0, detrás de NETWORK=
n4,81dio la vuelta: 10.0.1.27, detrás de IPADDR= (7)

Tres líneas con la red vieja: 4, 6 y 7. Tras la sustitución:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.0.5.27
NETMASK=255.255.255.0
GATEWAY=10.0.5.1
NETWORK=10.0.5.0
~
~
3 substitutions on 3 lines                            7,1           All

3 substitutions on 3 lines: el número que esperábamos. :w guarda sin salir y vim lo confirma:

DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.0.5.27
NETMASK=255.255.255.0
GATEWAY=10.0.5.1
NETWORK=10.0.5.0
~
~
"ifcfg-enp2s0" 7L, 113B written                       7,1           All

7L, 113B written: 7 líneas y 113 bytes. El archivo original tenía los mismos bytes, porque cambiamos un 1 por un 5 en tres sitios (mismo tamaño). En el disco:

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.5.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=10.0.5.1
     7	NETWORK=10.0.5.0
Anatomía de :%s/patrón/reemplazo/gLa orden :%s/10\.0\.1\./10.0.5./g troceada: dos puntos, el rango %, la s, el patrón con los puntos escapados, el reemplazo y la bandera g. Cambia IPADDR, GATEWAY y NETWORK.:%s/10\.0\.1\./10.0.5./gmodo órdenesrango: todo el archivosustituirpatrón (\. = un punto de verdad)reemplazotodas las de cada líneaIPADDR=10.0.1.27IPADDR=10.0.5.27GATEWAY=10.0.1.1GATEWAY=10.0.5.1NETWORK=10.0.1.0NETWORK=10.0.5.03 substitutions on 3 lines
Sin % solo cambia la línea del cursor; sin g, solo la primera coincidencia de cada línea.

El dibujo trocea la orden y enseña las tres líneas que cambió.

Preguntas que te puedes hacer

¿Qué pasaría sin el punto final del patrón? Con :%s/10\.0\.1/10.0.5/g aquí saldría lo mismo, pero en una red con IPADDR=10.0.1.15 y GATEWAY=10.0.10.1 también cambiarías 10.0.10.1 por 10.0.50.1. El punto final es un seguro barato.

¿Por qué buscar antes si :%s ya lo hace todo? Para saber qué número esperar. Contrastar «3 líneas encontradas» con «3 substitutions» es la forma rápida de comprobar que el patrón hace lo que crees.

¿Puedo ver los cambios uno a uno? Sí: con la bandera c (:%s/…/…/gc) vim te pregunta en cada uno replace with 10.0.5. (y/n/a/q/l/^E/^Y)?.

¿Y si me equivoco de red? u deshace la sustitución entera (es un solo cambio), aunque haya tocado tres líneas.

Escribir :s sin %. Solo mira la línea del cursor (aquí, la 4 tras la última búsqueda) y cambiarías la IP pero no la puerta de enlace ni la red. La estación quedaría en una red y su gateway en otra.

Pruébalo tú

  • Cambia solo las líneas 4 a 6 con un rango (:4,6s/…) y comprueba con cat -n que NETWORK sigue igual.
  • Usa la bandera c para aceptar el cambio de IPADDR y rechazar el de GATEWAY.

Errores típicos en esta práctica

  • Teclear con el cursor en el sitio equivocado: cw y dd actúan desde el cursor. Una búsqueda (/texto) antes de cada cambio evita sorpresas.
  • Contar líneas sin tener en cuenta los borrados anteriores: después de un dd, todo lo de debajo sube una posición.
  • Buscar un texto que también aparece en otro sitio: /no encuentra none. Haz el patrón más concreto (/=no).
  • Olvidar escapar el punto en :s: . es «cualquier carácter»; para un punto, \..
  • Sustituir sin %: solo cambia la línea del cursor.
  • Probar sobre el archivo real: trabaja sobre una copia hasta que la secuencia salga bien.

Pruébalo en tu terminal

vi también se puede usar sin abrir la pantalla: vim -es (modo ex silencioso) ejecuta órdenes de las que escribirías tras los dos puntos y termina. Es ideal dentro de un script. Esta es la misma mudanza del programa 3, ejecutada de verdad desde la terminal:

# vi sin abrir la pantalla: ex en modo silencioso (-es) ejecuta las órdenes de :  y termina
cat -n ifcfg-enp2s0
vim -u NONE -es -c '%s/10\.0\.1\./10.0.5./g' -c 'wq' ifcfg-enp2s0   # la misma sustitución del programa 3
echo $?                                                               # 0 = todo fue bien
cat -n ifcfg-enp2s0

La sesión real:

$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.1.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=10.0.1.1
     7	NETWORK=10.0.1.0
$ vim -u NONE -es -c '%s/10\.0\.1\./10.0.5./g' -c 'wq' ifcfg-enp2s0
$ echo $?
0
$ cat -n ifcfg-enp2s0
     1	DEVICE=enp2s0
     2	BOOTPROTO=none
     3	ONBOOT=yes
     4	IPADDR=10.0.5.27
     5	NETMASK=255.255.255.0
     6	GATEWAY=10.0.5.1
     7	NETWORK=10.0.5.0

Qué observar:

  1. Cada -c es una orden de las de : (sin los dos puntos), y se ejecutan en orden: primero la sustitución, después wq.
  2. -u NONE arranca vim sin configuración, para que se comporte igual en cualquier máquina.
  3. vim no escribe nada en la terminal: en modo silencioso solo habla si hay un error.
  4. echo $? da 0: todo fue bien (en los ejercicios verás un caso en el que también da 0… y no hace lo que querías).
  5. El resultado es idéntico al del programa 3: las líneas 4, 6 y 7 cambian y las demás no.

Resumen

  • En vi se edita con órdenes, no letra a letra: cw cambia una palabra, dd borra una línea, o abre una nueva.
  • Una búsqueda (/texto) es la forma más rápida y segura de poner el cursor en su sitio; haz el patrón concreto (/=no).
  • Un número delante repite la orden (3dd), y después de cada borrado las líneas se renumeran.
  • ddp intercambia dos líneas; u deshace una orden entera aunque haya tocado varias líneas.
  • :%s/patrón/reemplazo/g cambia todo el archivo; escapa los puntos (\.) y comprueba el número de sustituciones.
  • vim -es -c 'orden' -c 'wq' aplica las mismas órdenes desde un script.

Checklist: ¿lo has practicado?

  • ¿Has hecho los tres programas sobre una copia y comprobado el resultado con cat -n?
  • ¿Has intentado los «Pruébalo tú» sin mirar la teoría?
  • ¿Sabes por qué /=no es mejor que /no en el programa 1?
  • ¿Puedes explicar por qué el 3dd del programa 2 va en la línea 5 y no en la 6?
  • ¿Sabes qué hace cada parte de :%s/10\.0\.1\./10.0.5./g?
  • ¿Has probado vim -es desde la terminal?

Si has respondido que sí a casi todo, estás listo para los ejercicios de vi, donde ya no te doy las teclas hechas. ¡Nos vemos allí!

Siguiente paso: ejerciciosvi en Linux — ejercicios con resolv.conf, líneas repetidas y una tarjeta clonada (y el NBOOT=yes que nadie había escrito)

¿Te ha servido este artículo? Así puedes apoyar SergioLearns →

Sigue aprendiendo

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *