【謎】本当にあったfindコマンドの怖い話【おもしろ現象】
3/21 22時頃: 質問編へのリンクを撤去し、タイトルを変更しました。(元のタイトルは「【謎】本当にあったfindコマンドの怖い話【未解決→解決済み】」)
要約
100万個のファイルに対して、find
コマンドから始めて mv
コマンドでファイル名を変更するワンライナーを実行すると、 mv
コマンドが約158万回実行されました。
背景
これは、Software Design 2018年4月号
の「シェル芸人からの挑戦状」の記事執筆中に遭遇した不思議な現象です。1 初めはコラムに書こうとしていたのですが、結局原因がわからず、解説が書けなかったために紙面からは外すことにしました。 流石に結論が「わかりませんでした」で雑誌には載せられないので……。
現象自体は面白かったため、代わりに個人のブログの方に書くことで共有します。 (掲載の許可は頂いています)
環境
連載と同様、OSは Ubuntu 16.04 LTS、ファイルシステムは ext4 です。
再現手順
適当なディレクトリで、ファイルを100万個作成します。2
|
|
そして、以下のワンライナーを実行します。3
|
|
……結果を見る前に、ワンライナーの簡単な解説をしておきます。
ワンライナーの簡単な解説
これは、カレントディレクトリにある全てのファイルに対して、ファイル名の先頭に「a」を付与してリネームするワンライナーです。 例えば、「100」→「a100」という風にリネームします。
最初の
|
|
で、find
の結果から邪魔な ./
と ../
を除去し、さらに出力の頭に付く ./
を外します。
次の
|
|
で、頭に「a」が付いていないファイル名と付いているファイル名の並びを生成し、最後の
|
|
では xargs
で出力を2つずつ(つまり、先のawk
で作ったペアをそのまま)取り出し、mv
コマンドの引数を echo
しつつ mv
でリネームします。
つまり、最後の xargs
では
|
|
のようなコマンドを生成し実行します。
上記までの処理を time
コマンドで時間計測しつつ、最後の nl
で 何回mvを行ったかを数えます。
実行結果
|
|
予想に反する結果が出ていると思います。
- 用意したファイルは100万個なのに、なぜか
mv
が 1584218回 4実行されている - なぜか頭に「aaaa」の付いているファイル(1584212番目)が作成されている、つまり同じファイルが4回
mv
されている
なんやねんこれは
もう少し詳しく
落ち着いて、ファイル数を数えてみます。
|
|
……ちょっとよくわかりませんね。
まとめ
わからん
一応 find
コマンドのソースは読んだんですが。。。
ファイルを読んでいるところは fts_read (3)
で、その中の奥の方では readdir(3)
を使ってて、この子がスレッドセーフじゃないとかなんかそんな感じなんでしょうか……?
冒頭にも書いたんですが、ほんとわからないので誰かわかる方がいらっしゃったら教えて下さい。。。 流石に何かのバグではないと思うんですけども……
参考URL
- ftsfind.c\find - findutils.git - GNU findutils
- gnulib/fts.c at master · coreutils/gnulib · GitHub
- linux/readdir.c at 8e9a2dba8686187d8c8179e5b86640e653963889 · torvalds/linux · GitHub
- glibc/opendir.c at 20003c49884422da7ffbc459cdeee768a6fee07b · git-mirror/glibc · GitHub
3/21追記
原因分かりました。