Parece find
que tendría que verificar si una ruta determinada corresponde a un archivo o directorio de todos modos para recorrer recursivamente el contenido de los directorios.
Aquí hay algo de motivación y lo que he hecho localmente para convencerme de que find . -type f
realmente es más lento que find .
. Todavía no he profundizado en el código fuente de GNU find.
Así que estoy haciendo una copia de seguridad de algunos de los archivos en mi $HOME/Workspace
directorio y excluyendo los archivos que son dependencias de mis proyectos o archivos de control de versiones.
Entonces ejecuté el siguiente comando que se ejecutó rápidamente
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
canalizado a grep
puede ser de mal gusto, pero parecía que el camino más directo para utilizar un filtro de expresiones regulares negada.
El siguiente comando incluye solo archivos en la salida de find y tomó notablemente más tiempo.
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
Escribí un código para probar el rendimiento de estos dos comandos (con dash
y tcsh
, solo para descartar cualquier efecto que pueda tener el shell, aunque no debería haber ninguno). Los tcsh
resultados se han omitido porque son esencialmente los mismos.
Los resultados que obtuve mostraron una penalización de rendimiento del 10% por -type f
Aquí está la salida del programa que muestra la cantidad de tiempo necesario para ejecutar 1000 iteraciones de varios comandos.
% perl tester.pl
/bin/sh -c find Workspace/ >/dev/null
82.986582
/bin/sh -c find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
90.313318
/bin/sh -c find Workspace/ -type f >/dev/null
102.882118
/bin/sh -c find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
109.872865
Probado con
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
En Ubuntu 15.10
Aquí está el script perl que utilicé para la evaluación comparativa
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw[gettimeofday tv_interval];
my $max_iterations = 1000;
my $find_everything_no_grep = <<'EOF';
find Workspace/ >/dev/null
EOF
my $find_everything = <<'EOF';
find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
EOF
my $find_just_file_no_grep = <<'EOF';
find Workspace/ -type f >/dev/null
EOF
my $find_just_file = <<'EOF';
find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
EOF
my @finds = ($find_everything_no_grep, $find_everything,
$find_just_file_no_grep, $find_just_file);
sub time_command {
my @args = @_;
my $start = [gettimeofday()];
for my $x (1 .. $max_iterations) {
system(@args);
}
return tv_interval($start);
}
for my $shell (["/bin/sh", '-c']) {
for my $command (@finds) {
print "@$shell $command";
printf "%s\n\n", time_command(@$shell, $command);
}
}
fuente
find
que tendría que verificar si una ruta determinada corresponde a un archivo o directorio de todos modos para recorrer recursivamente el contenido de los directorios. - tendría que verificar si es un directorio, no tendría que verificar si es un archivo. Existen otros tipos de entradas: canalizaciones con nombre, enlaces simbólicos, dispositivos especiales de bloque, enchufes ... Por lo tanto, aunque ya haya realizado la comprobación para ver si es un directorio, no significa que sepa si es un archivo normal.-type f
y sin él. Pero al principio, el kernel de Linux lo cargó en caché y el primer hallazgo fue más lento.-type f
opción causadofind
a llamarstat()
ofstat()
o lo que sea con el fin de averiguar si el nombre de archivo corresponde a un archivo, un directorio, un enlace simbólico, etc, etc hice unastrace
en unafind .
y unafind . -type f
y la traza era casi idéntica, solo difiere en laswrite()
llamadas que tenían nombres de directorio en ellas. Entonces, no sé, pero quiero saber la respuesta.time
comando incorporado para ver cuánto tiempo tarda un comando en ejecutarse, realmente no necesitaba escribir un script personalizado para probar.Respuestas:
GNU find tiene una optimización que puede aplicarse
find .
pero no afind . -type f
: si sabe que ninguna de las entradas restantes en un directorio son directorios, entonces no se molesta en determinar el tipo de archivo (con lastat
llamada al sistema) a menos que uno de los los criterios de búsqueda lo requieren. Llamarstat
puede llevar un tiempo medible ya que la información generalmente está en el inodo, en una ubicación separada en el disco, en lugar de en el directorio que lo contiene.Como lo sabe Debido a que el recuento de enlaces en un directorio indica cuántos subdirectorios tiene. En los sistemas de archivos Unix típicos, el recuento de enlaces de un directorio es 2 más el número de directorios: uno para la entrada del directorio en su padre, uno para la
.
entrada y uno para la..
entrada en cada subdirectorio.La
-noleaf
opción le dice quefind
no aplique esta optimización. Esto es útil sifind
se invoca en algún sistema de archivos donde los recuentos de enlaces de directorio no siguen la convención de Unix.fuente
find
fuente, simplemente usafts_open()
yfts_read()
llama hoy en día.stat
llamadas cuando no las necesita debido al recuento de enlaces del directorio, y la-noleaf
opción está documentada en el manual.stat
incluso en lafts...
versión: pasa la bandera apropiada para eso a lafts_open
llamada. Pero lo que no estoy seguro es pertinente es la verificación con el número de enlaces. En su lugar, verifica si el registro fts devuelto tiene uno de los indicadores de "directorio". Es posible quefts_read
compruebe los enlaces para establecer esa bandera, perofind
no lo hace. Puede ver si su versión se basafts
llamandofind --version
.find
podría determinar cuándo todas las entradas en un directorio son directorios también y usar esa información?