當前位置: 首頁>>技術教程>>正文


為什麽`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/zh-tw/article/9674.html,未經允許,請勿轉載。