don puede ser mejor en la mayoría de los casos, pero en caso de que el archivo sea realmente grande y no pueda sedmanejar un archivo de script tan grande (que puede suceder en más de 5000 líneas de script) , aquí está con simple sed:
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Este es un ejemplo de lo que se llama una ventana deslizante en la entrada. Funciona mediante la construcción de un preanálisis de amortiguamiento de las $Blíneas -Contar incluso antes de intentar imprimir nada.
Y en realidad, probablemente debería aclarar mi punto anterior: el limitador de rendimiento primario tanto para esta solución como para el don estará directamente relacionado con el intervalo. Esta solución se ralentizará con intervalos de mayor tamaño , mientras que la de don disminuirá con frecuencias de intervalo más grandes . En otras palabras, incluso si el archivo de entrada es muy grande, si la ocurrencia del intervalo real es muy poco frecuente, entonces su solución es probablemente el camino a seguir. Sin embargo, si el tamaño del intervalo es relativamente manejable y es probable que ocurra con frecuencia, entonces esta es la solución que debe elegir.
Así que aquí está el flujo de trabajo:
- Si
$matchse encuentra en un espacio de patrón precedido por una línea de \nflujo, sedelegirá recursivamente Dcada línea de \nflujo que lo precede.
- Antes estaba limpiando
$matchcompletamente el espacio del patrón, pero para manejar fácilmente la superposición, dejar un hito parece funcionar mucho mejor.
- También traté
s/.*\n.*\($match\)/\1/de intentarlo de una vez y esquivar el bucle, pero cuando $A/$Bson grandes, el Dbucle elete prueba considerablemente más rápido.
- Luego, extraemos la
Nlínea de entrada de extensión precedida por un \ndelimitador de línea de línea e intentamos nuevamente Delegir una de /\n.*$match/nuevo refiriéndonos a nuestra expresión regular w / utilizada más recientemente //.
- Si el espacio de patrón coincide,
$matchentonces solo puede hacerlo $matchal principio de la línea: todas las $Blíneas anteriores se han borrado.
- Entonces comenzamos a dar vueltas
$Adespués.
- Cada ejecución de este bucle vamos a tratar de
s///ubstitute por &sí misma el $AXX \ncarácter ewline en el espacio de patrones, y, si tiene éxito, test nos BRANCH - y toda nuestra $Amemoria intermedia espués - fuera del guión completo para iniciar el script más de la parte superior con la siguiente línea de entrada si la hay.
- Si el
test no tiene éxito, bvolveremos a la :tetiqueta de operación y recurriremos a otra línea de entrada, posiblemente comenzando el ciclo nuevamente si $matchocurre mientras se recolecta $Adespués.
- Si conseguimos más allá de un
$matchbucle de función, entonces vamos a tratar de print la $última línea, si esto es así, y si !no tratar de s///ubstitute por &sí misma el $BXX \ncarácter ewline en el espacio patrón.
- También consideraremos
testo, y si tiene éxito, pasaremos a la :Petiqueta de la pista.
- Si no, volveremos a
:toperar y obtendremos otra línea de entrada añadida al búfer.
- Si llegamos a
:Print, vamos a rint, Pluego Delegiremos hasta la primera línea de \newline en el espacio del patrón y volveremos a ejecutar el script desde arriba con lo que queda.
Y esta vez, si estuviéramos haciendo A=2 B=2 match=5; seq 5 | sed...
El espacio del patrón para la primera iteración en :Print se vería así:
^1\n2\n3$
Y así es como sedreúne su $Bbuffer antes. Y así se sedimprime en las $Blíneas de conteo de salida detrás de la entrada que ha reunido. Esto significa que, dado nuestro ejemplo anterior, se seddaría una Ppista 1al resultado, y luego lo Delegiría y enviaría de nuevo a la parte superior del script un espacio de patrón que se parece a:
^2\n3$
... y en la parte superior de la secuencia de comandos Nse recupera la línea de entrada ext y, por lo tanto, la siguiente iteración se ve así:
^2\n3\n4$
Y así, cuando encontramos la primera aparición de 5entrada, el espacio del patrón en realidad se ve así:
^3\n4\n5$
Luego, el Dbucle elete se activa y cuando termina, se ve así:
^5$
Y cuando Nse tira de la línea de entrada ext sedgolpea EOF y se cierra. En ese momento, solo ha Pborrado las líneas 1 y 2.
Aquí hay un ejemplo de ejecución:
A=8 B=7 match='[24689]0'
seq 100 |
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Que imprime:
1
2
3
4
5
6
7
8
9
10
11
12
29
30
31
32
49
50
51
52
69
70
71
72
99
100
$Ay / o$B. Cuanto más grandes sean esos números, más lento se volverá, pero puede hacerlos razonablemente grandes.Puede usar
gnu grepcon-Ay-Bpara imprimir exactamente las partes del archivo que desea excluir, pero agregue el-ninterruptor para imprimir también los números de línea y luego formatee el resultado y páselo como un script de comandosedpara eliminar esas líneas:Esto también debería funcionar con archivos de patrones pasados a
greptravés de, por-fejemplo:Creo que esto podría optimizarse ligeramente si colapsó tres o más números de línea consecutivos en rangos para tener, por ejemplo, en
2,6dlugar de2d;3d;4d;5d;6d... aunque si la entrada tiene solo unas pocas coincidencias, no vale la pena hacerlo.Otras formas que no conservan el orden de las líneas y probablemente sean más lentas:
con
comm:commrequiere una entrada ordenada, lo que significa que el orden de las líneas no se conservará en la salida final (a menos que su archivo ya esté ordenado), por lo quenlse usa para numerar las líneas antes de ordenarlas,comm -13imprime solo las líneas exclusivas de 2nd FILE y luegocutelimina la parte que se agregónl(es decir, el primer campo y el delimitador:)con
join:fuente
commsea más rápida que la original consedygrep?Si no te importa usar
vim:-Nesactiva el modo ex silencioso no compatible. Útil para scripting.+{command}dile a vim que se ejecute{command}en el archivo.g/${PAT}/- En todas las líneas coincidentes/fff/. Esto se vuelve complicado si el patrón contiene caracteres especiales de expresión regular que no pretendía tratar de esa manera..-${B}- desde 1 línea por encima de esta.+${A}- a 2 líneas debajo de esta (ver:he cmdline-rangespara estas dos)d- Eliminar las líneas.+w !teeluego escribe en la salida estándar.+q!se cierra sin guardar los cambios.Puede omitir las variables y usar el patrón y los números directamente. Los usé solo por claridad de propósito.
fuente
¿Qué tal (usando GNU
grepybash):Aquí estamos encontrando las líneas a ser descartadas
grep -B2 -A1 'fff' file.txt, luego usándolas como un archivo de entrada para encontrar las líneas deseadas que las descartan.fuente
kosla solución (ahora eliminada) como si hubiera líneas duplicadas en el archivo de entrada y algunas caen fuera del rango y otras están dentro de ese rango, esto las eliminará a todas. Además, con múltiples ocurrencias de patrón , si hay líneas como--en el archivo de entrada (fuera de los rangos) esto las eliminará porque el delimitador--aparece engrepla salida cuando más de una línea coincide con el patrón (la última es altamente improbable pero vale la pena mencionando supongo).Puede alcanzar un resultado suficientemente bueno mediante el uso de archivos temporales:
El resultado es lo suficientemente bueno porque puede perder algo de sangría en el proceso, pero si se trata de un archivo insensible xml o de sangría, no debería ser un problema. Dado que este script usa una unidad ram, escribir y leer esos archivos temporales es tan rápido como trabajar en la memoria.
fuente
Además, si solo desea excluir algunas líneas delante de un marcador dado, puede usar:
(Glenn Jackman en /programming//a/1492538 )
Al canalizar algunos comandos, puede obtener el comportamiento antes / después:
fuente
awken un archivo invertido para manejar las siguientes líneas cuando quiera afectar las líneas anteriores y revertir el resultado.Una forma de lograr esto, quizás la forma más fácil sería crear una variable y hacer lo siguiente:
De esta manera todavía tienes tu estructura. Y puede ver fácilmente desde el revestimiento que está tratando de eliminar.
fuente
Si solo hay 1 coincidencia:
De lo contrario (awk):
fuente