2011-07-18 21 views
31

Estoy tratando de agregar una línea de texto a la mitad de un archivo de texto en un script bash. Específicamente, intento agregar un servidor de nombres a mi archivo /etc/resolv.conf. Tal como está, resolv.conf se ve así:¿Cómo agrego una línea de texto al medio de un archivo usando bash?

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

Mi objetivo es añadir nameserver 127.0.0.1 por encima de todas las demás líneas de servidores de nombres, pero por debajo de cualquier texto encima de eso. Al final quiero mi archivo resolve.conf a tener este aspecto:

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 127.0.0.1 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

¿Cómo es esto posible a través de una escritura del golpe? ¿Esto es algo que Sed o awk pueden hacer? ¿O sería la mejor opción moverme creativamente para recrear el archivo?

Respuesta

34

Aquí es una solución usando sed:

$ sed -n 'H;${x;s/^\n//;s/nameserver .*$/nameserver 127.0.0.1\n&/;p;}' resolv.conf 

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 127.0.0.1 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

Cómo funciona: en primer lugar, suprimir la salida del comando sed con la bandera -n. Luego, para cada línea, añadimos la línea hasta el espacio de bodega, separándolos con saltos de línea:

H 

Cuando llegamos al final del archivo (dirigida por $) que mover el contenido del espacio de bodega para el espacio del patrón:

x 

Si la primera línea del espacio del patrón está en blanco, la reemplazamos por nada.

s/^\n// 

A continuación, se sustituye la primera línea que comienza con nameserver por una línea que contiene nameserver 127.0.0.1, una nueva línea (Su versión de sed puede no apoyar \n, en cuyo caso sustituir el n con una nueva línea literal) y la línea original (representados por &):

s/nameserver .*$/nameserver 127.0.0.1\n&/ 

Ahora sólo tenemos que imprimir los resultados:

p 
+1

Esto es grande. Lo único extraño es que agrega una línea en blanco en la parte superior del nuevo archivo. No es gran cosa, pero está causando un momento de TOC. – PHLAK

+4

¡Oh, sí, tienes razón! El comando 'sed -n 'H; $ {x; s/^ \ n //; s/nameserver. * \ N/nameserver 127.0.0.1 \ n & /; p;}' resolv.conf', sin embargo, resuelve esto problema. Agregué 's/^ \ n //' al comando, por lo que eliminará la nueva línea al comienzo del contenido del espacio del patrón. – brandizzi

+0

¡Impresionante, gracias! – PHLAK

8

awk '/^nameserver/ && !modif { printf("INSERT\n"); modif=1 } {print}'

+0

Gran solución 'awk', tal vez la única que no copia todo el archivo en la memoria ... – MestreLion

15

Suponiendo que desea insertar inmediatamente después de la línea search, esto es mucho más simple:

sed -ie '/^search/a nameserver 127.0.0.1' filename 
  • -i: archivo de edición en lugar
  • -e: permite la ejecución de un script/expresión de comandos dentro de sed
  • a mynewtext: comando que indica a sed que inserte el mynewtext texto después emparejado patrón
+0

Esa es la cosa ... esa línea de búsqueda puede o no estar allí. Las líneas del servidor de nombres siempre deben estar allí, y quiero que se inserte la nueva línea inmediatamente antes de ellos, independientemente del resto del contenido del archivo. – PHLAK

+0

@PHLAK, la solución ofrecida por Jim es buena. Yo lo modificaría, sin embargo. Simplemente agregue un _special comment_ para marcar la línea donde se supone que se deben ingresar cosas nuevas. P.ej. una línea como '# <>' o algo así. Luego, en lugar de '/^buscar /', puede buscar '/^# <> $ /', lo que hace que sea mucho más improbable que coincida con la línea incorrecta. – bitmask

+0

¿Cómo modificaría esto (si fuera posible) para usar una sola línea de otro archivo (suponiendo que este archivo tiene solo una línea), en lugar de 'nameserver 127.0.0.1'? – Juan

0

Esto podría funcionar para que:

sed -e '/nameserver/{x;/./b;x;h;i\nameserver 127.0.0.1' -e '}' resolv.conf 

O GNU SED:

sed -e '0,/nameserver/{//i\nameserver 127.0.0.1' -e '}' resolv.conf 
0

he aquí una solución Perl:

perl -lne 'if (not $f and /^nameserver/){ print "nameserver 127.0.0.1"; $f=1 }; print' resolv.conf

  • -n bucle alrededor de cada línea del archivo de entrada, no se imprimirá automáticamente cada línea

  • -l elimina los saltos de línea antes de la transformación, y los añade de vuelta en adelante

  • -e ejecutar el código perl

$f se usa como una bandera para indicar que la cadena de servidor de nombres ya se ha encontrado

Cuestiones relacionadas