単純にはlsでプリントしてから手で数えたら良いが、 ファイルが何千、何万もあるとそうもいかない。
そこで
- ls: ファイルやディレクトリを列挙
- grep: 入力から条件を満たす行を抽出
- wc: 入力の行数などを数える
実行例
基本:カレントディレクトリ直下のファイルとディレクトリを数える
単純にすべてのカレントディレクトリ直下のファイル+ディレクトリを数えるには lsもwcもほぼそのまま使える。wcの-lオプションは行数カウントのみ出力する、出力整形用の オプションでカウントの動作には関係ない。また古い資料だとlsの出力を1行ずつ改行する-1オプションが必須と書いてあるのももあるが、 私の環境だとあってもなくても出力が変わらなかった(バージョンの関係か?)。
# 練習用ディレクトリをプリント $ tree . ├── dir1 │ └── subfile1.txt ├── dir2 │ ├── dir3 │ │ └── subfile3.txt │ └── subfile2.txt ├── file1.txt ├── file2.txt ├── file3.txt └── file4.csv # カレント直下は6つ $ ls dir1 dir2 file1.txt file2.txt file3.txt file4.csv $ ls | wc -l 6
カレントディレクトリ直下のファイルのみ/ディレクトリのみを数える
ファイルのみ・ディレクトリのみに絞りたいときはlsの-Fをつける。 これにより名前の後にタイプ識別子(ファイルなら*、ディレクトリなら/)を つけてくれるので、見分けられるようになる。そのうえでgrepでフィルタリングする。
# 練習用ディレクトリをプリント # -Fオプションでファイル・ディレクトリの表示分け $ ls -F dir1/ dir2/ file1.txt* file2.txt* file3.txt* file4.csv* $ ls -F | grep "*" file1.txt* file2.txt* file3.txt* file4.csv* $ ls -F | grep "*" | wc -l 4 $ ls -F | grep "/" dir1/ dir2/ $ ls -F | grep "/" | wc -l 2
再帰的にサブディレクトリ以下まで数える
lsはデフォルトだとカレント直下しか見ないので、再帰のオプション-Rを つける。なお再帰時には"[directory]/:"のように見に行ったディレクトリを 途中で表示してしまい、ナイーブにやるとこれで数のずれが生じる。また空白行もでる。grepで うまくこれらを除外する必要がある。grepの-vオプションを使い":"と"^$" (これが空白行を表す正規表現になる) を除外しよう。$ ls -1R .: dir1 dir2 file1.txt file2.txt file3.txt file4.csv ./dir1: subfile1.txt ./dir2: dir3 subfile2.txt ./dir2/dir3: subfile3.txt $ ls -1R | grep -ve ":" -e "^$" dir1 dir2 file1.txt file2.txt file3.txt file4.csv subfile1.txt dir3 subfile2.txt subfile3.txt $ ls -1R | grep -ve ":" -e "^$" | wc -l 10
特定のディレクトリ・ファイルだけ除外する
grep
の-vオプションで除外するパターンの設定ができるので、
これをうまく使う。
なおlsだとどうやっても再帰的にフルパスでの表示はできないので、サブディレクトリ名で除外をかけたいときなど できないケースがあると分かった。そのようなときはlsの代わりに
find
を使おう。
こちらはデフォルトで途中のディレクトリも表示してくれるので、除外が簡単である。なお
findではカレントディレクトリ"."が出力行に含まれてしまうので、合計から-1することを忘れないようにする。
実験として"dir2"以下のディレクトリ・ファイルのみ計数から除外してみる。
$ find . ./dir1 ./dir1/subfile1.txt ./dir2 ./dir2/dir3 ./dir2/dir3/subfile3.txt ./dir2/subfile2.txt ./file1.txt ./file2.txt ./file3.txt ./file4.csv $ find | grep -v dir3 . ./dir1 ./dir1/subfile1.txt ./dir2 ./dir2/subfile2.txt ./file1.txt ./file2.txt ./file3.txt $ find | grep -v dir3 | wc -l 9