前の関連記事:linuxBean14.04(184)デュアルディスプレイを使う
ディレクトリツリー内のファイル総数を取得する
まず実験に使うディレクトリツリー内にあるファイル総数を求めてみます。
対象ディレクトリはホームディレクトリです。
find ~ -type f | wc -l
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f | wc -l find: `/home/pq/.cache/dconf': 許可がありません 511814 real 1m50.799s user 0m2.056s sys 0m11.596s時間測定のためにtimeコマンドを最初に付けて実行しました。
51万1814個ものファイルがありました。
「許可がありません」といわれているパスは、rootのみアクセスが許可されているフォルダでした。
ファイル数のカウントだけで1分59秒もかかっています。
find ~ -type f -exec wc -l {} +
パイプを使わずにやろうとするとファイルパスが出力されるので時間がかかり過ぎて途中でやめました。
find ~ -type f | xargs wc -l
これもファイルパスが出力されてしまいました。
ディレクトツリー内の一番古いファイルを抽出する
find ~ -type f | xargs ls -t | tail -1
これは「そのようなファイルやディレクトリはありません」がたくさんでてきます。
原因はパスにある空白です(Linux - ls: cannot access(49015)|teratail)。
find ~ -type f -exec ls -t {} + | tail -1
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f -exec ls -t {} + | tail -1 find: `/home/pq/.cache/dconf': 許可がありません /home/pq/.local/share/mime/packages/Overrides.xml real 2m57.982s user 0m11.412s sys 0m17.620s
2分57秒かかって、/home/pq/.local/share/mime/packages/Overrides.xmlが出力されました。
しかしこれはディレクトリツリー内の一番古いファイルではなく、findからlsにまとまって渡された最後のまとまりの引数のパスの中で一番古いファイルというだけでした。
find ~ -type f -printf '%T+ %p\n' | sort | head -n 1
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f -printf '%T+ %p\n' | sort | head -n 1 find: `/home/pq/.cache/dconf': 許可がありません 1980-01-01+00:00:00.0000000000 /home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.json real 3m40.115s user 0m29.284s sys 0m19.056s
3分40秒もかかりましたが、/home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.jsonが正しい一番古いファイルのようです。
ファイルの日付も出力されているため、この結果を利用するにはパスのみ取り出す必要があります。
linux - How can I find the oldest file in a directory tree - Super Userで紹介されていた3つの方法をやってみました。
find ~ -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat find: `/home/pq/.cache/dconf': 許可がありません 1980-01-01+00:00:00.0000000000 /home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.json real 3m44.788s user 0m30.096s sys 0m19.552s
これも3分44秒もかかっています。
find ~ -type f -printf "%T@ %T+ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f -printf "%T@ %T+ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //' find: `/home/pq/.cache/dconf': 許可がありません 1980-01-01+00:00:00.0000000000 /home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.json real 4m20.295s user 0m27.500s sys 0m15.728s
%T+(日付と時刻)より%T@(Jan. 1, 1970, 00:00 GMT からの経過秒数)の出力をソートした方が、速いと解説されていますが、さっきよりも時間がかかっています。
これは%T+と%T@の両方を出力しているからと考えて、%T@だけの出力にしてみました。
find ~ -type f -printf "%T@ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
pq@pq-VirtualBox:~/_tmp$ time find ~ -type f -printf "%T@ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //' find: `/home/pq/.cache/dconf': 許可がありません /home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.json real 1m22.017s user 0m14.144s sys 0m9.568s
1分22秒という圧倒的に速くなりました。
最後のsedコマンドで%T@の出力を削っているのでパスのみの出力になっています。
この方法が一番目的に適っています。
stat -c "%y %n" "$(find ~ -type f -printf "%T@ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
pq@pq-VirtualBox:~/_tmp$ time stat -c "%y %n" "$(find ~ -type f -printf "%T@ %p\0" | sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')" find: `/home/pq/.cache/dconf': 許可がありません 1980-01-01 00:00:00.000000000 +0900 /home/pq/.config/chromium/CertificateTransparency/680/_metadata/verified_contents.json real 1m32.917s user 0m13.616s sys 0m6.724sこの方法は一番古いファイルの日時を出力しているのにもかかわらず1分32秒で済んでいます。
この方法は先ほどの方法で出力したファイルの日時をstatで取得して出力しているので、その分10秒ロスしています。
参考にしたサイト
ディレクトリ内のファイル数をカウントする
いくつかの方法の速度比較があります。
timeコマンドでプログラムの実行時間を知る
シェルではtimeコマンドで簡単に実行速度測定できます。
timeコマンドにはシェルの組み込みコマンドとGNU版の2種類ある -- ぺけみさお
linuxBean14.04ではシェルスクリプト内でtimeを使うとGNU版と同じ結果になりました。ただし、shebangを#!/bin/bashにするとシェル版になりました。
Linux - xargsとパイプの違いについて(63845)|teratail
xargsでしかパイプできないコマンドの例があります。
find の -exec optionの末尾につく \; と + の違い。
+がxargsに該当します。
Linux - ls: cannot access(49015)|teratail
パスにスペースがあるとパイプでそのまま渡すとエラーになります。
linux - How can I find the oldest file in a directory tree - Super User
%T@でソートする方法が一番速いようです。
bash - How to process each line received as a result of grep command - Stack Overflow
grepの結果をwhile文で1行ずつ処理する方法。
0 件のコメント:
コメントを投稿