Estoy intentando conectar algo que devuelva solo el primer "párrafo" o "sección" separado por una línea en blanco. Pensé que podría usar awk
or sed
para obtener un rango según otras respuestas, pero no parece funcionar.
$ cat txt
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
$ cat txt |awk '/^Package:/,/^$/'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
¿No debería devolver sólo la primera "sección"? (según: Grep comenzando desde un texto fijo, hasta la primera línea en blanco y https://www.unix.com/shell-programming-and-scripting/148692-awk-script-match-pattern-till-blank-line.html)
- Si uso
grep -ve ^$
las líneas en blanco, se eliminan, por lo que no hay caracteres especiales. Si intento extraer una parte diferente, obtengo las partes de ambas "secciones":
$ cat txt |awk '/^Package:/,/^Version:/' Package: plasma-desktop Architecture: amd64 Version: 4:5.12.9.1-0ubuntu0.1 Package: plasma-desktop Architecture: amd64 Version: 4:5.12.4-0ubuntu1
Si uso
sed -n '/^Package:/,/^$/p'
osed -n '/^Package:/,/^Version:/p'
obtengo los mismos resultados que el equivalente awk.
¿Cómo consigo awk
o sed
detengo después de la primera aparición?
Respuesta1
Esta es exactamente la razón por la que awk tiene un modo de párrafo:
$ awk -v RS= 'NR==1' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
e imprimir el segundo registro es solo el cambio obvio de NR==1
a NR==2
:
$ awk -v RS= 'NR==2' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
Por cierto, nunca use expresiones de rango: hacen que el código para problemas triviales sea un poco más breve que usar una bandera, pero luego, si sus requisitos cambian en lo más mínimo, requerirán una reescritura completa o condiciones duplicadas. Entonces, cada vez que desee usar /begin/,/end/
sed o awk, use /begin/{f=1} f{print} /end/{f=0}
awk en su lugar y eso le brinda MUCHO más control sobre cuándo/cómo imprimir las líneas de inicio/final, etc.
Respuesta2
En /begin/,/end/
, las "banderas de acción" se activan cada vez que /begin/
se encuentra una coincidencia y se desactivan cuando /end/
se encuentra una coincidencia. También se imprimen las líneas de límite con "comienzo" y "fin".
Las consecuencias de su entrada son (las líneas impresas tienen un comentario después en los siguientes ejemplos):
- Con
'/^Package:/,/^$/'
:
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.9.1-0ubuntu0.1 #
Supported: 3y #
#TURN OFF
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.4-0ubuntu1 #
Supported: 3y #
- Con
'/^Package:/,/^Version:/'
:
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.9.1-0ubuntu0.1 #TURN OFF
Supported: 3y
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.4-0ubuntu1 #TURN OFF
Supported: 3y
Para imprimir sólo el párrafo que comienza en "Paquete:" puedes escribir
sed -ne '/^$/q' -e '/^Package:/,$p' file
sed
deja de procesar el archivo tan pronto como encuentra una línea en blanco debido a /^$/q
.
Con awk
:
awk '/^$/{exit};/^Package:/,0' file
Respuesta3
Como comentado porcuasimodo
/begin/,/end/
obtiene líneas que coinciden con esas expresiones regulares, incluidas las líneas de límite. comenzar activa la impresión y finalizar la desactiva. La línea justo después de la línea en blanco vuelve a activar la impresión, porque también la tienePackage:
.
Me di cuenta de que puedo usar sed
y cambiar /begin/
a 0
y comenzará desde el principio. Como sólo hay un comienzo, sólo coincidirá una vez.
$ cat txt |sed -n '0,/^$/p'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y