计算目录中文件数量的最佳方法是什么?


11

如果解析的输出ls很危险,因为它的输出可能会破坏某些时髦的字符(空格\n,...),那么知道目录中文件数量的最佳方法是什么?

我通常依靠find避免这种解析,但是find mydir | wc -l出于相同的原因,它也会中断。

我现在正在使用Solaris,但是我正在寻找一个尽可能在不同的unice和不同的shell中移植的答案。


3
我不确定是否重复,我错过了什么吗?
rahmu 2014年

1
这可能是重复的,但不是所指出问题的重复。find会递归为您提供文件数量(-maxdepth 1如果您不希望使用find mydir -maxdepth 1 -type f -printf \\n | wc -l该文件,则应使用。应处理文件名中的特殊字符,因为它们不会从一开始就打印出来。)
Anthon 2015年

Answers:


16

这个技巧怎么样?

find . -maxdepth 1 -exec echo \; | wc -l

作为便携式的findwc


5
这不起作用(它n+1在我的Debian系统上显示文件)。它还不会过滤常规文件。
克里斯·

4
我只是举了一个通用的例子。它确实可以工作,但是它如何工作取决于您如何find根据特定需求调整命令。是的,这包括所有目录,包括.(这可能是为什么您将结果视为的原因n+1)。
rozcietrzewiacz 2011年

我喜欢这个技巧,非常聪明;但令我惊讶的是,没有简单的直接方法可以做到这一点!
rahmu 2011年

3
@ChrisDown OP未指定对常规文件的过滤,而是询问目录中的文件数。要摆脱n + 1问题,请使用find . -maxdepth 1 ! -name . -exec echo \; | wc -l; 的某些旧版本find没有-not
Arcege 2011年

3
注意,这-maxdepth不是标准的(其他一些实现现在也支持GNU扩展)。
斯特凡Chazelas

11

使用bash,没有外部实用程序,也不会循环:

shopt -s dotglob
files=(*)
echo ${#files[@]}

在ksh中,替换shopt -s dotglobFIGNORE=.?(.)。在zsh中,将其替换为setopt glob_dots,或删除shopt呼叫并使用files=(*(D))。(或者,如果您不想包括点文件,只需删除该行。)如果您不关心点文件,则可移植:

set -- *
echo $#

如果确实要包含点文件:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
1如果nullglob未启用,第一个示例将打印一个空目录。在zsh中,a=(*(DN));echo ${#a}使用Nnullglob)限定符不会导致空目录错误。
nisetama '16

8
find . ! -name . -prune -print | grep -c /

应该可以轻松移植到80年代后的系统。

这将计算当前目录中.和以外的所有目录条目..

要同时计数子目录中的文件:

find .//. ! -name . | grep -c //

(因为它不需要,甚至应该可以移植到Unix V6(1975)上-prune


此页面上的罕见便携式答案之一,如果不是唯一的话。
xhienne

我昨天对这个答案进行了投票,因为我发现它对于当前目录(find dirname ! -name dirname -prune -print)以外的其他目录也适用。从那以后,我一直想知道是否有任何特定的原因grep -c /代替wc -l(可能更常用于计数)。
Anthony Geoghegan '18年

1
find dirname ! -name dirname如果其中还有名为的其他目录,则无法使用dirname。最好使用find dirname/. ! -name .wc -l计算行数,文件名可以由几行组成,因为换行符与文件名中的任何字符一样有效。
斯特凡Chazelas

6

尝试:

ls -b1A | wc -l

-b将非打印字符,-A将显示除所有文件...每行(在管道上的默认,但好是明确的)一个。

只要我们包含更高级别的脚本语言,这就是Python的一线式:

python -c 'import os; print len(os.listdir(os.sep))'

或完整的“查找”:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc可以使用以下构造:

I=0; for i in * ; do ((I++)); done ; echo $I

但是恐怕,如果Argument list too long.目录中有太多文件,您可能会出现错误。但是我在具有100亿个文件的目录上对其进行了测试,并且效果很好。


3
除非将shell配置为使用扩展这些文件,否则该文件对隐藏文件均无效*
Lekensteyn 2011年

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley

4
@Rush:此命令永远不会引发“ arg list too long”。只有外部命令才会发生这种情况(所以永远不会发生for
enzotib 2011年

1

您是否考虑过perl,它应该相对可移植?

就像是:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

试试这个=>将ls与-i(用于节点号)和-F(在目录名后附加'/')一起使用。

ls -ilF | egrep -v '/' | wc -l

0

使用perl单线(经过重新格式化以提高可读性):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

要么

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

您可以使用perl修改数组的函数,例如第二个版本grepmap与第二个版本一起使用。请参阅perldoc -f readdir使用的示例grep


0

我一直使用且从未遇到过的最简单的版本是: ls -b1 | wc -l


如果文件名包含a \n或其他时髦字符,则可能会遇到问题(是的,某些unice允许这样做)。
rahmu

1
在发布答案之前,我明确尝试过此操作,但没有任何问题。我使用nautilus文件管理器来重命名包含\ n的文件,以尝试此操作。
彼得

您说对了,它不是那样工作的。我不知道我第一次测试时做了什么。再次尝试并更新了我的答案。
彼得

否,该命令还可以,但是已经有一个类似的解决方案,并且不计算隐藏文件。
xhienne

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.