当前位置: 首页>>技术教程>>正文


为什么`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

有什么解释?

最佳方法

您看到的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.

当您使用ls -la而不是ls -l时,总数从1220,因为您要计算的是另外两个目录:...。您为每个(空)目录使用四个磁盘块,因此总数从3×4变为5×4。(很可能,您为每个目录使用一个4096字节的磁盘块;正如info页所指示的,除非另有说明,否则该实用程序不会检查磁盘格式,但会假定其块大小为1024。)

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

ls | wc -l

次佳方法

user4556274 has already answered为什么。我的回答仅用于提供有关如何正确计数文件的其他信息。

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

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

方法1:查找实用程序

find命令通常用于解析文件名,它可以通过打印inode number来帮助我们。无论是目录还是文件,它都只有一个唯一的索引节点号。因此,使用-printf "%i\n"并通过-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 的位置参数(如echo $1中的$<INTEGER>变量)。这通常用于解决/bin/sh缺少数组的限制。可以在Unix&Linux上的Gille’s answer中找到执行额外检查的版本。

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

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

steeldriver in the comments提出。

与使用wc和globstar的find方法类似的技巧可以与stat一起使用以计算每行的索引节点数:

$> 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

也可以看看

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/9674.html,未经允许,请勿转载。