Usando los comandos estándar de Unix, ¿cómo agarras un montón de líneas?


1

Tengo varios archivos de texto con este formato:

name: john
address: bay area
phone: 6505561234
image: /work/myimage.png

name: stark
dob: 5AD
shirt color: red
physical address: Westros
phone model: S2
email id: me@stark.org

phone model: S2
name: tara
dob: 1ad
shirt color: red
physical address: Westros
email id: me@stark.org

Puede haber múltiples 'persona o' contacto '. Digamos que quiero encontrar a todas las personas con el modelo de teléfono 'S2'.

Puedo hacer un 'grep', eso solo devolvería esto:

phone model: S2
phone model: S2

Puedo usar el contexto antes / después en grep, pero eso es solo un número fijo de líneas antes / después que se imprimen. Con un contexto 'anterior' de 3, podría obtener algo como esto:

shirt color: red
physical address: Westros
phone model: S2
---
name: tara
dob: 1ad
phone model: S2

Pero eso no es lo que quiero. Quiero que aparezca todo el 'registro'. ¿Alguna pista sobre cómo hacer esto con los comandos estándar de Unix?


2
Suena como un trabajo para awk, pero, sinceramente, sería más fácil hacerlo con otras herramientas. ¿Por qué necesita herramientas estándar de Unix? ¿Puedes usar un lenguaje de scripting como Ruby o Python también? Esos a menudo vienen con todo tipo de distribuciones de Linux.
slhck

1
Sé que desea comandos Unix estándar, pero solo señalaré que Recutils le permite realizar consultas complejas contra datos formateados exactamente de esta manera.

Respuestas:


4

awk 'BEGIN {RS="\n\n"} $0 ~ /PATTERN/ {print $0"\n---"}' record

Simplemente reemplace PATTERN con lo que quiera.


1

Si reemplaza sus líneas vacías con ---, su documento es un archivo YAML válido. Esto representa muy bien una estructura de registro como la que tienes.

perl -p -e 's/^$/---/g' input > test.yml

Luego, para obtener los registros completos:

ruby -e 'require "yaml"; 
YAML::load_documents(File.open("test.yml")) do |d| 
  puts d.to_yaml if d["phone model"] == "S2" rescue nil
end'

Esto imprime:

---
name: stark
dob: 5AD
shirt color: red
physical address: Westros
phone model: S2
email id: me@stark.org
---
name: tara
dob: 1ad
phone model: S2
shirt color: red
physical address: Westros
email id: me@stark.org

Marcado como CW ya que estaba pidiendo herramientas estándar de Unix, que rubyobviamente no lo es. Funciona con Ruby 1.8.7, 1.9.3 y 2.0.0.


0

Usando esta pregunta, consigo encontrar una manera de hacer un grep multilínea para los bloques:

grep -Pzo 'name:(..*\n)*phone model:.*S2.*(..*\n)*' filename \
 | sed 's/^name:/---\nname:/' \
 | tail -n +2

donde (..*\n)*hay cualquier número de líneas contagiosas no vacías. -Phabilita la sintaxis de perl, -zpermite búsquedas de nueva línea e -oimprime solo las coincidencias. Sed se usa para la separación y la cola corta la primera línea.


1
Las claves de grabación son impredecibles.
Ярослав Рахматуллин

@ Ярослав La suposición que hice fue que todos los registros comienzan con la clave de nombre. Del ejemplo que esperaba this formatsignificar 1. todos los registros comienzan con el nombre de la clave 2. todas las claves están escritas en su propia línea 3. los registros están separados por una línea vacía. Mi solución funciona bien para eso.
Tim

@Tim: Mi ejemplo sugiere que siempre debe comenzar con 'nombre'; ese no es el caso ... Actualizaré mi ejemplo.
Utkarsh Sinha

0

La solución con awk es bastante clara. Aquí hay una posible solución con sed:

  1. -n no imprima nada
  2. todas las líneas no vacías se agregan al registro de retención
  3. cuando se encuentra una línea vacía, el registro de retención y el espacio del patrón se intercambian
    • si el espacio del patrón contiene la cadena que se pasa como primer argumento para look4pattern (), se imprime todo el conjunto de líneas.
  4. igual que 3. para la última línea (no puedo saber si la última línea está vacía)

$ look4pattern() { 
    sed -n '
    /^$/!{H}; 
    /^$/{ x ; /'$1'/p }; 
       ${ x ; /'$1'/p }
  ' < records.txt
  }

$ look4pattern S2

name: stark
dob: 5AD
shirt color: red
physical address: Westros
phone model: S2
email id: me@stark.org

name: tara
dob: 1ad
phone model: S2
shirt color: red
physical address: Westros
email id: me@stark.org

0

Los registros separados por líneas en blanco son en realidad un formato común para los archivos de fortuna, y (al menos en la versión de fortune que tengo, fortune-mod en Arch Linux) hay una -mopción que imprime todas las fortunas (registros) que coinciden con una expresión regular. Entonces algo como esto:

fortune -m "model: S2"

e imprimirá todos sus registros.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.