ディレクトリ内のすべてのファイルの相対パスを取得しようとしています。何十万ものファイルを実行できるため、高速化する必要があります。
試してみfind .
ましたrg --files
(rg
存在するripgrep
)rg
約6倍速いです。
これをよりよくしたり速くしたりするための基本的な方法はありますか?
ベストアンサー1
これはトリックであり、更新されたロケーションデータベースがあるとします。場所)、しかし、ディレクトリの内容のキャッシュを解析するので、最も高速です。
locate "$PWD/*" |awk -v len="${#PWD}" '{ print substr($0, len+2) }'
データベースは毎日更新されるため、事前に実行するlocate
必要があります。ファイルシステム全体がインデックス化されているため、明らかに時間がかかる可能性があります(ripgrepほど高速ではない可能性があります)、何度も実行する必要がある場合は、一度キャッシュしてsudo updatedb
も問題ありません。
このawk
コードは、指定されたパスに基づいてヒット数を印刷します。次の機能で作成できます。
# Usage: indir [DIRECTORY]
# Show recursive contents of DIRECTORY (defaults to current directory)
indir() {
d="$(readlink -f "${1:-$PWD}")"
locate "$d/*" |awk -v len="${#d}" '{ print substr($0, len+2) }'
}
readlink -f
(GNU Coreutilsでは)入力は正規化されているため、indir .
orを実行でき、引き続き機能indir ../foo
します(出力はDIRECTORYに基づいているため、../foo/bar/baz
と表示されますbar/baz
)。
この回答の説明で述べたように、クエリパス名にワイルドカード文字(?
またはまたは)が含まれると*
問題が発生します。[…]
バックスラッシュを使用してエスケープすることでこの問題を解決できます(ただし、長さが変更されることに注意してください)。
または、libpcreサポートでコンパイルされている場合は、GNU grepを使用してこれを実行できます。
# Usage: indir [DIRECTORY]
# Show recursive contents of DIRECTORY (defaults to current directory)
indir() {
d="$(readlink -f "${1:-$PWD}")"
locate "$d/*" |grep -Po "^\Q$d/\E\K.+"
}
PCREを使用してgrepを実行し、一致するもののみを印刷します。正規表現はもう少し複雑です。正規表現 101 説明)。これは行の先頭(^
)でのみ一致し、これはリテラル文字列の一致(\Q…\E
および間の正規表現の解釈を許可しない)になり、一致として報告する必要がある項目の開始を示します。結局、そのルートの後のすべてのものと一致します。これはgrepが報告する唯一のものです。ディレクトリ名自体と一致しないことを確認するためにリテラルを入れました。ただし、これはmatchなどの他のパスと一致しないようにします。\Q
\E
\K
.+
/
\Q…\E
/path/to/dirt
/path/to/dir