【问题标题】:Recursively counting files in a Linux directory递归计算Linux目录中的文件
【发布时间】:2012-02-27 18:03:32
【问题描述】:

如何递归计算 Linux 目录中的文件数?

我发现了这个:

find DIR_NAME -type f ¦ wc -l

但是当我运行它时,它会返回以下错误。

查找:路径必须在表达式之前:¦

【问题讨论】:

  • 您将虚线¦ (ASCII 166) 与用于UNIX pipeline 的竖线| (ASCII 124) 混淆了。
  • @SkippyleGrandGourou 不是叫管道吗?
  • @DaveStephens 是的,它也被称为。它也被称为 Sheffer stroke、verti-bar、vbar、stick、vertical line、vertical slash、bar、obelisk、glidus。
  • @zenith 我就叫它 Bob。
  • 在 RFC20 中它被称为“垂直线”。 “管道”是 shell 运算符的名称,而不是符号的名称。正如* 是“星号”ASCII 字符,但在其他一些上下文中是“次”。

标签: linux


【解决方案1】:

这应该可行:

find DIR_NAME -type f | wc -l

说明:

  • -type f 仅包含文件。
  • |而不是¦)将find 命令的标准输出重定向到wc 命令的标准输入。
  • wc(word count 的缩写)在其输入 (docs) 上计算换行符、单词和字节数。
  • -l 只计算换行符。

注意事项:

  • DIR_NAME 替换为. 以在当前文件夹中执行命令。
  • 您还可以删除 -type f 以在计数中包含目录(和符号链接)。
  • 如果文件名可以包含换行符,则此命令可能会过度计数。

解释为什么您的示例不起作用:

在您显示的命令中,您没有使用“管道”(|)来连接两个命令,而是使用 shell 无法识别为命令或其他东西的断线(¦)相似的。这就是您收到该错误消息的原因。

【讨论】:

  • 删除-type f 以将目录包含在计数中
  • 有更快的方法吗?因为如果你把它应用到 / 上确实需要一些时间
  • 如果文件名可能包含换行符,您可能需要使用-print0 标志。
  • @gaboroncancio 这不会有帮助,除非wc 的某些实现具有读取空终止列表的选项。请参阅我的答案以获取替代方案。
  • 如果您的文件中有换行符,您仍然可以使用 find 通过使用 -exec 而不是打印来执行此操作:find . -type f -exec echo \; | wc -l。这样,您实际上并没有输出文件名,而是输出每个遇到的文件一个空行,而不管名称如何,因此行数在任何情况下都有效。如果只计算空字符,print0 也可以工作:find . -type f -print0 | tr -dc '\0' | wc -c。在这种情况下,tr 删除所有非空字符并 wc 计算输入它的字符。
【解决方案2】:

对于当前目录:

find -type f | wc -l

【讨论】:

  • 此解决方案不考虑包含换行符的文件名。
  • 对于当前目录,你甚至不需要.
  • 其实在某些平台上,你确实需要拼出find .
  • @Kusalanandra 您的评论几乎适用于这里的所有答案。
【解决方案3】:

要确定当前目录中有多少文件,请输入ls -1 | wc -l。这使用wc 来计算ls -1 输出中(-l) 的行数。它不计算点文件。请注意,我在本 HOWTO 的先前版本中使用的ls -l(这是一个“L”而不是前面示例中的“1”)实际上会给你一个比实际计数大一的文件计数。感谢 Kam Nejad 提出这一点。

如果你只想计算文件而不包括符号链接(只是你可以做的一个例子),你可以使用ls -l | grep -v ^l | wc -l(这次是“L”而不是“1”,我们想要一个“长”列表在这里)。 grep 检查任何以“l”开头的行(表示链接),并丢弃该行 (-v)。

相对速度:“ls -1 /usr/bin/ | wc -l”在卸载的 486SX25 上大约需要 1.03 秒(这台机器上的 /usr/bin/ 有 355 个文件)。 “ls -l /usr/bin/ | grep -v ^l | wc -l”大约需要 1.19 秒。

来源:http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x700.html

【讨论】:

  • ls -l 必须对每个文件执行stat 系统调用以读取其大小、mtime 和其他属性,这很慢。在运行 ls -l 的大目录(100.000+ 个文件)上可能需要几分钟时间。所以只计算文件,总是使用ls -1 | wc -l
  • 486SX25,不错
  • ls -1 在大目录中仍然可能很慢,因为它必须对文件进行排序。只需printf '%s\n' * 做同样的事情,并避免外部ls 调用(无论如何是problematic),但最有效的解决方案是使用不执行任何排序的命令,例如find。 (glob 输出按 shell 排序。)
  • 当我在一个文件夹中只使用一个文件时,答案是 2。
【解决方案4】:

如果您想了解当前目录下每个目录中有多少文件:

for i in */ .*/ ; do 
    echo -n $i": " ; 
    (find "$i" -type f | wc -l) ; 
done

当然,这可以全部放在一条线上。括号阐明了谁的输出 wc -l 应该正在观看(在本例中为 find $i -type f)。

【讨论】:

  • 它可能会卡在名称中带有空格的目录上。将第一行更改为 find . -maxdepth 1 -type d -print0 | while IFS= read -r -d '' i ; do 可以修复它。见How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
  • find 用于外部循环只是一个不必要的复杂化。 for i in */;做`
  • function countit { for i in $(find . -maxdepth 1 -type d) ;做 file_count=$(find $i -type f | wc -l) ; echo "$file_count: $i" ;完毕 };计数 |排序 -n -r
  • 最后这就是我需要的。我的文件夹有数千个文件,所以不能用树或其他任何东西打印它们
  • 这包括 ../ 并且似乎没有前进 - 这意味着它不是回归的。
【解决方案5】:

你可以使用

$ tree

在安装 tree 软件包后使用

$ sudo apt-get install tree

(在 Debian / Mint / Ubuntu Linux 机器上)。

该命令不仅显示文件的数量,还分别显示目录的数量。选项 -L 可用于指定最大显示级别(默认为目录树的最大深度)。

通过提供-a 选项也可以包含隐藏文件。

【讨论】:

  • 这实际上是查看目录和文件数量的最简单方法。
  • 来自手册页:默认情况下树不打印隐藏文件。您必须提供 -a 选项才能包含它们。
  • 要在 macOS 上安装它,请使用 brew 并运行 brew install tree,最好在运行 brew update 之后。
  • 它还打印所有文件名,所以如果你有很多文件,它会很慢。
  • 哇,非常不错的工具,它可以打印彩色文件夹,只列出文件夹,输出为 JSON。它可以在几秒钟内列出 34k 个文件夹和 51k 个文件。奥莱!
【解决方案6】:

如果你想知道当前工作目录中有多少文件和子目录,你可以使用这个单行

find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find {} | wc -l) {}' | sort -n

这将在 GNU 风格中工作,并且只需在 BSD linux(例如 OSX)的 echo 命令中省略 -e。

【讨论】:

  • 优秀的解决方案!我发现的唯一问题是带有空格或特殊字符的目录。在使用目录名称的地方添加引号:find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find "{}" | wc -l) "{}"' | sort -n
  • 我对其进行了一些修改,对我来说效果很好:find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo $(find {} | wc -l) \\t {}' | sort -rn | less
  • 我在@Sebastian 的回答中的cmets 也适用于此。在未加引号的目录名称上使用echo -e(或只是前面评论中的`echo`)会以一个问题换另一个问题。
【解决方案7】:

如果您想避免错误情况,请不要让wc -l 看到带有换行符的文件(这将被视为 2+ 个文件)

例如考虑一个例子,我们有一个文件,里面有一个 EOL 字符

> mkdir emptydir && cd emptydir
> touch $'file with EOL(\n) character in it'
> find -type f
./file with EOL(?) character in it
> find -type f | wc -l
2

由于至少 gnu wc 似乎没有读取/计数空终止列表(文件除外)的选项,因此最简单的解决方案就是不传递文件名,而是每次都传递静态输出找到一个文件,例如和上面一样的目录

> find -type f -exec printf '\n' \; | wc -l
1

或者如果您的find 支持它

> find -type f -printf '\n' | wc -l
1 

【讨论】:

    【解决方案8】:

    将这里的几个答案组合在一起,最有用的解决方案似乎是:

    find . -maxdepth 1 -type d -print0 |
    xargs -0 -I {} sh -c 'echo -e $(find "{}" -printf "\n" | wc -l) "{}"' |
    sort -n
    

    它可以处理奇怪的事情,例如包含空格括号甚至换行的文件名。它还按文件数对输出进行排序。

    您也可以增加-maxdepth 后面的数字来计算子目录。请记住,这可能需要很长时间,特别是如果您有一个高度嵌套的目录结构和一个高 -maxdepth 数字。

    【讨论】:

    • echo -e 是怎么回事?我猜你把它放进去折叠任何换行符,但它也会破坏任何其他不规则的空格,并尝试扩展文件名中逐字存在的任何通配符。我会简单地使用 find .* * -type d -execdir sh -c 'find . -type f -printf "\n" | wc -l; pwd' 之类的东西,并忍受输出中的任何异常,或者使用 Bash 的 printf "%q" 来打印目录名称。
    • 这是一次执行多个目录并使用空白捕获目录的最佳答案!
    【解决方案9】:

    这种过滤格式的替代方法会计算所有可用的 grub 内核模块:

    ls -l /boot/grub/*.mod | wc -l
    

    【讨论】:

      【解决方案10】:

      在我的电脑上,rsync 在接受的答案中比find | wc -l 快一点:

      $ rsync --stats --dry-run -ax /path/to/dir /tmp
      
      Number of files: 173076
      Number of files transferred: 150481
      Total file size: 8414946241 bytes
      Total transferred file size: 8414932602 bytes
      

      第二行是文件的数量,在上面的例子中是 150,481。作为奖励,您还可以获得总大小(以字节为单位)。

      备注:

      • 第一行是文件、目录、符号链接等的总数,这就是它比第二行大的原因。
      • --dry-run(或简称-n)选项对于不实际传输文件很重要!
      • 我使用-x 选项来“不跨越文件系统边界”,这意味着如果您为/ 执行它并且连接了外部硬盘,它只会计算根分区上的文件。

      【讨论】:

      • 我喜欢你在这里使用 rsync 的想法。我从来没有想过!
      • 谢谢@Qeole,不过这个想法不是我的。几年前我在某处读到,rsync 是删除包含大量文件和子文件夹的文件夹最快的方法,所以我认为计数文件也可能很快。
      • 试过这个。在预先运行两次以填充 fs 缓存后,find ~ -type f | wc -l 花费了 1.7/0.5/1.33 秒(真实/用户/系统)。 rsync --stats --dry-run -ax ~ /xxx 耗时 4.4/3.1/2.1 秒。这相当于 SSD 上大约 500,000 个文件。
      • 不知道你用的是什么版本的 rsync,但在 3.1.2 中它更容易阅读:Number of files: 487 (reg: 295, dir: 192)
      • 我在macOS上使用了默认的rsync:rsync version 2.6.9 protocol version 29
      【解决方案11】:
      ls -l | grep -e -x -e -dr | wc -l 
      
      1. 长长的列表
      2. 过滤文件和目录
      3. 计算过滤后的行号

      【讨论】:

        【解决方案12】:

        这里有很多正确的答案。这是另一个!

        find . -type f | sort | uniq -w 10 -c
        

        其中. 是要查看的文件夹,10 是目录分组所依据的字符数。

        【讨论】:

          【解决方案13】:

          我写了ffcnt 来加速特定情况下的递归文件计数:支持范围映射的旋转磁盘和文件系统。

          它可能比基于 lsfind 的方法快一个数量级,但 YMMV。

          【讨论】:

            【解决方案14】:

            使用 bash:

            使用 ( ) 创建一个条目数组并使用 # 获取计数。

            FILES=(./*); echo ${#FILES[@]}
            

            好的,这不会递归地计算文件,但我想先展示简单的选项。一个常见的用例可能是创建文件的翻转备份。这将创建 logfile.1、logfile.2、logfile.3 等。

            CNT=(./logfile*); mv logfile logfile.${#CNT[@]}
            

            启用 bash 4+ globstar 的递归计数(如 @tripleee 所述)

            FILES=(**/*); echo ${#FILES[@]}
            

            要递归地获取文件的数量,我们仍然可以使用 find 以相同的方式。

            FILES=(`find . -type f`); echo ${#FILES[@]}
            

            【讨论】:

            • 现代 shell 支持 **/* 进行递归枚举。它在大目录上的效率仍然低于find,因为 shell 必须对每个目录中的文件进行排序。
            • 将整个搜索存储在一个 Bash 数组中以便稍后计算它是相当低效的,并且可能会占用大量内存,直到枚举完成。对于非常大的目录树,这可能是一个真正的问题。
            【解决方案15】:

            find -type f | wc -l

            OR(如果目录是当前目录)

            找到 . -类型 f | wc -l

            【讨论】:

            • 这至少重复了同一问题的另一个答案。
            【解决方案16】:

            这将完全正常。简单的短。如果要计算文件夹中存在的文件数。

            ls | wc -l
            

            【讨论】:

            • 首先,这并不能回答问题。问题是关于从目录向前递归计数文件,而您显示的命令不会这样做。此外,使用 ls 您可以计算目录和文件。此外,如果您不打算添加任何新内容,甚至不打算正确阅读问题,也没有理由回答老问题。请不要这样做。
            【解决方案17】:

            您可以使用命令ncdu。它将递归地计算一个 Linux 目录包含多少个文件。这是一个输出示例:

            它有一个进度条,如果你有很多文件,这很方便:

            在 Ubuntu 上安装它:

            sudo apt-get install -y ncdu
            

            基准测试:我使用https://archive.org/details/cv_corpus_v1.tar(380390 个文件,11 GB)作为必须计算文件数量的文件夹。

            • find . -type f | wc -l:大约需要 1 分 20 秒才能完成
            • ncdu: 大约 1 分 20 秒完成

            【讨论】:

            • 那主要计算磁盘使用量,而不是文件数。这种额外的开销可能是不需要的。 (除了需要为可以使用标准 POSIX 实用程序完成的事情安装额外的软件包)
            • @hek2mgl 它确实计算文件的数量,如第一个屏幕截图中的红色所示。我花了几分钟处理了大约 200 万个文件,所以速度还不错。
            • @hek2mgl 我在答案中添加了一个可重现的基准,我运行了两次,我没有发现find . -type f | wc -lncdu 之间有任何区别。
            • 是的,看起来find 在后台执行与du 或多或少相同的系统调用,ncdu 的后端。只是跟踪他们。
            • @FranckDernoncourt 喜欢它。我在一个文件夹中有大量文件,并且有一个进度条是救命稻草。感谢分享!
            【解决方案18】:

            由于 UNIX 中的文件名可能包含换行符(是的,换行符),wc -l 可能会计算太多文件。我会为每个文件打印一个点,然后计算点数:

            find DIR_NAME -type f -printf "." | wc -c
            

            注意:-printf 选项仅适用于来自 GNU findutils 的 find。您可能需要安装它,例如在 Mac 上。

            【讨论】:

            • 看起来这是唯一处理名称中带有换行符的文件的解决方案。赞成。
            • hihi :) 我喜欢文件名中的换行符。这使它们更具可读性。
            • 我的意思是,文件中的换行names不是内容!
            • 我只是在开玩笑......是的,文件名中的换行符总是必须考虑在内。它们可能来自恶意内容,也可能来自错字。
            • 这不适用于每个find。在 OSX 上,您需要安装 GNU Find,例如,brew install findutils
            【解决方案19】:
            tree $DIR_PATH | tail -1
            

            样本输出:

            5309 个目录,2122 个文件

            【讨论】:

            • 这是最简单的解决方案,可以生成(几乎)所需的精确信息。唯一更接近此解决方案的方法是将其通过cut -d',' -f2 进行管道传输。
            【解决方案20】:

            如果您需要计算特定文件类型 递归,您可以这样做:

            find YOUR_PATH -name '*.html' -type f | wc -l 
            

            -l只是显示输出的行数。

            如果您需要排除某些文件夹,请使用-not -path

            find . -not -path './node_modules/*' -name '*.js' -type f | wc -l
            

            【讨论】:

            • 扩展名是文件名的一部分,可能不代表文件类型
            【解决方案21】:

            对于名称中带有空格的目录...(基于上面的各种答案)-递归打印目录名称以及其中的文件数:

            find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done
            

            示例(为便于阅读而格式化):

            pwd
              /mnt/Vancouver/Programming/scripts/claws/corpus
            
            ls -l
              total 8
              drwxr-xr-x 2 victoria victoria 4096 Mar 28 15:02 'Catabolism - Autophagy; Phagosomes; Mitophagy'
              drwxr-xr-x 3 victoria victoria 4096 Mar 29 16:04 'Catabolism - Lysosomes'
            
            ls 'Catabolism - Autophagy; Phagosomes; Mitophagy'/ | wc -l
              138
            
            ## 2 dir (one with 28 files; other with 1 file):
            ls 'Catabolism - Lysosomes'/ | wc -l
              29
            

            使用tree可以更好地可视化目录结构:

            tree -L 3 -F .
              .
              ├── Catabolism - Autophagy; Phagosomes; Mitophagy/
              │   ├── 1
              │   ├── 10
              │   ├── [ ... SNIP! (138 files, total) ... ]
              │   ├── 98
              │   └── 99
              └── Catabolism - Lysosomes/
                  ├── 1
                  ├── 10
                  ├── [ ... SNIP! (28 files, total) ... ]
                  ├── 8
                  ├── 9
                  └── aaa/
                      └── bbb
            
              3 directories, 167 files
            
            man find | grep mindep
              -mindepth levels
                Do not apply any tests or actions at levels less than levels
                (a non-negative integer).  -mindepth 1 means process all files
                except the starting-points.
            

            ls -p | grep -v /(在下面使用)来自https://unix.stackexchange.com/questions/48492/list-only-regular-files-but-not-directories-in-current-directory的答案2

            find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done
            ./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
            ./Catabolism - Lysosomes: 28
            ./Catabolism - Lysosomes/aaa: 1
            

            应用程序:我想在几百个目录中找到最大文件数(所有深度 = 1)[下面的输出再次格式化以提高可读性]:

            date; pwd
                Fri Mar 29 20:08:08 PDT 2019
                /home/victoria/Mail/2_RESEARCH - NEWS
            
            time find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done > ../../aaa
                0:00.03
            
            [victoria@victoria 2_RESEARCH - NEWS]$ head -n5 ../../aaa
                ./RNA - Exosomes: 26
                ./Cellular Signaling - Receptors: 213
                ./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
                ./Stress - Physiological, Cellular - General: 261
                ./Ancient DNA; Ancient Protein: 34
            
            [victoria@victoria 2_RESEARCH - NEWS]$ sed -r 's/(^.*): ([0-9]{1,8}$)/\2: \1/g' ../../aaa | sort -V | (head; echo ''; tail)
            
                0: ./Genomics - Gene Drive
                1: ./Causality; Causal Relationships
                1: ./Cloning
                1: ./GenMAPP 2
                1: ./Pathway Interaction Database
                1: ./Wasps
                2: ./Cellular Signaling - Ras-MAPK Pathway
                2: ./Cell Death - Ferroptosis
                2: ./Diet - Apples
                2: ./Environment - Waste Management
            
                988: ./Genomics - PPM (Personalized & Precision Medicine)
                1113: ./Microbes - Pathogens, Parasites
                1418: ./Health - Female
                1420: ./Immunity, Inflammation - General
                1522: ./Science, Research - Miscellaneous
                1797: ./Genomics
                1910: ./Neuroscience, Neurobiology
                2740: ./Genomics - Functional
                3943: ./Cancer
                4375: ./Health - Disease 
            

            sort -V 是一种自然排序。 ...因此,我在这些(Claws Mail)目录中的最大文件数是 4375 个文件。如果我左填充 (https://*.com/a/55409116/1904943) 这些文件名——它们在每个目录中都以数字命名,从 1 开始——并且填充到 5 个总数字,我应该没问题。


            附录

            查找目录中文件、子目录的总数。

            $ date; pwd
            Tue 14 May 2019 04:08:31 PM PDT
            /home/victoria/Mail/2_RESEARCH - NEWS
            
            $ ls | head; echo; ls | tail
            Acoustics
            Ageing
            Ageing - Calorie (Dietary) Restriction
            Ageing - Senescence
            Agriculture, Aquaculture, Fisheries
            Ancient DNA; Ancient Protein
            Anthropology, Archaeology
            Ants
            Archaeology
            ARO-Relevant Literature, News
            
            Transcriptome - CAGE
            Transcriptome - FISSEQ
            Transcriptome - RNA-seq
            Translational Science, Medicine
            Transposons
            USACEHR-Relevant Literature
            Vaccines
            Vision, Eyes, Sight
            Wasps
            Women in Science, Medicine
            
            $ find . -type f | wc -l
            70214    ## files
            
            $ find . -type d | wc -l
            417      ## subdirectories
            

            【讨论】: