don puede ser mejor en la mayoría de los casos, pero en caso de que el archivo sea realmente grande y no pueda sed
manejar 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 $B
lí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
$match
se encuentra en un espacio de patrón precedido por una línea de \n
flujo, sed
elegirá recursivamente D
cada línea de \n
flujo que lo precede.
- Antes estaba limpiando
$match
completamente 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/$B
son grandes, el D
bucle elete prueba considerablemente más rápido.
- Luego, extraemos la
N
línea de entrada de extensión precedida por un \n
delimitador de línea de línea e intentamos nuevamente D
elegir una de /\n.*$match/
nuevo refiriéndonos a nuestra expresión regular w / utilizada más recientemente //
.
- Si el espacio de patrón coincide,
$match
entonces solo puede hacerlo $match
al principio de la línea: todas las $B
líneas anteriores se han borrado.
- Entonces comenzamos a dar vueltas
$A
después.
- Cada ejecución de este bucle vamos a tratar de
s///
ubstitute por &
sí misma el $A
XX \n
carácter ewline en el espacio de patrones, y, si tiene éxito, t
est nos BRANCH - y toda nuestra $A
memoria 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
t
est no tiene éxito, b
volveremos a la :t
etiqueta de operación y recurriremos a otra línea de entrada, posiblemente comenzando el ciclo nuevamente si $match
ocurre mientras se recolecta $A
después.
- Si conseguimos más allá de un
$match
bucle de función, entonces vamos a tratar de p
rint la $
última línea, si esto es así, y si !
no tratar de s///
ubstitute por &
sí misma el $B
XX \n
carácter ewline en el espacio patrón.
- También consideraremos
t
esto, y si tiene éxito, pasaremos a la :P
etiqueta de la pista.
- Si no, volveremos a
:t
operar y obtendremos otra línea de entrada añadida al búfer.
- Si llegamos a
:P
rint, vamos a rint, P
luego D
elegiremos hasta la primera línea de \n
ewline 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 :P
rint se vería así:
^1\n2\n3$
Y así es como sed
reúne su $B
buffer antes. Y así se sed
imprime en las $B
líneas de conteo de salida detrás de la entrada que ha reunido. Esto significa que, dado nuestro ejemplo anterior, se sed
daría una P
pista 1
al resultado, y luego lo D
elegirí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 N
se 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 5
entrada, el espacio del patrón en realidad se ve así:
^3\n4\n5$
Luego, el D
bucle elete se activa y cuando termina, se ve así:
^5$
Y cuando N
se tira de la línea de entrada ext sed
golpea EOF y se cierra. En ese momento, solo ha P
borrado 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
$A
y / o$B
. Cuanto más grandes sean esos números, más lento se volverá, pero puede hacerlos razonablemente grandes.Puede usar
gnu grep
con-A
y-B
para imprimir exactamente las partes del archivo que desea excluir, pero agregue el-n
interruptor para imprimir también los números de línea y luego formatee el resultado y páselo como un script de comandosed
para eliminar esas líneas:Esto también debería funcionar con archivos de patrones pasados a
grep
través de, por-f
ejemplo: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,6d
lugar 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
:comm
requiere 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 quenl
se usa para numerar las líneas antes de ordenarlas,comm -13
imprime solo las líneas exclusivas de 2nd FILE y luegocut
elimina la parte que se agregónl
(es decir, el primer campo y el delimitador:
)con
join
:fuente
comm
sea más rápida que la original consed
ygrep
?Si no te importa usar
vim
:-Nes
activa 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-ranges
para estas dos)d
- Eliminar las líneas.+w !tee
luego 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
grep
ybash
):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
kos
la 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 engrep
la 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
awk
en 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