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 que time 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 resultado find, mientras que coincide con find -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 significaba find -name filename. Con find filename, solo se examinaría filename (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

  • find filename devolvería solo filename si filename no fuera del tipo directorio (o fuera del tipo directorio, pero no tenía ninguna entrada)

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 llamado jack, o todos los nombres en el directorio si es ‘ un directorio. Es ‘ un malentendido de cómo funciona find.

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 de find …)
  • @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' ralentiza find? 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.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *