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

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

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

システム全体で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 として扱います。

答え2

あなたの使命は、最初の文字が大文字のサブディレクトリを見つけて、/このサブディレクトリのパス名を抽出することですX

の場合、最初の文字を大文字で書いたディレクトリが何千ものではfindないと仮定すると、これを行います。/

find /[[:upper:]]*/X -prune -type d -print 

上記では、一連のfind最上位検索パスを使用して呼び出しました。このパス名は、実際に探しているディレクトリ名と正確に一致します。唯一の作業findは、それぞれを調べて目次を印刷することです。

find完全にスキップして使用することもできます。

printf '%s\n' /[[:upper:]]*/X/

ここで唯一の違いは、パターンがディレクトリへのシンボリックリンクと一致できることです。これが重要な場合は、一致する名前に対してより明示的なテストを実行し、bash隠された名前も一致するようにシェルに指示できます。

shopt -s nullglob

for name in /[[:upper:]]*/X/; do
    [ -L "$name" ] && continue
    printf '%s\n' "$name"
done

あなたの質問を何度も読んだ後、私はあなたが検索したいかどうかわからなかったことに気づきました。X 再帰的または。上記の議論では、私はあなたがそうすると思いますいいえ再帰的に検索したいです。

もしあなたならする再帰的に検索するには、次のようにします。

find /[[:upper:]]* -name X -type d -print

検索をより少ない最上位の検索パスに制限したり、使用している既知のパスをクリーンアップしない限り、この作業を高速化する方法はありません。知る検索したくありません。たとえば、tmpディレクトリを入力しないでください。

find /[[:upper:]]* -name X -type d -print -o -name tmp -prune

検索を単一のファイルシステムに制限できます。

find /[[:upper:]]* -xdev -name X -type d -print -o -name tmp -prune

ここで、最上位の検索パスの検索はファイルシステムの境界を超えません。

関連情報