
Estoy usando este comando para buscar patrones en archivos zip (similar al) sugerido aquí https://superuser.com/questions/144926/unix-grep-for-a-string-within-all-gzip-files-in-all-subdirectories
find . -regex ".*/.*zip" | xargs zgrep -m 1 -E "PATTERN"
El grepping continúa después del primer partido. Probablemente find
yo xargs
sea el culpable. ¿Cómo dejar de buscar después grep
de encontrar la primera coincidencia?
PD¿Cómo detener el comando de búsqueda después de la primera coincidencia?no funcionará porque find
debe detenerse después de una coincidencia que tenga éxito con grep y no solo con la primera coincidencia de find.
Respuesta1
Varias cosas:
zgrep
es buscar.z
archivos.gz
comprimidos, no archivos dentro dezip
archivos comprimidos.A veces hay un
zipgrep
script (roto) incluido conunzip
, para buscarzip
archivos, pero lo que hace es ejecutarseegrep
en cada miembro del archivo (por lo que-m1
cada unoegrep
informaría la primera coincidencia para cada archivo).zgrep
, de manera similar, viene con un script quegzip
alimenta la salida degzip -cdfq
paragrep
cada archivo.gzip -d
Puede descomprimirzip
archivos, pero sólo lo hace para el primer miembro del archivo y sólo si está comprimido (enzip
los archivos, no todos los miembros están necesariamente comprimidos, especialmente los pequeños).xargs
ejecuta tan pocos comandos como sea necesario, pero aún puede ejecutar varios si la lista de archivos es grande.
En este caso, lo mejor que puede hacer probablemente sea implementarlo zipgrep
manualmente (aquí con herramientas GNU):
find . -name '*.zip' -type f -exec sh -c '
unzip -Z1 "$1" |
while IFS= read -r file; do
unzip -p "$1" "$file" | grep --label="$1//$file" -Hm1 -- "$0" && exit
done' PATTERN {} \; -quit
Eso ejecuta un shell por archivo, pero también lo haría zipgrep
y zipgrep
ejecuta muchos más comandos.
Puede fallar si los miembros del archivo tienen nombres que contienen caracteres comodín ( *
, [
, ?
) u otros caracteres como caracteres ASCII 0x1 a 0x1f y varios otros, pero eso se debe principalmente a errores y limitaciones en unzip
, y eso no es tan malo como cuando se usa zipgrep
.
Respuesta2
Intentar:
find . -iname '*.zip' -print0 | xargs -0r zgrep -l -E 'PATTERN'
He usado -iname
en lugar de -regex
: funciona también para esto y, en mi opinión, es menos confuso que find
el extraño manejo de expresiones regulares. -print0
y xargs -0
se utilizan para que cualquier nombre de archivo con espacios o metacaracteres de shell se maneje correctamente.
grep
La -l
opción está documentada en la página de manual:
-l, --files-with-matches
Suppress normal output; instead print the name of each input
file from which output would normally have been printed. The
scanning will stop on the first match.
La primera coincidencia mencionada es por archivo, por lo que si coinciden varios archivos, se imprimirán todos. tenga en cuenta que esto significa que grep continuará buscando otros archivos, incluso después de haber encontrado una coincidencia.
Si desea que se detenga después de la primera coincidencia, puede usar grep
la --line-buffered
opción y canalizar la salida de grep a head -1
. Cuando se imprima la primera coincidencia, head
la imprimirá y finalizará, grep
ya no tendrá una salida estándar, por lo que terminará y find
seguirá.
find . -iname '*.zip' -print0 | xargs -0r zgrep --line-buffered -l -E 'PATTERN' | head -1
Respuesta3
grep
La opción 's (o zgrep
's) -m
hará que deje de leer elarchivo actualen el primer partido:
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines.
Eso no le impedirá buscar en elpróximoarchivo. Por ejemplo:
$ echo "hello" > foo
$ echo "hello" > bar
$ grep -m 1 hello foo bar
foo:hello
bar:hello
Entonces, el problema no es xargs
más que el hecho de que estás recopilando varios archivos. Para que grep
(o zgrep
) se detenga después del primer emparejamientoarchivo, tendrías que ejecutar un pequeño bucle como sugirió @Stephane. O algo como esto con bash:
shopt -s globstar
for i in **/*.zip; do
zgrep -l pattern "$i" && break;
done
O, para archivos zip quecontener varios archivos(gracias @Stephane):
shopt -s globstar
for i in **/*.zip; do
if unzip -p "$i" | grep -q hello; then
echo "$i" && break;
fi;
done
Respuesta4
grep -m 1
enumera la primera coincidencia de cada archivo.
Hay una forma sencilla de enumerar solo la primera coincidencia: canalizar head -n 1
. La búsqueda pronto morirá de unSIGPIPE.
find . -regex ".*/.*zip" -print0 | xargs -0 zgrep -E "PATTERN" | head -n 1