Probé ambos comandos y el comando find | grep "filename"
es muchas veces más lento que el simple find "filename"
comando.
¿Cuál sería una explicación adecuada para este comportamiento?
Comentarios
- Usted están enumerando cada archivo con find y luego pasando los datos a grep para que los procese. Con find usado en él ‘ propio, se está perdiendo el paso de pasar cada archivo listado a grep para analizar la salida. Por tanto, esto será más rápido.
- ¿Más lento en qué sentido? ¿Los comandos toman una cantidad de tiempo diferente para completarse?
- No puedo ‘ t reproducir esto localmente. En todo caso,
time find "$HOME" -name '.profile'
informa un tiempo más largo quetime find "$HOME" | grep -F '.profile'
. (17 vs 12). - @JenniferAnderson Corrí ambos repetidamente. Los 17 y 12 segundos son promedios. Y sí, la variación
grep
coincidirá en cualquier lugar del resultadofind
, mientras que coincide confind -name
solo coincidiría exactamente (en este caso). - Sí,
find filename
sería rápido . Supuse que se trataba de un error tipográfico y que el OP significabafind -name filename
. Confind filename
, solo se examinaríafilename
(y nada más).
Respuesta
(Asumo que GNU find
aquí)
Usando solo
find filename
sería rápido, porque solo devolvería filename
, o los nombres dentro de filename
si es un directorio, o un error si ese nombre no existe en el directorio actual. Es una operación muy rápida, similar a ls filename
(pero recursiva si filename
es un directorio).
En Por el contrario,
find | grep filename
permitiría find
generar una lista de todos nombres de el directorio actual y debajo, que grep
luego filtraría. Obviamente, esto sería una operación mucho más lenta.
Estoy asumiendo que lo que fue en realidad previsto era
find . -type f -name "filename"
Esto buscaría filename
como el nombre de un archivo normal en cualquier lugar el directorio actual o inferior.
Esto será tan rápido (o comparablemente rápido) como find | grep filename
, pero el grep
la solución haría coincidir filename
con la ruta completa de cada nombre encontrado, de manera similar a lo que haría -path "*filename*"
con find
.
La confusión proviene de un malentendido de cómo find
funciona.
La utilidad toma una serie de rutas y devuelve todos los nombres debajo de estas rutas.
Puede entonces restringir los nombres devueltos mediante varias pruebas que pueden actuar sobre el nombre del archivo, la ruta, la marca de tiempo, el tamaño del archivo, el tipo de archivo, etc.
Cuando dices
find a b c
le pide a find
que enumere todos los nombres disponibles en las tres rutas a
, b
y c
. Si resulta que son nombres de archivos normales en el directorio actual, se devolverán. Si alguno de ellos es el nombre de un directorio, se devolverá junto con todos los demás nombres dentro de ese directorio.
Cuando lo haga
find . -type f -name "filename"
Esto genera una lista de todos los nombres en el directorio actual (.
) y más abajo. Luego restringe los nombres a los de archivos normales, es decir, no a directorios, etc., con -type f
. Luego hay una restricción adicional para los nombres que coinciden con filename
usando -name "filename"
. La cadena filename
puede ser un patrón global de nombre de archivo, como *.txt
(¡solo recuerde citarlo!).
Ejemplo:
Lo siguiente parece «encontrar» el archivo llamado .profile
en mi directorio de inicio:
$ pwd /home/kk $ find .profile .profile
Pero de hecho, solo devuelve todos los nombres en la ruta .profile
(solo hay un nombre, y ese es el de este archivo).
Luego cd
subo un nivel y vuelvo a intentar:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
El find
comando ahora no puede encontrar ninguna ruta llamada .profile
.
Sin embargo, si consigo que mire el directorio actual y luego restringir los nombres devueltos a solo .profile
, encuentra desde allí también:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Comentarios
Respuesta
Explicación no técnica: buscar a Jack entre la multitud es más rápido que buscar a todos en una multitud y eliminar a todos de la consideración excepto a Jack.
Comentarios
- El problema es que el OP espera que Jack sé la única persona en la multitud. Si es así, ‘ tienen suerte.
find jack
enumerarájack
si es ‘ un archivo llamadojack
, o todos los nombres en el directorio si es ‘ un directorio. Es ‘ un malentendido de cómo funcionafind
.
Respuesta
Aún no he entendido el problema, pero puedo proporcionar más información.
Al igual que para Kusalananda, la find | grep
llamada es claramente más rápido en mi sistema, lo que no tiene mucho sentido. Al principio asumí algún tipo de problema de almacenamiento en búfer; que escribir en la consola ralentiza el tiempo hasta la siguiente llamada al sistema para leer el siguiente nombre de archivo. Escribir en una tubería es muy rápido: alrededor de 40MiB / s incluso para escrituras de 32 bytes (en mi sistema bastante lento; 300 MiB / s para un tamaño de bloque de 1MiB). Por lo tanto, asumí que find
puede leer desde el sistema de archivos más rápido al escribir en una tubería (o archivo) para que las dos operaciones que leen las rutas de los archivos y escriban en la consola se puedan ejecutar en paralelo ( que find
como un proceso de un solo hilo no puede hacer por sí solo.
Es «s find
«s error
Comparando las dos llamadas
:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s
y
:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s
muestra que find
hace algo increíblemente estúpido (sea lo que sea). Simplemente resulta ser bastante incompetente para ejecutar -name "*.txt"
.
Podría depender de la relación entrada / salida
Puede pensar que find -name
gana si hay muy poco que escribir. Pero esto se vuelve más vergonzoso para find
. Pierde incluso si no hay nada que escribir contra 200K archivos (13M de datos de canalizaciones) para grep
:
time find /usr -name lwevhewoivhol
find
puede ser tan rápido como grep
, aunque
Resulta que la estupidez de find
«con name
no se extiende a otras pruebas. Use una expresión regular en su lugar y el problema desaparecerá:
:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s
Supongo que esto puede considerarse un error. ¿Alguien está dispuesto a presentar un informe de error? Mi versión es find (GNU findutils) 4.6.0
Comentarios
- ¿Qué tan repetibles son sus tiempos? Si primero hizo la prueba
-name
, es posible que haya sido más lenta debido a que el contenido del directorio no se almacenó en caché. (Al probar-name
y-regex
, encuentro que toman aproximadamente el mismo tiempo, al menos una vez que se ha tenido en cuenta el efecto de caché. Por supuesto, puede ser una versión diferente defind
…) - @psmears Por supuesto, he realizado estas pruebas varias veces. El problema del almacenamiento en caché se ha mencionado incluso en los comentarios a la pregunta antes de la primera respuesta. Mi
find
versión es find (GNU findutils) 4.6.0 - ¿Por qué es sorprendente que agregar
-name '*.txt'
ralentizafind
? Tiene que hacer un trabajo adicional, probando cada nombre de archivo. - @Barmar Por un lado, este trabajo adicional se puede hacer extremadamente rápido. Por otro lado, este trabajo adicional ahorra otro trabajo.
find
tiene que escribir menos datos. Y escribir en una tubería es una operación mucho más lenta. - Escribir en un disco es muy lento, escribir en una tubería no es tan malo, simplemente se copia en un búfer del kernel. Observe que en su primera prueba, escribir más en
/dev/null
de alguna manera usó menos tiempo del sistema.
Respuesta
Aviso : Asumiré que te refieres a find . -name filename
(de lo contrario, «estás buscando cosas diferentes; find filename
en realidad busca en una ruta llamada nombre de archivo , que puede no contener casi ningún archivo, por lo que se cierra muy rápido).
Suponga que tiene un directorio que contiene cinco mil archivos. En la mayoría de los sistemas de archivos, estos archivos se almacenan en una estructura de árbol , que permite localizar rápidamente cualquier archivo determinado.
Entonces, cuando le pida a find
que ubique un archivo cuyo nombre solo requiere verificación, find
le preguntará para ese archivo, y solo ese archivo, en el sistema de archivos subyacente, que leerá muy pocas páginas del almacenamiento masivo. Entonces, si el sistema de archivos vale la pena, esta operación se ejecutará mucho más rápido que atravesando todo el árbol para recuperar todas las entradas.
Cuando solicita find
sin formato, sin embargo, eso es exactamente lo que hace, recorre todo el árbol, leyendo. Every. Single. Entry. Con grandes directorios, esto podría ser un problema (es exactamente la razón por la que varios softwares, que necesitan almacenar muchos archivos en el disco, crearán «árboles de directorios» con dos o tres componentes de profundidad: de esta manera, cada hoja solo necesita contener menos archivos) .
Respuesta
Supongamos que el archivo / john / paul / george / ringo / beatles existe y el archivo que está buscando se llama «piedras»
find / stones
find comparará «beatles» con «piedras» y lo dejará caer cuando la «s» y la «b» no coincidan .
find / | grep stones
En este caso, find pasará «/ john / paul / george / ringo / beatles» a grep y grep wil Tengo que recorrer toda la ruta antes de determinar si coincide.
grep, por lo tanto, está haciendo mucho más trabajo, por lo que lleva más tiempo
Comentarios
- ¿Lo ha intentado?
- El costo de las comparaciones de cadenas (extremadamente simples y baratas) es completamente eclipsado por el costo de IO (o simplemente syscall si está almacenado en caché) de las búsquedas de directorio.
- grep no es ‘ una comparación de cadenas, su comparación de expresiones regulares, lo que significa que tiene que recorrer toda la cadena hasta que encuentre un partido o llega al final. Las búsquedas de directorio son las mismas sin importar qué.
- @Paranoid Hm, ¿de qué versión de encontrar estás hablando? Aparentemente, ‘ no se parece en nada al encontrar que ‘ solía usar en Debian.
find filename
devolvería solofilename
sifilename
no fuera del tipo directorio (o fuera del tipo directorio, pero no tenía ninguna entrada)