A continuación se muestra el texto del archivo:

Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Necesito grep para «42B» y obtenga el resultado del texto anterior como:

Pseudo name=Apple Code=42B state=fault 

¿Alguien tiene idea de cómo lograr esto usando grep / awk / sed?

Comentarios

  • Etiquetó esta pregunta con solo " grep ". Entonces, ¿solo busca soluciones " grep "? En la pregunta, también especifica awk & sed. ¿Podemos agregar esas etiquetas? No estaba ' seguro de tu intención cuando edité la pregunta anoche.
  • stackoverflow.com/ preguntas / 12024410 / …

Responder

Con awk

awk -v RS="" "/42B/" file 

RS= cambia el separador de registros de entrada de una nueva línea a líneas en blanco. Si algún campo en un registro contiene /42B/ imprima el registro.

"" (la cadena nula) es una magia valor utilizado para representar líneas en blanco según POSIX :

If RS es nulo, los registros están separados por secuencias que constan de un <newline> más uno o más espacios en blanco líneas, líneas en blanco iniciales o finales no deben dar como resultado registros vacíos al principio o al final de la entrada, y un <newline> siempre será un separador de campo, sin importar el valor de FS es.

Los párrafos de salida no separarse ya que el separador de salida sigue siendo una única línea nueva. Para asegurarse de que haya una línea en blanco entre los párrafos de salida, configure el separador de registros de salida en dos líneas nuevas:

awk -v RS="" -v ORS="\n\n" "/42B/" file 

Comentarios

  • +1 para una solución elegante. No ' no es necesario que redirija el archivo …
  • los dedos estaban en piloto automático.
  • @jasonwryan, a menos que necesite acceso al nombre del archivo dentro de awk (FILENAME), ' no es una mala idea utilizar la redirección, ya que evita problemas con el nombre de archivo que contiene = o comenzando con - (o siendo -), genera mensajes de error consistentes y evita ejecutar awk o realizar otras redirecciones si el archivo de entrada no puede ' t abrirse.

Respuesta

Suponiendo que los datos están estructurados de modo que siempre sea la línea antes y después de lo que desea, puede utilizar grep «s -A (después) y -B (antes) para indicarle que incluya la 1 línea antes de la coincidencia y la 1 línea después:

$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Si desea el las mismas líneas numéricas antes y después del término de búsqueda, puede usar el -C (contexto):

$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Si le gustaría ser más estricto al hacer coincidir las múltiples líneas, puede usar la herramienta pcregrep , para hacer coincidir un patrón sobre varias líneas:

$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault 

El patrón anterior coincide de la siguiente manera:

  • -M: varias líneas
  • "Pseudo.*\n.*42B.*\nstate.*": coincide con un grupo de cadenas donde la primera cadena comienza con la palabra "Pseudo" seguido de cualquier carácter hasta el final de la línea \n, seguido de cualquier carácter hasta la cadena "42B" seguido de cualquier carácter hasta otro final de línea (\n), seguido de la cadena "state" seguida de cualquier carácter.

Comentarios

  • -C (contexto) se puede utilizar como acceso directo, si -A y -B son iguales.
  • @DavidBaggerman – gracias. Se agregó a la respuesta.
  • ¿Por qué el voto negativo? Esto responde a la pregunta.

Respuesta

El grep de algunas versiones de Unix tienen el indicador -p para «párrafo». Sé que AIX hace .

grep -p 42B <myfile> 

haría exactamente lo que estás pidiendo allí . YMMV y GNU grep no tienen esta bandera.

Comentarios

  • Tener la bandera -p sería maravilloso. Especialmente si se usa junto con -v para que pueda excluir párrafos completos de la salida.

Respuesta

Probablemente exista una forma igualmente fácil de hacerlo con awk, pero en perl:

cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;" 

Eso básicamente dice que dividir el archivo en fragmentos delimitados por líneas en blanco, luego imprimir solo aquellos fragmentos que coincidan con su expresión regular.

Comentarios

  • Esto se puede simplificar utilizando opciones y abreviaturas, y perdiendo el uso inútil de cat ; perl -00 -ne 'print if /42B/' file

Respuesta

Otra solución de Perl, sin línea vacía al final:

perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo 

Ejemplo

% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Comentarios

  • O más corto (y por lo tanto más legible), como escribió triplee en un comentario: perl -00 -ne 'print if /42B/' file.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *