Han ignorado las líneas que no coinciden

94

¿Cómo puedo sedfiltrar las líneas coincidentes de acuerdo con alguna expresión, pero ignorar las líneas que no coinciden, en lugar de dejar que se impriman?

Como ejemplo real, quiero ejecutar scalac(el compilador Scala) en un conjunto de archivos y leer de su -verbosesalida los .classarchivos creados. scalac -verbosegenera un montón de mensajes, pero solo nos interesan los del formulario [wrote some-class-name.class]. Lo que estoy haciendo actualmente es esto ( |&es la forma de bash 4.0 de canalizar stderr al siguiente programa):

$ scalac -verbose some-file.scala ... |& sed 's/^\[wrote \(.*\.class\)\]$/\1/'

Esto extraerá los nombres de archivo de los mensajes que nos interesan, ¡pero también permitirá que todos los demás mensajes pasen sin cambios! Por supuesto que podríamos hacer en su lugar esto:

$ scalac -verbose some-file.scala ... |& grep '^\[wrote .*\.class\]$' |
  sed 's/^\[wrote \(.*\.class\)\]$/\1/'

que funciona pero se parece mucho a solucionar el problema real, que es cómo dar instrucciones sedpara ignorar las líneas que no coinciden de la entrada. ¿Entonces cómo hacemos eso?

Paggas
fuente
2
La respuesta aceptada debe ser la de mouviciel: stackoverflow.com/a/1665574/869951
Oliver

Respuestas:

90

Otra forma con sed simple:

sed -e 's/.../.../;t;d'

s///es una sustitución, tsin ninguna etiqueta, omite condicionalmente todos los comandos siguientes, delimina la línea.

No necesita perl ni grep.

(editado según la sugerencia de Nicholas Riley)

liori
fuente
3
En OS X 10.8.2 tuve que separar txy dcon una nueva línea en lugar de un punto y coma como estaba obteniendo undefined label 'x;d;:x'.
davidchambers
6
Aún mejor: sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(sugerido en un comentario sobre una pregunta similar ).
davidchambers
1
't' se transferirán al final de la secuencia de comandos si hay una etiqueta se suministra, de manera más simple: sed -e 's/.../.../' -e 't' -e 'd'.
Nicholas Riley
La gente no conoce el significado de -eopción, así que no lo mencione en general.
Fredrick Gauss
246

Si no desea imprimir líneas que no coincidan, puede utilizar la combinación de

  • -n opción que le dice a sed que no imprima
  • p bandera que le dice a sed que imprima lo que coincide

Esto da:

sed -n 's/.../.../p'
Mouviciel
fuente
3
Una desventaja de este enfoque es que si tiene varias expresiones que coinciden, el resultado también se imprimirá varias veces. Por ejemplo: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'generará ambos bary oofen líneas separadas. Aunque la variedad Ir a etiqueta tampoco puede manejar varios patrones, ya que eliminará la línea si el primer patrón no coincide.
Rapsey
@Rapsey, eso se debe a que le está diciendo que imprima dos veces. En el comando sed único le ha dicho que imprima dos veces, cada instancia se imprime in situ (o tal vez almacenada en búfer). Tendrías que poner una tubería en lugar de -e o solo poner 'p' en la última -e.
microbiano
@Rapsey: vea mi respuesta sobre este punto relevante
Amessihel
@microbial, no funcionará ya que el último indicador p funcionará en cada línea que coincida con la última expresión de sustitución.
Amessihel
1

Utilice Perl:

... |& perl -ne 'print "$1\n" if /^\[wrote (.*\.class)\]$/'
Greg Hewgill
fuente
0

Rapsey planteó un punto relevante sobre las expresiones de sustituciones múltiples.

  • Primero, citando una respuesta de Unix SE , puede "prefijar la mayoría de los comandos sed con una dirección para limitar las líneas a las que se aplican".
  • En segundo lugar, puede agrupar los comandos entre llaves {}(separados por un punto y coma ;o una nueva línea)
  • En tercer lugar, agregue el indicador de impresión p en la última sustitución

Sintaxis:

sed -n -e '/^given_regexp/ {s/regexp1/replacement1/flags1;[...];s/regexp1/replacement1/flagsnp}'

Ejemplo (consulte el documento Aquí para obtener más detalles):

  • Código:

    sed -n -e '/^ha/ {s/h/k/gp;s/a/e/g}' <<SAMPLE
    haha
    hihi
    SAMPLE
    
  • Resultado:

    kaka
    
Amessihel
fuente
-1
sed -n '/.../!p'

No hay necesidad de sustitución.

Obviamente
fuente