私のユースケースは次のとおりです。
システム全体で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
まず、出力されるファイル名に空白文字、引用符、またはバックスラッシュ(または一部の実装では文字以外の文字)が含まれていない限り、コマンドや他のコマンドの出力に同様の方法を使用することはできません。find
find
xargs
任意のファイルを処理するには、出力の非標準オプションのみを使用できます(これも非標準です)。出力自体はまったく後処理できません(参照:-0
find -print0
-print0
find -print
検索結果を繰り返すのはなぜ悪い習慣ですか?)。
さらに、xargs
ここでは追加2番目のコマンドのファイルパスを選択しfind
、フィルタ条件を形成する述語の後に配置します。find
作業するファイルのリストを提供する必要があります。今後任意の述語。
xargs
より一般的には、/(および一部の/)述語を使用して見つかったファイルに対してコマンドを実行するための独自の組み込みサポート(より信頼性が高く、より効率的)があるため、出力に使用する必要はほとんどありません。find
find
-exec
-ok
-execdir
-okdir
ただし、同様に、xargs
2番目のファイルのリストが述語の前にあることを確認する必要があるため、find
次のようにする必要があります。
find / -maxdepth 1 -name '[[:upper:]]*' -type d -exec sh -c '
exec find "$@" -name X -type d' sh {} +
-exec cmd {} +
できるだけ多くのパスを渡すためにlike形式を使用しますが、最後にのみ渡すことができます。 2番目の正しい位置に移動するために使用されます。-exec
xargs
cmd
sh
find
また、-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/X
iso8859-1でエンコードされ、現在のロケールが文字マップとしてUTF-8を使用している場合(0xe9バイトを文字としてデコードできず、一致しない可能性があります)。同じ理由で見つかりません。s
é
*
/Stéphane/X
zsh
globには、文字でデコードできないすべてのバイトが未定義の文字として扱われるため、この問題はありません。したがって、次のようにすることができます。
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
ここで、最上位の検索パスの検索はファイルシステムの境界を超えません。