似乎find
必须检查给定路径是否对应于文件或目录,以便递归地遍历目录的内容。
这是一些动机以及我在本地所做的事情,以说服自己find . -type f
确实比find .
.我还没有深入研究 GNU find 源代码。
因此,我备份了目录中的一些文件$HOME/Workspace
,并排除了项目依赖项或版本控制文件的文件。
所以我运行了以下命令,该命令执行得很快
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
通过管道传输grep
可能是不好的形式,但这似乎是使用否定正则表达式过滤器的最直接方法。
以下命令仅包含 find 输出中的文件,并且花费的时间明显更长。
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
我编写了一些代码来测试这两个命令的性能(使用dash
和tcsh
,只是为了排除 shell 可能产生的任何影响,即使不应该有任何影响)。结果tcsh
已被省略,因为它们本质上是相同的。
我得到的结果显示大约 10% 的性能损失-type f
下面是程序的输出,显示了执行各种命令 1000 次迭代所需的时间。
% 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
测试用
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
在 Ubuntu 15.10 上
这是我用于基准测试的 perl 脚本
#!/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);
}
}
答案1
GNU find 有一个优化,可以应用于find .
但不能应用于find . -type f
:如果它知道目录中的剩余条目都不是目录,那么它不会费心确定文件类型(使用系统stat
调用),除非其中之一搜索条件需要它。调用stat
可能需要相当长的时间,因为信息通常位于磁盘上单独位置的 inode 中,而不是位于包含的目录中。
它是怎么知道的?因为目录上的链接计数表明它有多少个子目录。在典型的 Unix 文件系统上,目录的链接计数为 2 加上目录数:1 个用于其父目录中的目录条目,1 个用于条目.
,1 个用于..
每个子目录中的条目。
该-noleaf
选项指示find
不应用此优化。如果find
在目录链接计数不遵循 Unix 约定的某些文件系统上调用,这非常有用。