【问题标题】:How to read first n-th files from directory (pleaso NOT a "head -n solution")?如何从目录中读取第一个第 n 个文件(请不是“head -n 解决方案”)?
【发布时间】:2014-09-03 14:40:22
【问题描述】:

我有一个包含超过 60000 个文件的目录。如何在不使用find | head -nls | head -n 解决方案的情况下仅获取其中N 个,因为findls 读取此文件列表需要太多时间。有没有lsfind 的配置,或者有没有其他程序可以帮助节省时间?

【问题讨论】:

  • "find 和 ls 读取这个文件列表需要太多时间" 需要多长时间? 60000 个文件并不多。在我的系统上ls | head -n ... | tail -n ... 花费的时间远少于 1 秒。我们可能在这里缺少一些信息:您使用网络 FS 吗?还是您有一些关键时间要求?还有什么?
  • 您能否提供时间要求以及您尝试的运行时间。正如所写的那样,这个问题并没有多大意义,因为lsfind 的输出都将通过管道进行线路缓冲,并且您不会比| head -n 更快地获得管道解决方案

标签: bash find ls head tail


【解决方案1】:

物有所值:

# Create 60000 files
sh$ for i in {0..100}; do
    for j in {0..600}; do
        touch $(printf "%05d" $(($i+$j*100)));
    done;
done

在 Linux Debian Wheezy x86_64 w/ext4 文件系统上:

sh$ time bash -c 'ls | head -n 50000 | tail -10'
49990
49991
49992
49993
49994
49995
49996
49997
49998
49999

real    0m0.248s
user    0m0.212s
sys 0m0.024s


sh$ time bash -c 'ls -f | head -n 50000 | tail -10'
27235
02491
55530
44435
24255
47247
16033
45447
18434
35303

real    0m0.051s
user    0m0.016s
sys 0m0.028s


sh$ time bash -c 'find | head -n 50000 | tail -10'
./02491
./55530
./44435
./24255
./47247
./16033
./45447
./18434
./35303
./07658

real    0m0.051s
user    0m0.024s
sys 0m0.024s


sh$ time bash -c 'ls -f | sed -n 49990,50000p'
30950
27235
02491
55530
44435
24255
47247
16033
45447
18434
35303

real    0m0.046s
user    0m0.032s
sys 0m0.016s

当然,以下两个更快,因为它们只采用 first 条目(并且一旦所需的“行”,它们就会用 broken pipe 中断配对过程已阅读):

sh$ time bash -c 'ls -f | sed 1000q >/dev/null'

real    0m0.008s
user    0m0.004s
sys 0m0.000s


sh$ time bash -c 'ls -f | head -1000>/dev/null'

real    0m0.008s
user    0m0.000s
sys 0m0.004s

有趣的是(?)sed 我们将时间花在用户空间进程中,而head 则在 sys.跑了几次,结果还是一致的……

【讨论】:

    【解决方案2】:

    您可以用 C 编写自己的简单实用程序。

    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    
    int main(int argc, char **argv) {
      DIR *dir;
      struct dirent *ent;
      int i = 0, n = 0;
      n = atoi(argv[2]);
      dir = opendir(argv[1]);
      while ((ent = readdir(dir)) != NULL) {
        if (strcmp(ent->d_name, ".") == 0 ||
            strcmp(ent->d_name, "..") == 0)
          continue;
        if (i++ >= n) break;
        printf("%s\n", ent->d_name);
      }
      closedir(dir);
      return 0;
    }
    

    这只是一个快速而肮脏的初稿,但你明白了。

    【讨论】:

    • 这可能不会比find | head 快。你能提供时间吗?
    • @tripleee 如果您担心,请自行安排时间。我看不出用管道运行两个程序会比单个程序更快。不过,我也明白find|head 应该足够好了。重点是上面的程序写起来简单快捷。
    • 好吧,“快不了多少”。我的想法是开销在系统的readdir() 中,并且您无法通过使用裸 C 来解决该瓶颈,但是由于您已经编写了代码,因此如果我的猜想成立,将会很有趣。但我不打算进行测量。
    【解决方案3】:

    您可以将sedq 一起使用:

    find ... | sed 10q  ## Prints 1st to 10th line.
    

    这将使sed 在第 10 行之后退出,这可能会使find 更快地结束其功能。

    另一种方法是使用awk,但sed仍然更高效:

    find ... | awk 'NR==11{exit}1'
    

    或者

    find ... | awk '1;NR==10{exit}'
    

    【讨论】:

      【解决方案4】:
      ls -f directory | sed -n 1,10p       # print line 1-10
      

      ls的选项:

      -f: 不排序

      【讨论】:

      • 根据实施情况,即使sed 不再打印其输出,这仍可能允许find 在第 10 行之后继续。
      • 使用sed 10qsed -n 1,10p 快得多。 ls -ffind 快。在一个目录中使用 60.000 个 /etc/passwd 副本进行了测试。用 Ubuntu 测试。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多