【发布时间】:2010-09-07 14:23:12
【问题描述】:
我必须得到一个包含大约 200 万个文件的目录列表,但是当我对其执行 ls 命令时,什么也没有返回。我等了3个小时。我试过ls | tee directory.txt,但这似乎永远挂起。
我假设服务器正在进行大量的 inode 排序。有什么方法可以加快ls 命令的速度,以获取文件名的目录列表?我现在不关心大小、日期、权限等。
【问题讨论】:
我必须得到一个包含大约 200 万个文件的目录列表,但是当我对其执行 ls 命令时,什么也没有返回。我等了3个小时。我试过ls | tee directory.txt,但这似乎永远挂起。
我假设服务器正在进行大量的 inode 排序。有什么方法可以加快ls 命令的速度,以获取文件名的目录列表?我现在不关心大小、日期、权限等。
【问题讨论】:
ls -U
将执行 ls 而不进行排序。
【讨论】:
ls -U|sort是否比ls快吗?
ls 中的单独程序中完成的。但找出答案的唯一方法就是测试它。
ls -f 等价于ls -aU;即,包含 all 文件(即使是那些名称以“.”开头的文件)并且不排序。而在一些系统上,-f是选项来抑制排序,而-U做其他事情(或什么都不做)。跨度>
-U 按文件创建时间排序。
我有一个目录,里面有 400 万个文件,我让 ls 立即吐出文件而无需先进行大量搅动的唯一方法是
ls -1U
【讨论】:
尝试使用:
find . -type f -maxdepth 1
这只会列出目录中的文件,如果您想列出文件和目录,请忽略 -type f 参数。
【讨论】:
这个问题似乎很有趣,我查看了发布的多个答案。为了了解发布的答案的效率,我对 200 万个文件执行了它们,发现结果如下。
$ time tar cvf /dev/null . &> /tmp/file-count
real 37m16.553s
user 0m11.525s
sys 0m41.291s
------------------------------------------------------
$ time echo ./* &> /tmp/file-count
real 0m50.808s
user 0m49.291s
sys 0m1.404s
------------------------------------------------------
$ time ls &> /tmp/file-count
real 0m42.167s
user 0m40.323s
sys 0m1.648s
------------------------------------------------------
$ time find . &> /tmp/file-count
real 0m2.738s
user 0m1.044s
sys 0m1.684s
------------------------------------------------------
$ time ls -U &> /tmp/file-count
real 0m2.494s
user 0m0.848s
sys 0m1.452s
------------------------------------------------------
$ time ls -f &> /tmp/file-count
real 0m2.313s
user 0m0.856s
sys 0m1.448s
------------------------------------------------------
总结结果
ls -f 命令的运行速度比 ls -U 快一点。禁用颜色可能会导致这种改进。find 命令以 2.738 秒的平均速度运行第三。 ls 耗时 42.16 秒。在我的系统中ls 是ls --color=auto 的别名
echo ./* 的 shell 扩展功能运行了 50.80 秒。tar 的解决方案耗时约 37 分钟。所有测试都是在系统处于空闲状态时单独进行的。
这里要注意的重要一点是文件列表不会打印在终端中,而是
它们被重定向到一个文件,稍后使用wc 命令计算文件计数。
如果输出打印在屏幕上,则命令运行速度太慢。
任何想法为什么会发生这种情况?
【讨论】:
这将是最快的选项 AFAIK:ls -1 -f。
-1(无列)-f(不排序)【讨论】:
macOS (BSD) 和Linux
使用
ls -1 -f
大约快 10 倍,而且很容易做到(我测试了 100 万个文件,但我最初的问题是 6 800 000 000 个文件)
但就我而言,我需要检查某个特定目录是否包含超过 10 000 个文件。如果有超过 10 000 个文件,我不再对有多少文件感兴趣。我只是退出了该程序,以便它运行得更快,并且不会尝试一一阅读其余内容。如果少于 10 000,我将打印确切的数量。如果您为参数指定的值大于文件数量,我的程序的速度与 ls -1 -f 非常相似。
你可以在当前目录中使用我的程序 find_if_more.pl,输入:
find_if_more.pl 999999999
如果您只是对有 n 个以上的文件感兴趣,那么脚本将比 ls -1 -f 更快地完成大量文件。
#!/usr/bin/perl
use warnings;
my ($maxcount) = @ARGV;
my $dir = '.';
$filecount = 0;
if (not defined $maxcount) {
die "Need maxcount\n";
}
opendir(DIR, $dir) or die $!;
while (my $file = readdir(DIR)) {
$filecount = $filecount + 1;
last if $filecount> $maxcount
}
print $filecount;
closedir(DIR);
exit 0;
【讨论】:
您可以重定向输出并在后台运行 ls 进程。
ls > myls.txt &
这将允许您在业务运行的同时继续开展业务。它不会锁定你的外壳。
不确定运行 ls 和获取较少数据的选项有哪些。您可以随时运行man ls 进行检查。
【讨论】:
这可能不是一个有用的答案,但如果您没有find,您可以使用tar
$ tar cvf /dev/null .
比我年长的人告诉我,“在过去”,单用户和恢复环境比现在更受限制。这就是这个技巧的由来。
【讨论】:
我假设您使用的是 GNU ls? 试试
\ls
它将取消通常的 ls (ls --color=auto) 的别名。
【讨论】:
ls 尝试确定每个目录条目的类型和模式,导致大量 stat(2) 调用,从而导致大量磁盘活动.
如果一个进程“没有回来”,我推荐strace 来分析一个进程是如何与操作系统交互的。
如果是 ls:
$strace ls
您会看到它在实际输出任何内容之前读取了所有目录条目 (getdents(2))。 (排序……正如这里已经提到的)
【讨论】:
要尝试的事情:
检查 ls 没有别名?
alias ls
或许可以尝试使用 find 代替?
find . \( -type d -name . -prune \) -o \( -type f -print \)
希望这会有所帮助。
【讨论】:
一些后续: 您没有提及您正在运行的操作系统,这将有助于指示您正在使用的 ls 版本。这可能不像 ls 问题那样是“bash”问题。我的猜测是您使用的是 GNU ls,它具有一些在某些情况下有用的功能,但在大目录中会杀死您。
GNU ls 试图对列进行更漂亮的排列。 GNU ls 尝试对所有文件名进行智能排列。在一个巨大的目录中,这将需要一些时间和内存。
要“解决”这个问题,您可以尝试:
ls -1 # 根本没有列
在某个地方找到 BSD ls http://www.freebsd.org/cgi/cvsweb.cgi/src/bin/ls/ 并将其用于您的大目录。
使用其他工具,例如查找
【讨论】:
有几种方法可以获取文件列表:
使用此命令获取不排序的列表:
ls -U
或使用以下命令将文件列表发送到文件:
ls /Folder/path > ~/Desktop/List.txt
【讨论】:
您使用的是什么分区类型?
在一个目录中有数百万个小文件,使用 JFS 或 ReiserFS 可能是个好主意,因为它们对许多小文件有更好的性能。
【讨论】:
find ./ -type f 怎么样(它将找到当前目录中的所有文件)?取下-type f 即可找到所有内容。
【讨论】:
我有一个文件名中带有时间戳的目录。我想查看最新文件的日期,发现find . -type f -maxdepth 1 | sort | tail -n 1 的速度大约是ls -alh 的两倍。
【讨论】:
这里有很多其他好的解决方案,但为了完整性:
echo *
【讨论】:
您也可以使用 xargs。只需将 ls 的输出通过 xargs 传递。
ls | xargs
如果这不起作用并且上面的 find 示例不起作用,请尝试将它们通过管道传送到 xargs,因为它可以帮助内存使用,这可能会导致您的问题。
【讨论】: