¿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 foo
hasta 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
foo
y el últimobar
e 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 quebar
se 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 cicloa
comienza. Agregamos una nueva línea al búfer de coincidencia conN
y 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
sed
versiones, 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-e
argumentos 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
E
lugar dee
y en-00777
lugar 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
sed
invocación pasa el archivo y encuentra la primera apariciónfoo
y todas las apariciones posteriores debar
.sed
script con dos invocaciones desed
y unatr
. La salida del tercerosed
es[start_address],[end_address]p
, sin los corchetes.sed
pasesinfile
nuevamente, 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
csplit
para dividirlo en pedazos al principiofoo
y en cada uno de ellosbar
luego ensamblar los pedazos. Las piezas se llamanpiece-000000000
,piece-000000001
etc. 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-k
opción. Ese número es el número debar
piezas).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 porcsplit
no 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 (!
sed
eligen líneas que no están en este rango ) alH
espacio antiguo. Las líneas que no coincidenbar
se eliminan. En las líneas que coinciden, el espacio del patrón se vacía, sex
cambia 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
bar
esto, 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
ed
puede 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