【问题标题】:Quick ls command快速 ls 命令
【发布时间】:2010-09-07 14:23:12
【问题描述】:

我必须得到一个包含大约 200 万个文件的目录列表,但是当我对其执行 ls 命令时,什么也没有返回。我等了3个小时。我试过ls | tee directory.txt,但这似乎永远挂起。

我假设服务器正在进行大量的 inode 排序。有什么方法可以加快ls 命令的速度,以获取文件名的目录列表?我现在不关心大小、日期、权限等。

【问题讨论】:

    标签: bash unix command ls


    【解决方案1】:
    ls -U
    

    将执行 ls 而不进行排序。

    【讨论】:

    • 你知道ls -U|sort是否比ls快吗?
    • 我不知道。我对此表示怀疑,因为在查看所有记录之前,排序无法完成,无论它是在ls 中的单独程序中完成的。但找出答案的唯一方法就是测试它。
    • 注意:在某些系统上,ls -f 等价于ls -aU;即,包含 all 文件(即使是那些名称以“.”开头的文件)并且不排序。而在一些系统上,-f选项来抑制排序,而-U做其他事情(或什么都不做)。跨度>
    • 不适用于 BSD。在 BSD 上 -U 按文件创建时间排序。
    【解决方案2】:

    我有一个目录,里面有 400 万个文件,我让 ls 立即吐出文件而无需先进行大量搅动的唯一方法是

    ls -1U
    

    【讨论】:

    • 拯救了我的一天!谢谢!
    • 对于网络安装驱动器上的大文件夹(例如 google-drive-ocamlfuse 上的 Google Drive)绝对至关重要
    • ls -1f 对我来说似乎比 ls -1U 好很多。它们的输出速度相似,但 ls -1U 似乎不可中断。
    • 不间断?它正在将输出写入终端,任何取消/ctrl-c/etc 的尝试都与您的终端有关,而不是与 ls 相关。
    【解决方案3】:

    尝试使用:

    find . -type f -maxdepth 1
    

    这只会列出目录中的文件,如果您想列出文件和目录,请忽略 -type f 参数。

    【讨论】:

      【解决方案4】:

      这个问题似乎很有趣,我查看了发布的多个答案。为了了解发布的答案的效率,我对 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
      
      ------------------------------------------------------
      

      总结结果

      1. ls -f 命令的运行速度比 ls -U 快一点。禁用颜色可能会导致这种改进。
      2. find 命令以 2.738 秒的平均速度运行第三。
      3. 仅运行 ls 耗时 42.16 秒。在我的系统中lsls --color=auto 的别名
      4. 使用带有 echo ./* 的 shell 扩展功能运行了 50.80 秒。
      5. 而基于 tar 的解决方案耗时约 37 分钟。

      所有测试都是在系统处于空闲状态时单独进行的。

      这里要注意的重要一点是文件列表不会打印在终端中,而是 它们被重定向到一个文件,稍后使用wc 命令计算文件计数。 如果输出打印在屏幕上,则命令运行速度太慢。

      任何想法为什么会发生这种情况?

      【讨论】:

      • 终端很慢,必须滚动和格式化,文件写入到块设备,实际上,它们首先进入页面缓存,所以你真的只是在写入内存,这比终端快。
      【解决方案5】:

      这将是最快的选项 AFAIK:ls -1 -f

      • -1(无列)
      • -f(不排序)

      【讨论】:

      • 这适用于macOS (BSD) 和Linux
      【解决方案6】:

      使用

      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;
      

      【讨论】:

        【解决方案7】:

        您可以重定向输出并在后台运行 ls 进程。

        ls > myls.txt &
        

        这将允许您在业务运行的同时继续开展业务。它不会锁定你的外壳。

        不确定运行 ls 和获取较少数据的选项有哪些。您可以随时运行man ls 进行检查。

        【讨论】:

          【解决方案8】:

          这可能不是一个有用的答案,但如果您没有find,您可以使用tar

          $ tar cvf /dev/null .
          

          比我年长的人告诉我,“在过去”,单用户和恢复环境比现在更受限制。这就是这个技巧的由来。

          【讨论】:

            【解决方案9】:

            我假设您使用的是 GNU ls? 试试

            \ls
            

            它将取消通常的 ls (ls --color=auto) 的别名。

            【讨论】:

            • 没错,着色是我通常的罪魁祸首:着色时,ls 尝试确定每个目录条目的类型和模式,导致大量 stat(2) 调用,从而导致大量磁盘活动.
            【解决方案10】:

            如果一个进程“没有回来”,我推荐strace 来分析一个进程是如何与操作系统交互的。

            如果是 ls:

            $strace ls
            

            您会看到它在实际输出任何内容之前读取了所有目录条目 (getdents(2))。 (排序……正如这里已经提到的)

            【讨论】:

              【解决方案11】:

              要尝试的事情:

              检查 ls 没有别名?

              alias ls
              

              或许可以尝试使用 find 代替?

              find . \( -type d -name . -prune \) -o \( -type f -print \)
              

              希望这会有所帮助。

              【讨论】:

                【解决方案12】:

                一些后续: 您没有提及您正在运行的操作系统,这将有助于指示您正在使用的 ls 版本。这可能不像 ls 问题那样是“bash”问题。我的猜测是您使用的是 GNU ls,它具有一些在某些情况下有用的功能,但在大目录中会杀死您。

                GNU ls 试图对列进行更漂亮的排列。 GNU ls 尝试对所有文件名进行智能排列。在一个巨大的目录中,这将需要一些时间和内存。

                要“解决”这个问题,您可以尝试:

                ls -1 # 根本没有列

                在某个地方找到 BSD ls http://www.freebsd.org/cgi/cvsweb.cgi/src/bin/ls/ 并将其用于您的大目录。

                使用其他工具,例如查找

                【讨论】:

                  【解决方案13】:

                  有几种方法可以获取文件列表:

                  使用此命令获取不排序的列表:

                  ls -U
                  

                  或使用以下命令将文件列表发送到文件:

                  ls /Folder/path > ~/Desktop/List.txt
                  

                  【讨论】:

                    【解决方案14】:

                    您使用的是什么分区类型?

                    在一个目录中有数百万个小文件,使用 JFS 或 ReiserFS 可能是个好主意,因为它们对许多小文件有更好的性能。

                    【讨论】:

                      【解决方案15】:

                      find ./ -type f 怎么样(它将找到当前目录中的所有文件)?取下-type f 即可找到所有内容。

                      【讨论】:

                      • 这将在当前目录以及任何子目录中查找文件。
                      【解决方案16】:

                      您应该提供有关您正在使用的操作系统和文件系统类型的信息。在某些 UNIX 风格和某些文件系统上,您可能可以使用命令 ffncheck 作为替代。

                      【讨论】:

                        【解决方案17】:

                        我有一个文件名中带有时间戳的目录。我想查看最新文件的日期,发现find . -type f -maxdepth 1 | sort | tail -n 1 的速度大约是ls -alh 的两倍。

                        【讨论】:

                          【解决方案18】:

                          这里有很多其他好的解决方案,但为了完整性:

                          echo *
                          

                          【讨论】:

                          • 有 200 万个文件,很可能只返回“命令行太长”错误。
                          【解决方案19】:

                          您也可以使用 xargs。只需将 ls 的输出通过 xargs 传递。

                          ls | xargs
                          

                          如果这不起作用并且上面的 find 示例不起作用,请尝试将它们通过管道传送到 xargs,因为它可以帮助内存使用,这可能会导致您的问题。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2012-06-10
                            • 2013-05-22
                            • 2014-05-25
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2017-08-09
                            • 2018-01-03
                            相关资源
                            最近更新 更多