別の検索でパイプ検索が機能しません。

別の検索でパイプ検索が機能しません。

私のユースケースは次のとおりです。

システム全体でXというディレクトリを検索します。

もちろん、次の行は動作します。

find / -type d -name "X"

ただ、速度が少し遅い方で、リソースをたくさん使うようです。

スピードを上げるために、検索結果を別のディレクトリに送信して、可能な検索結果をフィルタリングすることを検討しました。たとえば、ルートディレクトリで大文字で始まるディレクトリのみを見つけるには、その中で次のディレクトリを探します。X

find / -maxdepth 1 -type d -name "/[A-Z]*" | xargs find -type d -name "X"

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

私はすでにそれを見ましたfindの出力を別のfindにパイプする方法ただし、検索のためのパイプラインガイドラインが見つかりません。

照会を別の照会にパイプするにはどうすればよいですか?

ベストアンサー1

あなたできるfindこの構文を使用せずに、他の結果に従って実行されますfind

find / -maxdepth 1 -type d -name "/[A-Z]*" | xargs find -type d -name "X"

xargsまず、出力されるファイル名に空白文字、引用符、またはバックスラッシュ(または一部の実装では文字以外の文字)が含まれていない限り、コマンドや他のコマンドの出力に同様の方法を使用することはできません。findfind

xargs任意のファイルを処理するには、出力の非標準オプションのみを使用できます(これも非標準です)。出力自体はまったく後処理できません(参照:-0find -print0-print0find -print検索結果を繰り返すのはなぜ悪い習慣ですか?)。

さらに、xargsここでは追加2番目のコマンドのファイルパスを選択しfind、フィルタ条件を形成する述語の後に配置します。find作業するファイルのリストを提供する必要があります。今後任意の述語。

xargsより一般的には、/(および一部の/)述語を使用して見つかったファイルに対してコマンドを実行するための独自の組み込みサポート(より信頼性が高く、より効率的)があるため、出力に使用する必要はほとんどありません。findfind-exec-ok-execdir-okdir

ただし、同様に、xargs2番目のファイルのリストが述語の前にあることを確認する必要があるため、find次のようにする必要があります。

find / -maxdepth 1 -name '[[:upper:]]*' -type d -exec sh -c '
   exec find "$@" -name X -type d' sh {} +

-exec cmd {} +できるだけ多くのパスを渡すためにlike形式を使用しますが、最後にのみ渡すことができます。 2番目の正しい位置に移動するために使用されます。-execxargscmdshfind

また、-nameフルパス(必要なパス-path)ではなくファイル名が一致することに注意してください。したがって、大文字で始まるファイル名を一致させるためには[[:upper:]]*必要ありません/[[:upper:]]*(通常はロケールに応じて一致は非常にランダムです)。[A-Z]*

GNUの次のバージョンfind(または現在の開発バージョン)を使用すると、次のこともできます。

find / -maxdepth 1 -name '[[:upper:]]*' -type d -print0 |
  find -files0-from - -name X -type d

ここでは、単一の呼び出しでプロセス全体を完了できますfind

find / -path '/[![:upper:]]*' -prune -o -name X -type d -print

Xというディレクトリを見つける前に、find名前が大文字以外の文字で始まるディレクトリで始まるツリーの枝を切り取るように指示します。/

一部のシステム(GNUシステムのGNUを含む)の一部の実装では、find現在のロケールに無効なテキストであるファイル名の部分を一致させることができない場合があります。find*

たとえば、上記のコマンドは大文字でなくても/stéphane/Xiso8859-1でエンコードされ、現在のロケールが文字マップとしてUTF-8を使用している場合(0xe9バイトを文字としてデコードできず、一致しない可能性があります)。同じ理由で見つかりません。sé*/Stéphane/X

zshglobには、文字でデコードできないすべてのバイトが未定義の文字として扱われるため、この問題はありません。したがって、次のようにすることができます。

print -rC1 /[[:upper:]]*/**/X(ND/)

または、リストを並べ替える必要がない場合は、いくつかoの最適化を実行できます。

print -rC1 /[[:upper:]]*/**/X(ND/oN)

これには/SymLink/.../Xディレクトリが含まれます。これを防ぐには:

(){print -rC1 $^@/**/X(ND/oN)} /[[:upper:]]*(N/oN)

または:

print -rC1 /[[:upper:]]*(N/oNe['reply=($REPLY/**/X(ND/oN)'])

これは2段階のfindアプローチと似ています。名前が glob で大文字で始まるディレクトリを探し、その中のすべての X ディレクトリを別々の glob として扱います。

おすすめ記事