なぜ `ls -l`は私よりも多くのファイルをカウントするのですか?


25

どうやら私は数えられない。私は3つのファイルがあると思います/media

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

ただし、ls -l12が見つかります。

$ 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

説明は何ですか?

回答:


33

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.

合計から行く1220は、使用するときls -laの代わりにls -l使用すると、2つの追加のディレクトリをカウントしているので:...。各(空の)ディレクトリに4つのディスクブロックを使用しているので、合計は3×4から5×4になります(ほとんどの場合、各ディレクトリに4096バイトのディスクブロックを1つ使用していinfoます。ページが示すように、ユーティリティはディスク形式をチェックしませんが、1024特に指示がない限り、ブロックサイズを想定しています。

単にファイルの数を取得したい場合は、次のようなものを試してみてください

ls | wc -l

13
ls | wc -lファイル名に改行があるファイルがあると失敗します。これはより回復力がありますfind . -mindepth 1 -maxdepth 1 -printf . | wc -c
。– Flimm

20
「ファイル名に新しい行がある場合」... 震え
ペタ

8
man lsあなたがコントロール文字を避けることができ、あなたを教えてくれます-b(それらをエスケープ)または-q(省いそれらを)。したがって、カウントのために、ls -1q | wc -l非隠しファイルを表示するために安全かつ正確です。ls -1qA | wc -l隠しファイルをカウントします(ただし、.および..)。-1代わりに使用しているのは-l、それがより速いはずだからです。
オリ

18

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

方法#1:ユーティリティの検索

このfindコマンドは通常、ファイル名の解析に使用されますが、ここではiノード番号を出力することで役立ちます。ディレクトリでもファイルでも、一意のiノード番号は1つだけです。したがって、via を使用-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コマンドは、シェルの位置パラメーター(のような$<INTEGER>変数echo $1)を設定するために使用されます。これは/bin/sh、配列不足の制限を回避するためによく使用されます。追加のチェックを実行するバージョンは、Unix&LinuxのGilleの回答に記載されています。

などの配列をサポートするシェルではbash、次を使用できます。

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

スチールドライバーがコメントで提案した通り

globstar findを使用した方法と同様のトリックをwc使用してstat、行ごとにiノード数をカウントできます。

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

別のアプローチは、forループでワイルドカードを使用することです。(このテストは別のディレクトリを使用して、このアプローチがサブディレクトリに下降するかどうかをテストしますが、そうではありません-16はmyの検証済みアイテム数です~/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

こちらもご覧ください


2
bashでは、別のオプションとして、配列items=( dir/* ); echo ${#items[@]}(たとえばshopt -s dotglob、隠しファイルを含めるために追加する)を使用し ます。
スチールドライバー

1
iノード番号を印刷すると、必要に応じてハードリンクを簡単にフィルタリングできfind | sort -u | wc -lます。
ピーター・コーデス

@steeldriver:bash-arrayメソッドの方が高速になる可能性は低いと思います。再帰的にしたい場合は、items=( dir/** )(を使用してshopt -s globstar)使用する必要がありますが、bashはreaddirからの追加のメタデータを利用しないため、すべてのディレクトリエントリを統計して、それがディレクトリ自体かどうかを確認します。多くのファイルシステムは、ファイルタイプをディレクトリエントリに保存するため、readdirはiノードにアクセスせずにファイルタイプを返すことができます。(たとえば、最新のデフォルトではないXFSにはこれがあり、ext4にはこれよりも長い時間がかかると思います。)strace見つけると、statbashを追跡するよりもはるかに少ないシステムコールが表示されます。
ピーターコーデス

2
なぜ単に使用しないのprint(len(os.listdir('.')))ですか?入力する文字数が少なくなり、二重下線付きの属性にアクセスすることも避けられます。
edwinksl

1
@edwinksl編集、thx
セルギー・コロディアズニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.