¿Cómo puedo recortar un archivo (flujo de entrada de pozo) para que solo obtenga las líneas que van desde la primera aparición del patrón foohasta la última aparición del patrón bar?
Por ejemplo, considere la siguiente entrada:
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
Espero esta salida:
foo
this
foo
bar
something
something else
foo
bar
text-processing
sed
rahmu
fuente
fuente

fooy el últimobare imprimirá todo en el medio, si acaso. Con un flujo, tendría que leer hasta el primerofoo, y almacenar en el búfer todas las líneas subsiguientes en la memoria hasta EOF, vaciando el búfer cada vez quebarse ve a. Esto podría significar almacenar en búfer todo el flujo en la memoria.Respuestas:
La coincidencia del patrón sed
/first/,/second/lee las líneas una por una. Cuando una línea coincide con/first/ella, la recuerda y espera la primera coincidencia para el/second/patrón. Al mismo tiempo, aplica todas las actividades especificadas para ese patrón. Después de que el proceso comienza una y otra vez hasta el final del archivo.Eso no es lo que necesitamos. Necesitamos buscar la última coincidencia de
/second/patrón. Por lo tanto, construimos una construcción que busca solo la primera entrada/foo/. Cuando se encuentra el cicloacomienza. Agregamos una nueva línea al búfer de coincidencia conNy verificamos si coincide con el patrón/bar/. Si lo hace, simplemente lo imprimimos y borramos el búfer de coincidencia y el salto de janyway al comienzo del ciclo conba.También debemos eliminar el símbolo de nueva línea después de limpiar el búfer con
/^\n/s/^\n//. Estoy seguro de que hay una solución mucho mejor, desafortunadamente no se me ocurrió.Espero que todo esté claro.
fuente
sedversiones, por ejemplo, BSD sed (que es lo que se encuentra en Mac), las etiquetas deben ir seguidas de una nueva línea o un final de cadena, por lo que es necesario el siguiente ajuste:sed -n -e '/foo/{:a' -e 'N;/^\n/s/^\n//;/bar/{p;s/.*//;};ba' -e '};'Esto también funciona en GNU sed, por lo que creo que esta modificación (múltiples-eargumentos poner fin a un argumento después de cada nombre de rama) es un buen hábito portátil para usar cuando se usan ramas en sed.Lo haría con un poco de Perl one-liner.
rendimientos
fuente
Elugar deey en-00777lugar del$/bit (consulte perlrun (1)). Lo que lo acortaría a:,perl -0777 -nE 'say /(foo.*bar)/s'todavía algo legible.-0[octal]encontrará su camino en mi flujo de trabajo! Gracias por esoAquí hay una solución sed de GNU de dos pasos que no requiere mucha memoria:
Explicación
sedinvocación pasa el archivo y encuentra la primera apariciónfooy todas las apariciones posteriores debar.sedscript con dos invocaciones desedy unatr. La salida del tercerosedes[start_address],[end_address]p, sin los corchetes.sedpasesinfilenuevamente, imprimiendo las direcciones encontradas y todo lo demás.fuente
Si el archivo de entrada cabe cómodamente en la memoria, manténgalo simple .
Si el archivo de entrada es enorme, puede usarlo
csplitpara dividirlo en pedazos al principiofooy en cada uno de ellosbarluego ensamblar los pedazos. Las piezas se llamanpiece-000000000,piece-000000001etc. Elija un prefijo (aquípiece-) que no choque con otros archivos existentes.(En sistemas que no sean Linux, tendrá que usar un gran número dentro de las llaves, por ejemplo
{999999999}, y pasar la-kopción. Ese número es el número debarpiezas).Puedes ensamblar todas las piezas
cat piece-*, pero esto te dará todo después del primerofoo. Quita esa última pieza primero. Dado que los nombres de archivo producidos porcsplitno contienen ningún carácter especial, puede trabajarlos sin tomar ninguna precaución especial, por ejemplo, cono equivalente
Ahora puede unir todas las piezas y eliminar los archivos temporales:
Si desea eliminar las piezas, ya que están concatenadas para ahorrar espacio en disco, hágalo en un bucle:
fuente
Aquí hay otra forma con
sed:Agrega cada línea en el
/foo/,$rango (!sedeligen líneas que no están en este rango ) alHespacio antiguo. Las líneas que no coincidenbarse eliminan. En las líneas que coinciden, el espacio del patrón se vacía, sexcambia con el espacio de espera y se elimina la línea vacía principal en el espacio del patrón.Con una entrada enorme y pocas ocurrencias de
baresto, debería ser (mucho) más rápido que tirar de cada línea al espacio del patrón y luego, cada vez, verificar el espacio del patrónbar.Explicado:
Claro, si este es un archivo (y cabe en la memoria) simplemente podría ejecutar:
porque
edpuede buscar hacia adelante y hacia atrás.Incluso podría leer una salida de comando en el búfer de texto si su shell admite la sustitución de procesos:
o si no es así, con
gnu ed:fuente
Usando cualquier awk en cualquier shell en cualquier sistema UNIX y sin leer todo el archivo o la secuencia de entrada en la memoria al mismo tiempo:
fuente
Grep también podría hacerlo (bueno, GNU grep):
Para la entrada del cuerpo de la pregunta:
fuente