LoginSignup
22
4

Linux: ファイルが多すぎるとLSできない?

Posted at

少しひっかかったのでメモ。

実施環境:
Linux
[testuser@testhost ~]$ uname -a
Linux testhost 4.18.0-147.8.1.el8_1.x86_64 #1 SMP Thu Apr 9 13:49:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
[testuser@testhost ~]$ echo $SHELL
/bin/bash

事象

以下のように、100万個のファイルが入っているディレクトリがあるとします。

Linux
[root@testhost ~]# ls ./test/ | wc -l
1000000

このディレクトリの中のファイルの一覧をとろうとするとき、普通にディレクトリを引数に指定すれば特に問題なく ls コマンドを実行できます。

Linux
[root@testhost ~]# ls ./test/
1.txt
10.txt
100.txt
(以下省略)

ところが、ファイルをワイルドカードで指定しようとすると、 ls コマンドはエラーとなってしまいます。

Linux
[root@testhost ~]# ls ./test/*
-bash: /usr/bin/ls: 引数リストが長すぎます

原因

なぜこのようなことが起こるのか。
原因は Linux における特殊文字の展開の順序が大きく絡んできます。

細かい説明は省きますが、 ls コマンドでワイルドカードを指定した場合、 ls コマンドが実行される前にワイルドカードが展開されてしまいます。
すなわち、

Linux
ls ./test/*

Linux
ls ./test/1.txt ./test/10.txt ./test/100.txt (以下省略)

として解釈され、実行されます。
一方で、 Linux においてコマンドの引数には長さの上限があります。
そのため、大量のファイルをワイルドカードを使って ls コマンドに指定した場合、引数エラーが発生してしまうのです。
無論、このエラーは ls コマンド以外でも発生しうるので注意しましょう。

Linux
[root@testhost ~]# rm ./test/*
-bash: /usr/bin/rm: 引数リストが長すぎます

対処法

対処法はいくつかありますが、今回は3つほど紹介します。

①ワイルドカードを使用しない

一番手っ取り早いのは、ワイルドカードを使用しないことです。
例えば先ほどのようにディレクトリを指定するだけなら、きちんと ls コマンドは実行できます。

Linux
[root@testhost ~]# ls ./test/
1.txt
10.txt
100.txt
(以下省略)
②コマンド側でワイルドカードを展開できるコマンドを使用する

Linux のコマンドの中には、コマンド側でワイルドカードを展開できるコマンドもいくつか存在します。

代表的なのが find コマンドです。
find コマンドの name オプションを使用すれば、ワイルドカードをコマンド側で展開することができます。

Linux
[root@testhost ~]# find ./test/ -name "*"
./test/
./test/1.txt
./test/2.txt
(以下省略)

ls コマンドを通す必要があるなら、 xargs コマンドを使用することで対応可能です。

Linux
[root@testhost ~]# find ./test/ -name "*" -type f | xargs ls
./test/1.txt
./test/10.txt
./test/100.txt
(以下省略)
③ echo コマンドを使用する

実は echo コマンドを使用することでも対応可能です。
ただし、結果は改行区切りでなくスペース区切りとなります。

Linux
[root@testhost ~]# echo ./test/*
./test/1.txt ./test/10.txt ./test/100.txt (以下省略)

なお、ここで使用している echo コマンドは exit コマンドや let コマンド等と同じ、「 bash の組み込みコマンドである echo コマンド」です。
bin 配下にある echo コマンドは ls コマンド等と同じようにエラーになります。

Linux
[root@testhost ~]# /bin/echo ./test/*
-bash: /bin/echo: 引数リストが長すぎます

補足

ちなみに、引数の長さの上限は以下のコマンドラインで確認できます。

Linux
[root@testhost test]# getconf ARG_MAX
2097152
[root@testhost test]#

なお、この「2097152」は引数の個数の上限ではなく、「引数のバイト数の上限」であることに注意が必要です。
ワイルドカードを使用せずとも、例えば以下のように非常に長い文字列を1つ与えるだけで ls コマンドはエラーとなります。

Linux
[root@testhost ~]# cat test.txt | wc -c
3154812
[root@testhost ~]#
[root@testhost ~]# ls "`cat test.txt`"
-bash: /usr/bin/ls: 引数リストが長すぎます
22
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
4