vi en Linux — ejercicios con resolv.conf, líneas repetidas y una tarjeta clonada (y el NBOOT=yes que nadie había escrito)
El día del examen práctico de redes, un compañero de mi fila levantó la mano: «Profe, vi me ha escrito una línea que pone NBOOT=yes y yo no he sido». Sí había sido él: tecleó ONBOOT=yes en modo normal y la O se convirtió en una orden. Toda la clase se rió… y la mitad comprobamos a escondidas que nuestro archivo estaba bien. La lección: en vi, antes de escribir, mira abajo; si no pone -- INSERT --, tus letras son órdenes.
Estos ejercicios cierran el tema de vi después de la teoría y la práctica. Ahora tú decides las teclas.
Tabla de Contenidos
Cómo usar este artículo
- Lee el enunciado y la salida esperada (lo que tiene que dar
cat -nal final). - Haz una copia del archivo y resuélvelo en vi sin mirar la solución. Si te atascas, abre la pista.
- Antes de mirar las soluciones, haz los tres fragmentos de «¿Qué falla aquí?»: predice qué pasará.
- Compara tus teclas con las mías. Hay muchas secuencias válidas: lo que cuenta es el resultado y que sepas por qué funciona.
Nivel 1: crea el resolv.conf
El archivo /etc/resolv.conf dice a qué servidores DNS pregunta la máquina para traducir nombres (como ulpgc.es) a direcciones IP. Crea desde cero un archivo resolv.conf con los dos primeros servidores DNS de la universidad, uno por línea, con el formato nameserver IP: 193.145.147.22 y 193.145.138.100.
Partes de que el archivo no existe:
$ cat -n resolv.conf cat: resolv.conf: No such file or directory
Salida esperada:
$ cat -n resolv.conf
1 nameserver 193.145.147.22
2 nameserver 193.145.138.100
vi resolv.conf abre un archivo vacío (vi lo crea al guardar). Entra en inserción, escribe la primera línea, Enter, la segunda, Esc y guarda.
Nivel 2: fuera los repetidos
Este resolv.conf tiene el primer servidor repetido tres veces y dos servidores públicos que el laboratorio no quiere usar (8.8.8.8 y 8.8.4.4). Deja solo los tres de la universidad, sin borrar línea a línea: usa órdenes con número.
$ cat -n resolv.conf
1 nameserver 193.145.147.22
2 nameserver 193.145.147.22
3 nameserver 193.145.147.22
4 nameserver 193.145.138.100
5 nameserver 8.8.8.8
6 nameserver 8.8.4.4
7 nameserver 193.145.138.200
Salida esperada:
$ cat -n resolv.conf
1 nameserver 193.145.147.22
2 nameserver 193.145.138.100
3 nameserver 193.145.138.200
Son dos borrados de dos líneas cada uno. Fíjate en dónde queda el cursor después del primero.
Nivel 3: clona la tarjeta
La estación va a tener una segunda tarjeta, enp3s0, con la misma configuración que enp2s0 pero la IP siguiente (.28 en lugar de .27). Partiendo de ifcfg-enp2s0, crea ifcfg-enp3s0 sin modificar el original y sin escribir la IP a mano.
$ 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
$ cat -n ifcfg-enp3s0
cat: ifcfg-enp3s0: No such file or directory
Salida esperada:
$ 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
$ cat -n ifcfg-enp3s0
1 DEVICE=enp3s0
2 BOOTPROTO=none
3 ONBOOT=yes
4 IPADDR=10.0.1.28
5 NETMASK=255.255.255.0
6 GATEWAY=10.0.1.1
7 NETWORK=10.0.1.0
Necesitas tres cosas de vim que no son de vi clásico ni de la práctica: :w nombre guarda con otro nombre, Ctrl-a suma 1 al número que hay en el cursor o a su derecha, y :q! sale sin tocar el archivo que abriste.
¿Qué falla aquí?
Tres fragmentos sobre el ifcfg-enp2s0 de la teoría (BOOTPROTO=dhcp, ONBOOT=no, red 192.168.2.x). Antes de leer la explicación, predice qué saldrá en la pantalla.
Fragmento 1: escribir sin entrar en inserción
Abres el archivo y, sin pulsar nada más, tecleas:
ONBOOT=yes # tecleado en modo normal, como si estuvieras en inserción <Esc>:q!<CR>
Predice: ¿aparece ONBOOT=yes en algún sitio?
La pantalla real tras teclear ONBOOT=yes:
NBOOT=yes DEVICE=enp2s0 BOOTPROTO=dhcp ONBOOT=no IPADDR=192.168.2.27 NETMASK=255.255.255.0 GATEWAY=192.168.2.1 ~ ~ -- INSERT -- 1,10 All
Hay una línea nueva arriba del todo con NBOOT=yes y vim está en inserción. Cada letra se interpretó según el modo en que estaba vi en ese momento:
En modo normal, O es la orden «abre una línea encima y entra en inserción». A partir de ahí ya estás en inserción y el resto (NBOOT=yes) se escribe tal cual. La posición 1,10 es el final de esa línea nueva.
Confiar en que vi «ya estaba escribiendo». Con otras palabras el destrozo cambia, porque cada letra es una orden distinta (d borra, x borra, u deshace, p pega…). Mira siempre la última línea.
El arreglo: Esc, u para deshacer, ir a la línea correcta y cambiarla entera con cc: 3GccONBOOT=yes<Esc>. Es justo la primera orden del fragmento 2, y su resultado lo ves allí.
Fragmento 2: salir sin guardar… o no
3GccONBOOT=yes<Esc> # cambia la línea 3 entera :q<CR> # intenta salir <CR> :wq<CR> # guarda y sale
Predice: ¿qué hace el :q?
BOOTPROTO=dhcp ONBOOT=yes IPADDR=192.168.2.27 NETMASK=255.255.255.0 GATEWAY=192.168.2.1 ~ ~ ~ E37: No write since last change (add ! to override) Press ENTER or type command to continue
E37: hay un cambio sin guardar (la línea 3) y :q se niega a salir. La pantalla ha subido una línea para hacer sitio al mensaje y vim espera un Enter. Tras ese Enter, :wq sí guarda y sale:
$ cat -n ifcfg-enp2s0
1 DEVICE=enp2s0
2 BOOTPROTO=dhcp
3 ONBOOT=yes
4 IPADDR=192.168.2.27
5 NETMASK=255.255.255.0
6 GATEWAY=192.168.2.1
Lee el mensaje entero: add ! to override te dice que :q! saldría tirando el cambio. vi nunca te deja atrapado; te obliga a decidir.
Fragmento 3: la sustitución que no encuentra nada
El cursor está en la línea 1 (recién abierto) y quieres pasar el archivo de la red 192.168.2 a la 10.0.1:
:s/192.168.2/10.0.1/g<CR> # sin % : solo la línea del cursor (la 1) :%s/192.168.2/10.0.1/g<CR> # con % : todo el archivo :wq<CR>
Predice: ¿cuántas líneas cambia la primera orden?
DEVICE=enp2s0 BOOTPROTO=dhcp ONBOOT=no IPADDR=192.168.2.27 NETMASK=255.255.255.0 GATEWAY=192.168.2.1 ~ ~ ~ E486: Pattern not found: 192.168.2 1,1 All
E486: Pattern not found: ninguna. Sin %, :s solo mira la línea del cursor, y la línea 1 (DEVICE=enp2s0) no contiene 192.168.2. vim no busca en el resto del archivo. Con % sí:
DEVICE=enp2s0 BOOTPROTO=dhcp ONBOOT=no IPADDR=10.0.1.27 NETMASK=255.255.255.0 GATEWAY=10.0.1.1 ~ ~ ~ :%s/192.168.2/10.0.1/g 6,1 All
Y tras :wq:
$ cat -n ifcfg-enp2s0
1 DEVICE=enp2s0
2 BOOTPROTO=dhcp
3 ONBOOT=no
4 IPADDR=10.0.1.27
5 NETMASK=255.255.255.0
6 GATEWAY=10.0.1.1
Si :s te da E486 y estás seguro de que el texto está en el archivo, casi siempre falta el % (o un rango como :4,6s).
Soluciones
Solución del Nivel 1
inameserver 193.145.147.22<CR>nameserver 193.145.138.100<Esc> :wq<CR>
La pantalla antes de guardar:
nameserver 193.145.147.22
nameserver 193.145.138.100
~
~
~
~
~
~
~
2,26 All
Por qué está hecho así:
ientra en inserción en un archivo vacío (también valdríaauo).<CR>dentro de inserción es un salto de línea normal: no ejecuta nada.- Esc antes de
:wq, porque los dos puntos solo abren el modo de órdenes desde el modo normal. Si no pulsas Esc, escribirías:wqdentro del archivo. - Comprobación: la regla dice
2,26porquenameserver 193.145.138.100tiene 26 caracteres (10 + 1 espacio + 15). Ya no pone-- INSERT --: Esc nos devolvió al modo normal.
Solución del Nivel 2
j2dd # en la línea 2, borra las dos copias j2dd # baja a 8.8.8.8 y borra esa línea y 8.8.4.4 :wq<CR>
Tras el primer j2dd:
nameserver 193.145.147.22
nameserver 193.145.138.100
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 193.145.138.200
~
~
~
~
2,1 All
Por qué está hecho así:
jbaja a la línea 2 y2ddborra la 2 y la 3: las dos copias. La primera aparición se queda. Quedan 7 − 2 = 5 líneas.- Después del borrado el cursor está en la línea 2 (
193.145.138.100): lo que había debajo subió. Unjmás y estamos en8.8.8.8.
Tras el segundo j2dd:
nameserver 193.145.147.22
nameserver 193.145.138.100
nameserver 193.145.138.200
~
~
~
~
~
~
3,1 All
2ddse lleva8.8.8.8y8.8.4.4: 5 − 2 = 3 líneas. El cursor queda en la 3 (193.145.138.200), la que subió.- La alternativa obvia,
ddcinco veces moviéndote entre medias, funciona, pero son más teclas y más ocasiones de borrar la que no es.
Solución del Nivel 3
:%s/enp2s0/enp3s0/g<CR> # el nombre de la tarjeta /IPADDR<CR> # la línea de la IP $<C-a> # al final de la línea y suma 1 al número: 27 -> 28 :w ifcfg-enp3s0<CR> # guarda con OTRO nombre :q!<CR> # el original no se toca
Tras la sustitución, la búsqueda y el Ctrl-a:
DEVICE=enp3s0 BOOTPROTO=none ONBOOT=yes IPADDR=10.0.1.28 NETMASK=255.255.255.0 GATEWAY=10.0.1.1 NETWORK=10.0.1.0 ~ ~ /IPADDR 4,16 All
IPADDR=10.0.1.28: Ctrl-a buscó el número desde el cursor y le sumó 1 (27 + 1 = 28). La regla dice 4,16, el último dígito de la línea. Después, :w ifcfg-enp3s0:
DEVICE=enp3s0 BOOTPROTO=none ONBOOT=yes IPADDR=10.0.1.28 NETMASK=255.255.255.0 GATEWAY=10.0.1.1 NETWORK=10.0.1.0 ~ ~ "ifcfg-enp3s0" [New] 7L, 113B written 4,16 All
[New] 7L, 113B written: el archivo nuevo tiene 7 líneas y 113 bytes, los mismos que el original (cambiamos 2 por 3 y 7 por 8, mismo tamaño). El mensaje no cabe entero en la esquina y vim lo recorta por la izquierda con <.
Por qué está hecho así:
:%s/enp2s0/enp3s0/gcambia el nombre en cualquier línea donde aparezca (aquí soloDEVICE, pero en otros ifcfg también va enNAME).$antes deCtrl-adeja el cursor sobre el7: así suma 1 a27. Desde el principio de la línea,Ctrl-atambién habría encontrado el primer número de la línea, que es el10de10.0.1.27, y habrías creado11.0.1.27.:w ifcfg-enp3s0escribe el búfer en otro archivo, pero vi sigue editandoifcfg-enp2s0.:q!es clave: el búfer tiene cambios respecto aifcfg-enp2s0y no queremos guardarlos ahí. El original sale intacto, como pedía el enunciado.
El dibujo enseña los dos archivos al final: el original sin tocar y el clon con sus dos diferencias.
Pruébalo en tu terminal
El fragmento 3 tiene una versión aún más traicionera: dentro de un script, con vim -es. Esta sesión es real, sobre el ifcfg-enp2s0 con la red 192.168.2:
# El fragmento 3 en modo silencioso: sin % la orden solo mira la línea 1 vim -u NONE -es -c 's/192.168.2/10.0.1/g' -c 'wq' ifcfg-enp2s0 echo $? # distinto de 0: algo falló grep -c 192.168.2 ifcfg-enp2s0 # cuántas líneas siguen con la red vieja vim -u NONE -es -c '%s/192.168.2/10.0.1/g' -c 'wq' ifcfg-enp2s0 echo $? grep -c 192.168.2 ifcfg-enp2s0
Lo que salió:
$ vim -u NONE -es -c 's/192.168.2/10.0.1/g' -c 'wq' ifcfg-enp2s0 $ echo $? 0 $ grep -c 192.168.2 ifcfg-enp2s0 1 $ vim -u NONE -es -c '%s/192.168.2/10.0.1/g' -c 'wq' ifcfg-enp2s0 $ echo $? 0 $ grep -c 192.168.2 ifcfg-enp2s0 0
Qué observar:
- La primera orden, sin
%, no da error:echo $?vale 0. En modo ex, la línea actual al empezar es la última del archivo (GATEWAY=192.168.2.1), y ahí sí había coincidencia. - Por eso
grep -ccuenta 1: de las dos líneas con192.168.2, solo cambió una. QuedaIPADDRcon la red vieja. - El mismo descuido da un resultado distinto según dónde esté el cursor: en pantalla (fragmento 3) falló con E486; aquí «funciona» a medias y en silencio.
- Con
%, la segunda orden arregla lo que quedaba y el recuento baja a 0. - Moraleja para tus scripts: comprueba el resultado (
grep -c), no solo$?.
Chuletario: vi
Lo esencial en 30 segundos
vi tiene tres modos: normal (órdenes), inserción (texto) y órdenes (:). Esc siempre vuelve al normal. Las órdenes se combinan: número + operador (d, c, y) + movimiento. Nada llega al disco hasta :w, y :q! sale sin guardar.
Moverse
| Quiero… | Teclas | Resultado |
|---|---|---|
| bajar / subir una línea | j / k | misma columna (si existe) |
| ir al principio / final de línea | 0 / $ | |
| ir a la línea 5 | 5G | |
| primera / última línea | gg / G | |
| siguiente palabra / anterior | w / b | = cuenta como palabra |
buscar ONBOOT | /ONBOOT Enter | cursor en la O; n siguiente, N anterior |
saltar al siguiente = de la línea | f= |
Editar
| Quiero… | Teclas | Resultado |
|---|---|---|
| escribir antes del cursor / al final de línea | i / A | -- INSERT -- |
| línea nueva debajo / encima | o / O | |
| cambiar una palabra | cw | borra y entra en inserción |
| cambiar la línea entera | cc | |
| borrar carácter / línea / 3 líneas | x / dd / 3dd | 3 fewer lines |
| copiar línea y pegarla debajo | yy p | |
| intercambiar con la de abajo | ddp | |
| deshacer / rehacer / repetir | u / Ctrl-r / . | |
| sumar 1 al número | Ctrl-a | 27 → 28 |
Órdenes de :
| Quiero… | Orden | Resultado |
|---|---|---|
| guardar / guardar y salir | :w / :wq | "archivo" 7L, 113B written |
| salir sin guardar | :q! | el disco no cambia |
| guardar con otro nombre | :w ifcfg-enp3s0 | [New] |
| sustituir en todo el archivo | :%s/viejo/nuevo/g | N substitutions on M lines |
| sustituir en las líneas 4 a 6 | :4,6s/viejo/nuevo/g | |
| borrar las líneas que empiezan por # | :g/^#/d | |
| sin abrir pantalla (scripts) | vim -es -c '%s/a/b/g' -c wq archivo |
Plantillas de los ejercicios
| Ejercicio | Teclas | Resultado |
|---|---|---|
| Nivel 1 | i texto <CR> texto <Esc> :wq | archivo nuevo de 2 líneas |
| Nivel 2 | j2dd j2dd :wq | de 7 a 3 líneas |
| Nivel 3 | :%s/enp2s0/enp3s0/g /IPADDR $ Ctrl-a :w ifcfg-enp3s0 :q! | original intacto + clon con .28 |
Síntoma / causa probable
| Síntoma | Causa probable |
|---|---|
| aparecen letras sueltas o líneas raras | escribiste en modo normal; Esc y u |
E37: No write since last change | :q con cambios: :wq o :q! |
E486: Pattern not found con :s | falta % o el patrón no coincide (¿un punto sin escapar?) |
:wq aparece escrito dentro del archivo | estabas en inserción: Esc antes de : |
E45: 'readonly' option is set | el archivo es de otro usuario (root): sudo vi |
vim dice Press ENTER | el mensaje no cabía: pulsa Enter y sigue |
Antes de entregar, pregúntate
- ¿He comprobado el archivo con
cat -ndespués de salir de vi, no solo en la pantalla del editor? - ¿El número de sustituciones o de líneas borradas es el que esperaba?
- ¿He salido con
:wqcuando quería guardar y con:q!cuando no? - ¿He trabajado sobre una copia hasta estar seguro?
Con vi dominado, el siguiente tema abre por fin lo que hay dentro del ifcfg: la configuración de red en Linux.
¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




El hardware que sostiene al sistema operativo — teoría con la práctica de IC2 en la impresora, una interrupción que lo para todo y una caché que acierta (y el bucle infinito que no colgó mi portátil)