GNU/Linux >> Tutoriales Linux >  >> Linux

El concepto de 'Espacio de espera' y 'Espacio de patrón' en sed

@Ed Morton:No estoy de acuerdo contigo aquí. Encontré sed muy útil y simple (una vez que asimila el concepto del patrón y mantiene los búferes) para encontrar una forma elegante de hacer grepping multilínea.

Por ejemplo, tomemos un archivo de texto que tiene nombres de host y alguna información sobre cada host, con mucha basura en el medio que no me importa.

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Para mí, un script awk para obtener las líneas con el nombre de host y el correspondiente info línea tomaría un poco más de lo que puedo hacer con sed:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

la salida se parece a:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

(Tenga en cuenta que Host: foo1 aparece dos veces en la salida).

Explicación:

  1. -n deshabilita la salida a menos que se imprima explícitamente
  2. primera coincidencia, encuentra y pone el Host: línea en el búfer de retención (h)
  3. segunda coincidencia, encuentra la siguiente línea Info:, pero primero intercambia (x) la línea actual en el búfer de patrón con el búfer de retención e imprime (p) el Host: línea, luego vuelve a intercambiar (x) e imprime (p) la línea Info:.

Sí, este es un ejemplo simplista, pero sospecho que es un problema común que se resolvió rápidamente con una sola línea de sed. Para tareas mucho más complejas, como aquellas en las que no puede confiar en una secuencia predecible dada, awk puede ser más adecuado.


Cuando sed lee un archivo línea por línea, la línea que se ha leído actualmente se inserta en el patrón búfer (espacio patrón). El búfer de patrones es como el búfer temporal, el bloc de notas donde se almacena la información actual. Cuando le dices a sed que imprima, imprime el búfer de patrones.

El búfer de retención/el espacio de retención es como un almacenamiento a largo plazo, de modo que puede capturar algo, almacenarlo y reutilizarlo más tarde cuando sed esté procesando otra línea. No procesa directamente el espacio de retención, sino que debe copiarlo o agregarlo al espacio de patrón si desea hacer algo con él. Por ejemplo, el comando de impresión p imprime el espacio del patrón solamente. Asimismo, s opera en el espacio del patrón.

Aquí hay un ejemplo:

sed -n '1!G;h;$p'

(la opción -n suprime la impresión automática de líneas)

Aquí hay tres comandos:1!G , h y $p . 1!G tiene una dirección, 1 (primera línea), pero el ! significa que el comando se ejecutará en todas partes pero en la primera línea. $p en cambio solo se ejecutará en la última línea. Entonces lo que sucede es esto:

  1. la primera línea se lee y se inserta automáticamente en el espacio del patrón
  2. en la primera línea, el primer comando no se ejecuta; h copia la primera línea en el espera espacio.
  3. ahora la segunda línea reemplaza lo que estaba en el espacio del patrón
  4. en la segunda línea, primero ejecutamos G , agregando el contenido del búfer de retención al búfer de patrón, separándolo con una nueva línea. El espacio del patrón ahora contiene la segunda línea, una nueva línea y la primera línea.
  5. Entonces, h El comando inserta el contenido concatenado del búfer de patrones en el espacio de retención, que ahora contiene las líneas invertidas dos y uno.
  6. Pasamos a la línea número tres:ve al punto (3) anterior.

Finalmente, después de leer la última línea y agregar el espacio de espera (que contiene todas las líneas anteriores en orden inverso) al espacio patrón, el espacio patrón se imprime con p . Como habrás adivinado, lo anterior hace exactamente lo que tac el comando sí:imprime el archivo al revés.


Aunque la respuesta de @January y el ejemplo son buenos, la explicación no fue suficiente para mí. Tuve que buscar y aprender mucho hasta que logré entender cómo exactamente sed -n '1!G;h;$p' obras. Así que me gustaría dar más detalles sobre el comando para alguien como yo.

En primer lugar, veamos qué hace el comando.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Invierte la entrada como tac el comando lo hace.

sed lee línea por línea, así que veamos qué sucede en el espacio de patrón y el espacio de espera en cada línea. Como h El comando copia el contenido del espacio del patrón al espacio de espera, ambos espacios tienen el mismo texto.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

En la última línea, $p imprime d\nc\nb\na$ que está formateado para

d
c
b
a

Si desea ver el patrón de espacio para cada línea, puede agregar un l comando.

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

Me resultó muy útil ver este video tutorial Comprender cómo funciona sed, ya que el chico muestra cómo se usará cada espacio paso a paso. El espacio de espera se menciona en el 4to tutorial, pero recomiendo ver todos los videos si no está familiarizado con sed .

También el documento sed de GNU y el tutorial Sed de Bruce Barnett son muy buenas referencias.


Linux
  1. ¿Cómo insertar texto antes de la primera línea de un archivo?

  2. ¿Imprimir línea coincidente y línea enésima de la línea coincidente?

  3. ¿Imprimir línea anterior después de una coincidencia de patrón usando Sed?

  4. ¿Adjuntar palabra al final de la línea con Sed?

  5. ¿Trap, Err y haciendo eco de la línea de error?

Ohcount:el contador y analizador de líneas de código fuente

¿Encuentra el número de línea que contiene el patrón usando el delimitador Regex personalizado?

¿Cómo cambiar la longitud de línea predeterminada para Od y Hexdump?

¿Cómo el comando Sed '1!g;h;$!d' invierte el contenido de un archivo?

Tutorial de Unix Sed:7 ejemplos de operaciones Sed Hold y Pattern Buffer

MySQL la línea de comando y buscapersonas