Tengo un montón de archivos y quiero encontrar cuál contiene líneas secuenciales que comienzan con una cadena determinada.
Por ejemplo para el siguiente archivo:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee
Hay más de una línea que comienza con 'C', por lo que quiero que este archivo se encuentre por comando.
Por ejemplo para el siguiente archivo:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Siempre hay una línea que comienza con 'C', no quiero este archivo. Pensé en usar a grep
o a sed
pero no sé exactamente cómo hacerlo. Tal vez usando una expresión regular ^C.*$^C
o algo así. Alguna idea ?
C
en su segundo ejemplo.C
?grep
versiones anteriores .Respuestas:
Con
pcregrep
:POSIXY:
(aunque eso significa leer todos los archivos completamente con aquellas
awk
implementaciones que no son compatiblesnextfile
).Con versiones de GNU
grep
hasta 2.5.4:parece funcionar, pero es por accidente y no se garantiza que funcione.
Antes de que se corrigiera en 2.6 (por este commit ), GNU
grep
había pasado por alto que la función de búsqueda de pcre que estaba usando coincidiría con todo el búfer procesado actualmentegrep
, causando todo tipo de comportamiento sorprendente. Por ejemplo:coincidiría en un archivo que contiene:
Esto coincidiría con:
Pero esto:
O:
no lo haría (ya que
1\n2\n
está en dos buffers procesados porgrep
).Sin embargo, ese comportamiento terminó siendo documentado:
Después de que se corrigió en 2.6, la documentación no se modificó (una vez lo informé allí ).
fuente
exit
y en-exec \;
lugar de nextfile?awk
por archivo. Desea hacer eso solo siawk
no es compatiblenextfile
y tiene una gran proporción de archivos que son grandes y tienen líneas coincidentes hacia el comienzo del archivo.-z
con-P
. No hay\N
sin-P
, tendrías que escribirlo,$'[\01-\011\013-\0377]'
que solo funcionaría en C locales (ver thread.gmane.org/gmane.comp.gnu.grep.bugs/5187 )Con
awk
:Esto imprimirá el contenido del archivo si hay líneas consecutivas que comienzan con a
C
. La expresión(p ~ /^C/ && $1 ~ /^C/)
buscará líneas sucesivas en el archivo y se evaluará como verdadero si el primer carácter de ambos coincideC
. Si ese es el caso, se imprimirá la línea.Para encontrar todos los archivos que tienen dicho patrón, puede ejecutar el awk anterior a través de un
find
comando:En este comando, el
find
+exec
pasará por cada uno de los archivos y realizará unawk
filtrado similar en cada archivo e imprimirá su nombreFILENAME
si la expresión awk se evalúa como verdadera. Para evitar imprimirFILENAME
varias veces para un solo archivo con múltiples coincidenciasexit
, se utiliza la declaración (gracias @terdon).fuente
C
flag
, solo en suexit
lugar. De esa manera, no necesita seguir procesando archivos después de encontrar una coincidencia.Otra opción más con GNU
sed
:Para un solo archivo:
(aunque también informará los archivos que no puede leer).
Para
find
:El problema con los archivos ilegibles que se imprimen se puede evitar escribiéndolo:
fuente
sed -n '$q1;/^C/{n;/^C/q}'
?$q1
: obliga a sed a salir con un error si no se encuentra el patrón. También terminará con un error si algo está mal con el archivo (es ilegible o está roto). Por lo tanto, se cerrará con el estado de salida 0 solo en caso de que se encuentre un patrón y se pase a imprimir. Parte con/^C/{n;/^C/q
es bastante simple. Si encuentra una cadena que comienza con C, leerá la siguiente línea y si también comienza con C, se cerrará con el estado de salida cero.Asumiendo que sus archivos son lo suficientemente pequeños como para ser leídos en la memoria:
Explicación:
000
: establecido\n\n
como separador de registros, esto activa el modo de párrafo que tratará los párrafos (separados por nuevas líneas consecutivas) como líneas individuales.-ne
: aplica el script dado como argumento-e
a cada línea de los archivos de entrada.$ARGV
: es el archivo que se está procesando actualmente/^C[^\n]*\nC/
: coincideC
al principio de una línea (consulte la descripción de lossm
modificadores a continuación para saber por qué esto funciona aquí) seguido de 0 o más caracteres que no sean de nueva línea, una nueva línea y luego otra C. En otras palabras, encuentre líneas consecutivas que comiencen porC
. *//sm
: estos modificadores de coincidencia son (como se documenta [aquí]):También podrías hacer algo feo como:
En este caso, el
perl
código reemplaza los saltos de línea, con%%
lo que, suponiendo que no tiene%%
en su archivo de entrada (grande si , por supuesto), lagrep
coincidirá con líneas consecutivas comenzando conC
.fuente
SOLUCIÓN:
MANIFESTACIÓN:
Primero, crearemos una base de prueba:
Lo anterior crea 26 archivos en
/tmp
nombrefile1-26
. En cada archivo hay 27 o 28 líneas que comienzan con las letrasa-z
y seguidas del resto del alfabeto. Cada tercer archivo contiene dos líneas consecutivas en las que se duplica el primer carácter.MUESTRA:
Y cuando cambio:
a:
Yo obtengo...
SALIDA:
Entonces, en resumen, la solución funciona así:
fuente
Este script usa
grep
ycut
para obtener números de línea de líneas coincidentes, y verifica dos números consecutivos. Se supone que el archivo tiene un nombre de archivo válido pasado como primer argumento para el script:fuente