为什么“ls -l”计算的文件数比我还多?

为什么“ls -l”计算的文件数比我还多?

显然我数不过来。我认为有三个文件/media

$ tree /media
/media
├── foo
├── onex
└── zanna
3 directories, 0 files

然而,ls -l发现 12。

$ ls -l /media
total 12
drwxr-xr-x  2 root root 4096 Jul 31 20:57 foo
drwxrwxr-x  2 root root 4096 Jun 26 06:36 onex
drwxr-x---+ 2 root root 4096 Aug  7 21:17 zanna

并且,如果我这样做,除了上述内容之外,ls -la我只会得到,但计数是...total 20

怎么解释?

答案1

12看到的并不是文件的数量,而是消耗的磁盘块的数量。

info coreutils 'ls invocation'

 For each directory that is listed, preface the files with a line
 `total BLOCKS', where BLOCKS is the total disk allocation for all
 files in that directory.  The block size currently defaults to 1024
 bytes, but this can be overridden (*note Block size::).  The
 BLOCKS computed counts each hard link separately; this is arguably
 a deficiency.

当您使用而不是时,总数将从 变为12,因为您要计算两个附加目录:和。您为每个(空)目录使用 4 个磁盘块,因此总数将从 3 × 4 变为 5 × 4。(最有可能的是,您正在使用20ls -lals -l...每个目录的磁盘块为 4096 字节;如页面info所示,该实用程序不检查磁盘格式,但假定块大小为,1024除非另有说明。)

如果你只想获取文件数量,你可以尝试类似

ls | wc -l

答案2

user4556274 已经回答为什么。我的回答仅用于提供补充信息如何正确计数文件。

在 Unix 社区中,普遍的共识是解析输出ls是一个非常糟糕的主意,因为文件名可以包含控制字符或隐藏字符。例如,由于文件名中有换行符,我们被ls | wc -l告知输出中有 5 行ls(确实有),但实际上目录中只有 4 个文件。

$> touch  FILE$'\n'NAME                                                       
$> ls                                                                         
file1.txt  file2.txt  file3.txt  FILE?NAME
$> ls | wc -l
5

方法一:寻找效用

find命令通常用于解决文件名解析问题,它可以帮助我们打印索引节点号。无论是目录还是文件,它都只有一个唯一的 inode 编号。因此,使用-printf "%i\n"并排除.via-not -name "."我们可以准确计算文件数量。(请注意使用-maxdepth 1以防止递归下降到子目录)

$> find  -maxdepth 1 -not -name "." -print                                    
./file2.txt
./file1.txt
./FILE?NAME
./file3.txt
$> find  -maxdepth 1 -not -name "." -printf "%i\n" | wc -l                    
4

方法 #2:globstar

简单,快速且最便携的方式:

$ set -- * 
$ echo $#
228

set命令用于设置 shell 的位置参数($<INTEGER>变量,如echo $1)。这通常用于解决/bin/sh缺少数组的限制。执行额外检查的版本可以在Gille 的回答在Unix和Linux上。

在支持数组的 shell 中,例如bash,我们可以使用

items=( dir/* )
echo ${#items[@]}

按照提议steeldriver 在评论中

find与使用的方法类似的技巧wc,可以使用 globstar 来stat计算每行的 inode 数量:

$> LC_ALL=C stat ./* --printf "%i\n" | wc -l                                          
4

另一种方法是使用for循环中的通配符。(请注意,此测试使用不同的目录来测试此方法是否会进入子目录,但事实并非如此 - 16 是我的已验证项目数~/bin

$> count=0; for item in ~/bin/* ; do count=$(($count+1)) ; echo $count ; done | tail -n 1                                
16

方法 3:其他语言/解释器

Python 还可以通过打印给定我的函数的列表长度来处理有问题的文件名os.listdir()(它是非递归的,并且只列出作为参数给出的目录中的项目)。

$> python -c "import os ; print os.listdir('.')"                              
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$>  python -c "import os ; print(len(os.listdir('.')))"                    
4

也可以看看

相关内容