`find` *output* ファイル名からすべてのシンボリックリンクを効率的に逆参照する方法は?

`find` *output* ファイル名からすべてのシンボリックリンクを効率的に逆参照する方法は?

完全に検証され、指定されたディレクトリへの相対パスが必要です。通常、パスの数は100,000を超えるので、これは効率的に行われるべきです。

状態:次の内容を含むディレクトリがあります。最大次のような他のディレクトリへのシンボリックリンク

foo
 123 -> ../baz/123
 896 -> ../bar/896

(fooにはディレクトリへのシンボリックリンクが含まれるだけでなく、キャプチャする必要がある一般的なファイルも含まれています。)

これらのシンボリックリンクディレクトリにはファイルが含まれています。このファイルのリストを次の形式で取得したいと思います。

baz/123/some.file
bar/123/other.file

つまり、「find」がシンボリックリンクを見つけたら、パスを逆参照したいのです。コンテンツを報告するとき

そのため、fooの親ディレクトリで次のコマンドを実行します。

find -L foo -type f

しかし、これはうまくいきません。

-L正直なところ、この動作を達成するには、「シンボリックリンクに従う」と主張するオプションが必要になります。しかし、実際行動するのは見ることです入力するこれらのディレクトリの内容は、その中のファイルと逆参照されていない名前を報告します。結果は次のとおりです。

foo/baz/123/some.file
foo/bar/896/another.file

結果は、ファイルパスのリストをすべての項目に設定するために使用されます。完全に解決しましたそして2.fooの親ディレクトリに相対的したがって、各結果もこの基準を満たす必要があります。この目的のためにすべてのリンクを確認できることを保証できます。丸くても過度に深いものはありません。すべてではありませんが、ほとんどのリンクはファイルではなくディレクトリを指します。

現在私ができる最善の方法は、Pythonスクリプトを使用して参照されていないすべてのパスを確認済みのパスに書き換えることです。しかし、関連文書の量が多いため100000+これはあまり実用的ではありません。 (そして、むしろ面白いです。findすでに参照していない問題が発生したため、逆参照されたパスを返しません。)しかし、間違った方法で外部コマンドを実行するためです)。

私は外部コマンドだけを使ってこれを行うことができるはずですが、ここでは正しい動作がなく、明らかな理由から除外されるfindマニュアルページを見つけることができませんでした。内部コマンドではありません。どんなアイデアがありますか?-L-H-P-follow-printf %l-execfind

編集2:この時点で、Stephenはあなたが見つけなければならない特別な理由がないと私に確信しました。会議この機能は内部的に存在するため、合理的に有効な回答を得ることができます。

ベストアンサー1

find一般的に、あなたが要求するものはあまり意味がないので、規制がないことは驚くべきことではありません。

相対ターゲットを持つシンボリックリンクは、シンボリックリンクのパスに基づいています。たとえば、シンボリックリンクに沿ってディレクトリをナビゲートしていて、相対または絶対シンボリックリンク(またはシンボリックリンクコンポーネントを持つパスを持つシンボリックリンク)である、、、およびをfind見つける場合はどうすればよいですか。a/b/c/daa/ba/b/c

次に拡張されるfind述語またはGNUディレクティブを探している場合-printf %現在のディレクトリへの相対ファイルパスまたは任意のディレクトリへの非符号化リンク、私は恐れていない。

Linuxを使用している場合は、次のようにファイルの絶対パスを取得できます。

find -L foo -type f -exec readlink -f {} \;

realpath見つかったように、複数のパス引数を受け入れるコマンドが1つ以上あり、-exec cmd {} +標準構文と組み合わせると実際のパスコマンドをできるだけ少なく実行するため、より効率的です。

find -L foo -type f -exec realpath {} +

find -L foo -type f -print0 | xargs -r0 realpath

realpath複数のコマンドが必要なように、より高速にすることもできます。find最初のコマンドが機能し始めている間は、さらに多くのファイルを見つけることができるため、単一のプロセッサrealpathシステムでも効率が向上します。

-print0標準ではなく、xargs -r0GNUに由来していますが、他の多くの実装(例えば、ほとんどの最新のBSD)にあります。

Zshにはこれをサポートする機能が組み込まれています。

print -rl foo/***/*(-.:A)

ソート順序が重要でない場合は、次のようにしてソートを無効にして効率を上げることができます。

print -rl foo/***/*(-.oN:A)

現在のディレクトリへの相対パスに変換するには、次を参照してください。だから質問は

これらのすべてのファイルが現在ディレクトリ内に絶対標準パスを持っていることがわかっている場合(そのコンポーネントのどれもシンボリックリンクではない)、次のように単純化できます(続きを使用zsh)。

files=(foo/***/*(-.:A))
print -rl -- ${files#$PWD/}

短くて便利で、ファイル名に含まれるすべての文字で動作しますが、find+より速くなる疑問ですrealpath

Debianrealpathおよび GNU ツールを使用すると、次のことができます。

cd -P .
find -L foo -type f -exec realpath -z {} + | 
  gawk -v p="$PWD" -v l="${#PWD}" -v RS='\0' -vORS='\0' '
    substr($0, 1, l+1) == p "/" {$0 = substr($0, l+2)}; 1' |
  xargs -r0 whatever you want to do with them

これで、あなたが探している機能を備えた最新バージョンのGNU coreutilsがあることに気づいたので、realpathこれは単なる質問です。

find -L foo -type f -print0 |
  xargs -r0 realpath -z --relative-base . |
  xargs -r0 whatever you want to do with them

(相対パスが必要な場合は、シンボリックリンクフリーパスが現在の作業ディレクトリの下にないファイルでも--relative-to .代わりに使用してください。)--relative-base .

おすすめ記事