¿Hay alguna forma de obligar al find
comando a detenerse justo después de encontrar el primer partido?
¿Hay alguna forma de obligar al find
comando a detenerse justo después de encontrar el primer partido?
Respuestas:
Con GNU o FreeBSD find
, puede usar el -quit
predicado:
find . ... -print -quit
El find
equivalente de NetBSD :
find . ... -print -exit
Si todo lo que hace es imprimir el nombre, y suponiendo que los nombres de los archivos no contienen caracteres de nueva línea, puede hacer lo siguiente:
find . ... -print | head -n 1
Eso no se detendrá find
después del primer partido, pero posiblemente, dependiendo del momento y el almacenamiento en el segundo partido o (mucho) más tarde. Básicamente, find
terminará con un SIGPIPE cuando intente generar algo mientras head
ya no está, porque ya ha leído y mostrado la primera línea de entrada.
Tenga en cuenta que no todos los shells esperarán ese find
comando después de que head
haya regresado. Las implementaciones de shell Bourne y AT&T de ksh
(cuando no son interactivas) y yash
(solo si esa canalización es el último comando en un script) no lo harían, dejándolo ejecutándose en segundo plano. Si prefiere ver ese comportamiento en cualquier shell, siempre puede cambiar lo anterior a:
(find . ... -print &) | head -n 1
Si está haciendo más que imprimir las rutas de los archivos encontrados, puede probar este enfoque:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(reemplace printf
con lo que sea que esté haciendo con ese archivo).
Eso tiene el efecto secundario de find
devolver un estado de salida que refleja el hecho de que fue asesinado
En realidad, el uso de la señal SIGPIPE en lugar de SIGTERM (en kill -s PIPE
lugar de kill
) hará que algunos proyectiles sean más silenciosos sobre esa muerte (pero aún devolvería un estado de salida distinto de cero).
if [[ $(find ... -print -quit) ]]; then ...
Solo prueba si find imprimió algo.
$(…)
parte entre comillas en caso de que esté usando solo los corchetes ( [ … ]
).
[
es un comando estándar. No es tanto ese comando lo que es horrible, sino la forma en que los shells tipo Bourne analizan las líneas de comando. [[...]]
es una construcción ksh que tiene problemas propios en varios shells. Por ejemplo, hasta hace poco [[ $(...) ]]
no funcionaría zsh
(lo necesitabas [[ -n $(...) ]]
). Excepto en zsh
, necesita comillas [[ $a = $b ]]
, [[ =~ ]]
tiene diferencias incompatibles entre implementaciones e incluso entre versiones para bash y varios errores en algunos. Personalmente, lo prefiero [
.
...
? .
find . -name something -print -quit
Termina la búsqueda después de la primera coincidencia después de imprimirla.
Termine la búsqueda después de una cantidad específica de coincidencias y resultados de impresión:
find . -name something -print | head -n 5
Sorprendentemente, la cabeza ahora termina la secuencia después de 5 partidos, aunque no sé cómo ni por qué.
Es muy fácil de probar. Solo deje que encuentre una búsqueda en la raíz que generaría miles, tal vez incluso más coincidencias mientras toma al menos un minuto o más. Pero cuando se canaliza a "head", "find" terminará después de la cantidad especificada de líneas definidas en head (el encabezado predeterminado muestra 10, use "head -n" para especificar líneas).
Tenga en cuenta que esto terminará después de que "head -n" alcance el recuento de caracteres de nueva línea especificado y, por lo tanto, cualquier coincidencia que contenga varios caracteres de nueva línea contará en consecuencia.
Para fines de entretenimiento, aquí hay un generador de búsqueda perezosa en Bash. Este ejemplo genera un anillo sobre los archivos en el directorio actual. Lee cuantos quieras entonces kill %+
(tal vez solo 1)
#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT
coproc x while :; do
find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
read -r _
printf '%s\0' "$x"
done
EOF
while
echo >&${x[1]}
IFS= read -rd '' -u "$x" 'files[n++]'
do
printf '%q ' "${files[@]}"
echo
sleep .2
done
grep también regresa si se usa con la bandera -m
, entonces con
find stuff | grep -m1 .
regresará después de la primera línea impresa por find.
La diferencia entre esto y esto find stuff -print -quit | head -1
es que si la búsqueda es lo suficientemente rápida, grep podría no ser capaz de detener el proceso a tiempo (sin embargo, en realidad no importa), mientras que si la búsqueda es larga, no tendrá que imprimir mucho. líneas.
en cambio, esto funciona con busybox find, aunque como busybox grep también lo tiene, -m
no es realmente necesario
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
esto emitirá un mensaje sobre el proceso de búsqueda que ha recibido la señal (generalmente) sigterm, pero esta salida pertenece al shell en ejecución, no al comando de búsqueda, por lo que no se mete con la salida del comando, lo que significa que las tuberías o redireccionamientos generarán solo la línea emparejado por encontrar.