findでディレクトリを除外する方法。コマンド


1380

私は実行しようとしています findすべてのJavaScriptファイルに対してコマンドますが、特定のディレクトリを除外するにはどうすればよいですか?

findこれが使用しているコードです。

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

10
除外する必要があるディレクトリは何ですか?
典型的なポール

11
使用することをお勧めしますfind ... | while read -r file ...。また、回答を受け入れて賛成することをお勧めします。
追って通知があるまで一時停止。

読み込みは遅いが、読み込みは速い
mpapis 2010年

18
@mpapisは読み込み中に空白を含む行全体を正しく処理します。
Jean-Philippe Pellet 2012

1
名前にスペースが含まれているファイルを含むフォルダでこれを実行してください:for file in $(find .); do echo "$file"; done。スペースを含む名前は分割されますが、これは望ましくありません。
Jean-Philippe Pellet

回答:


1140

-pruneスイッチを使用します。たとえば、miscディレクトリを除外する場合は-path ./misc -prune -o、検索コマンドにa を追加するだけです。

find . -path ./misc -prune -o -name '*.txt' -print

次に、複数のディレクトリを使用した例を示します。

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

ここでは、dir1dir2、およびdir3を除外しfindます。これは、式では基準と-path dir1 -o -path dir2 -o -path dir3dir1またはdir2またはdir3の場合)、ANDで動作するアクションであるためですtype -d

さらなるアクションは-o print、単に印刷することです。


89
うーん。無視されたディレクトリ「./misc」が出力に含まれるため、これも私にとっては機能しません。
Theuni

84
@Theuni -print後に明示的に(またはその他のアクション)を追加しなかったため、おそらく機能しませんでした-name。その場合、両方の「面」は-o最終的に印刷されますが、を使用すると-print、その面のみが印刷されます。
ダニエルC.ソブラル2013年

4
マンページから: Because -delete implies -depth, you cannot usefully use -prune and -delete together.では、特定のディレクトリを削除から除外したい場合、findで削除するにはどうすればよいですか?
ジャニスElmeris

15
結果からディレクトリ全体を削除するには、次のコマンドを使用しますfind . -not -path "./.git*"。の./dir*代わりにを使用./dir/*すると、ディレクトリとコンテンツが出力から削除されます。
micahblu

64
この質問と回答の混乱は、検索ユーザーインターフェイスがユーザーのニーズとどの程度一致していないかを示しています。
ヨハネスオーバーマン

1932

場合は-pruneあなたのために動作しません、これは以下となります。

find -name "*.js" -not -path "./directory/*"

警告:すべての不要なディレクトリをトラバースする必要があります。


86
受け入れられた回答のコメントの1つが問題を指摘しています。-pruneディレクトリ自体を除外するのではなく、そのコンテンツを除外します。つまり、除外されたディレクトリを含む出力に不要な行が表示されることになります。
GetFree

96
すばらしい答えです。最初に.を変更することにより、任意のレベルでディレクトリを除外できることをこれに追加します*。したがってfind -name "*.js" -not -path "*/omitme/*"、「omitme」という名前のディレクトリから任意のレベルの深さでファイルを除外します。
DeeDee 2013年

83
ただし、それでも不要なディレクトリはすべて通過します。自分の答えを追加します。:-)
ダニエルC.ソブラル2013年

18
ただし、-print明示的に使用しないと、プルーンオプションが機能しないことに注意してください。
ダニエルC.ソブラル

39
「これは-pruneを使用する代わりの方法です」と言ったほうがいいでしょう。-pruneを示唆する回答は明らかに間違いではありません。それらは、あなたがそうする方法ではありません。
神保

458

次のことは、他の提案されたソリューションよりも簡単に推論できます。

find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

重要な注意:入力したパスは、除外せずに印刷するパスと-path完全に一致する必要がありますfind。この文が混乱する場合は次のようにコマンド全体で完全パスを使用するようにしてください。find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...。理解を深めたい場合は、注[1]を参照してください。

インサイド\(\)一致する表現で正確に build/external(上の重要な注意を参照)、および意志、成功時には、以下のものを横断避けます。これは、その後でエスケープ括弧で単一の式としてグループ化され、前置され-notているようになりますfindその式に一致したものをすべてスキップられます。

追加し-notても他のすべてのファイルが-prune再表示されないかどうかを尋ねる人もいるかもしれません。機能する方法-pruneは、一度到達すると、そのディレクトリの下のファイルが永久に無視されることです。

これは、wintersmithによって生成された一部のファイルに対してyui-compressorを呼び出す必要があり、そのまま送信する必要のある他のファイルは除外するという、実際の使用例から来ています。


注[1]:除外/tmp/foo/barしたい場合、次のようにfindを実行すると、find /tmp \(...指定する必要があります-path /tmp/foo/bar。一方、このようにfindを実行する場合は、をcd /tmp; find . \(...指定する必要があります-path ./foo/bar


37
すばらしい回答、ありがとうございます。これは機能し、複数の除外に対してスケーラブル(読み取り可能)です。あなたは紳士であり、学者です。複数の除外の例をありがとう
Freedom_Ben 2013

7
-deleteスイッチを使用する場合、これは機能しません。find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
JānisElmeris

17
@Janisの-exec rm -rf {} \;代わりに使用できます-delete
ダニエルC.ソブラル

11
の出力を調べるとfind、これは本当に明白ですが、私はつまずきました。現在のディレクトリを検索している場合(.検索パスとして指定するか、まったく指定しない場合)は、で-path始まるパターンが必要になる可能性があります./(例:)find -not \( -path ./.git -prune \) -type f
Zantier 2014年

7
このメソッドのより正確な(そしてPOSIX互換の)バリエーション:find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)探しているものと一致するはずの条件が続きます。
Walf、

218

ここでは、ディレクトリをスキップするための推奨構文について、いくつかの混乱があります。

GNU意見

To ignore a directory and the files under it, use -prune

GNU find manページから

推論

-prunefindディレクトリへの下降を停止します。指定-not -pathするだけでもスキップされたディレクトリに下降し-not -pathますが、常にfalseになりますfind各ファイルをテストするます。

の問題 -prune

-prune それが意図したことを行いますが、それを使用するときにまだ注意しなければならないことがあります。

  1. find 除去されたディレクトリーを出力します。

    • TRUEこれは意図された動作であり、その中には含まれません。ディレクトリを完全に印刷しないようにするには、論理的に省略した構文を使用します。
  2. -pruneでのみ動作し-print、他のアクションはありません。

    • 真実ではない-prune以外のすべてのアクションで動作し-deleteます。削除で機能しないのはなぜですか?以下のために-delete仕事に、以来、DFSのために、ディレクトリを横断する必要性を見つける-delete最初など、葉の両親、その後、葉を削除します...しかし、指定するための-prune意味を作るために、findそれを降順ディレクトリとストップをヒットする必要があり、その-depthまたは-delete上では明らかに意味がありません。

パフォーマンス

この質問に対する上位3つの回答の簡単なテストを設定しました(別のアクションの例を示すために置き換え-printまし-exec bash -c 'echo $0' {} \;た)。結果は以下です

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

結論

どちらf10bitの構文ダニエルC.ソブラルの構文は、平均的に実行するように10-25msを取りました。GetFreeの構文は、を使用せず-prune、865msかかりました。だから、はい、これはかなり極端な例ですが、ランタイムを気にし、リモートで集中的に何かをしている場合は、-prune

ダニエルC.ソブラルの構文は、2つの-prune構文のどちらが優れているかに注意してください。しかし、これはいくつかのキャッシングの結果であると強く思います。2つが実行された順序を切り替えると、反対の結果が得られたのに対し、非プルーンバージョンは常に最も低速でした。

テストスクリプト

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

18
非常に良い分析をありがとうございます。「これはいくつかのキャッシュの結果だと強く思います」に関して、次のコマンドを実行できます:sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && free"キャッシュをクリアします(unix。 stackexchange.com/questions/87908/…)。
ndemou 2014年

これら2つについていくつかのテストを行った後、ほとんど-prune違いがないことがわかります。最初にどのコマンドが最初にCPUパフォーマンスの恩恵を受けるか、後のCPUウォームアップ>パフォーマンスの低下により若干のスローダウンが発生することに注意してください(@ndemouの提案に従って各コマンドの前にキャッシュをパージしました)
Huy.PhamNhu

name1() name2() name3()上記の@BroSlowテストスクリプトでスイッチ番号を切り替えて、実行順序を変更し、私が言ったことを視覚的に確認してください。しかし、実際には、この2つを区別することはできません。
Huy.PhamNhu 2017

拍手。この質の高い回答に感謝します。
Stphane

-oであってはなりません。したがって、最初のステップで剪定し、次のステップでそれについてすべて忘れます。
mmm

97

これは私のために働いた唯一のものです。

find / -name MyFile ! -path '*/Directory/*'

「ディレクトリ」を除く「MyFile」を検索しています。星を強調します*。


13
この方法はmacOSで機能しますが、受け入れられた回答は機能しません。元の質問はLinuxに関するものです。
Xavier Rubio Jansana 2018年

5
! -path '*/Directory/*'コマンドに複数を連続して追加して、複数のディレクトリを無視できることに注意してください
Aclwitt

MacOSでは動作しますが、Linuxでは動作しません...確認済み
Marcello de Sales

docker containerのみ動作しますsh -c "find..."
マルチェロデセール

@Marcello de Salesもちろん、Linux上で動作します。
DimiDak

59

1つのオプションは、ディレクトリ名を含むすべての結果をgrepで除外することです。例えば:

find . -name '*.js' | grep -v excludeddir

44
これにより、検索が非常に遅くなります
ドリアン

6
これは私にとってはうまくいきましたが、他のもの(を使用しています-prune)-うまくいきません
アンドロン、2013年

7
大きな結果では遅くなりますが、小さなセットでは役立ちます。しかし、grepを使用して複数のディレクトリを除外する方法は?もちろんこの方法ですfind . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3が、いくつかのgrep方法があるかもしれません。
TimoKähkönen2013年

6
複数のgrepsを実行する場合は、正規表現として記述したほうがよいでしょうegrep -v '(dir1|dir2|dir3)'。ただし、この特定のケーススタディでは、ディレクトリfind自体を除外する方が適切です。
ローレンス

1
はい、括弧は必要ありません。文字列の先頭にあるディレクトリ名と一致するように、^を使用することをお勧めします(例:find)。-name '* .js' | egrep -v "^ \ ./ excludeddir1 | ^ \ ./ excludeddir2"
Sofija

41

私は-not表記を好む...それはもっと読みやすいです:

find . -name '*.js' -and -not -path directory

5
申し訳ありませんが、機能しません。のマニュアルページにfindは、「ディレクトリとその下のファイルを無視するには、-pruneを使用します」とあります。
クリスチャンダベン2012

8
これは間違っています。findがディレクトリに入り、内部のすべてのファイルをたどることを妨げません。
GetFree

find . -iname '*' -and -not -path './somePath'上記のディレクトリに入るのを妨げません。
Lemmings19 2013年

これは私に.gitパスを助けました find . -iname '*' -not -path './.git/*'
M.academyのMark Shust、2013

7
@rane:より具​​体的にfind . -not -path "*/.git*"は、あなたが望むものになるでしょう。
ベン、

20

-pruneオプションを使用します。だから、次のようなもの:

find . -type d -name proc -prune -o -name '*.js'

「-type d -name proc -prune」は、除外するprocという名前のディレクトリのみを検索します。
「-o」は「OR」演算子です。


1
これは、私にとって有効な唯一の「検索」ソリューションです。除外したいディレクトリは、現在の作業ディレクトリのすぐ下にはありません。
ランバート2013

5
ただし、-print最後に追加すると結果が向上する場合があります。find . -type d -name .hg -prune -o -name data(複数の).hgディレクトリの内容を無視しましたが、.hgディレクトリ自体をリストしました。では-print、私が探していた「データ」ディレクトリのみがリストされていました。
ランバート

19

-prune確実に機能し、除外したいディレクトリへの下降を防ぐため、最良の答えです。-not -path除外されたディレクトリを検索しますが、結果は出力されません。除外されたディレクトリがネットワークボリュームにマウントされている場合、または権限がない場合に問題となる可能性があります。

トリッキーな部分はfind、引数の順序に非常に注意が必要であるため、引数を正しく取得しないと、コマンドが機能しない場合があります。引数の順序は一般的に次のとおりです。

find {path} {options} {action}

{path}:すべてのパス関連の引数を最初に置きます。 . -path './dir1' -prune -o

{options}:私は-name, -iname, etcこのグループの最後のオプションとして置くときに最も成功しています。例えば-type f -iname '*.js'

{action}-print使用時に追加する必要があります-prune

これが実際の例です:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print

16

これは、一部のパスを除外するために使用した形式です。

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

これを使用して、「。*」パスにないすべてのファイルを検索しました。

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

私はこれを試しました、そしてそれはまだディレクトリに降りるので、速度は確実に改善されません。
Br.Bill 2018

10

-path -pruneアプローチは、パス内のワイルドカードでも機能します。以下は、git内部ディレクトリを除いた複数のgitリポジトリを提供するgitサーバーのディレクトリを見つけるfindステートメントです。

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

9

複数のディレクトリを除外するには:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

ディレクトリを追加するには、次を追加し-o -path "./dirname/*"ます。

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

ただし、除外するディレクトリが多い場合は、正規表現を使用する必要があります。


9

良い答えはたくさんありますが、コマンドの各要素の目的とその背後にあるロジックを理解するのに少し時間がかかりました。

find . -path ./misc -prune -o -name '*.txt' -print

findは、現在のディレクトリ、つまりfind .

-oオプションは、論理和の略で、コマンドの2つの部分を分離します:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

ある任意のディレクトリやファイルではない ./miscディレクトリが最初のテストに合格しません-path ./misc。しかし、それらは2番目の式に対してテストされます。それらの名前*.txt-printオプションのために印刷されるパターンに対応している場合。

findが./miscディレクトリに到達すると、このディレクトリは最初の式のみを満たします。したがって、-pruneオプションがそれに適用されます。そのディレクトリを探索しないようにfindコマンドに指示します。そのため、。/ misc内のファイルまたはディレクトリは、findによって探索されず、式の2番目の部分に対してテストされず、印刷されません。


誰もが解決策を持っていますが、あなたの解決策が最もよく説明されています。-pathではなく-nameを最初に使用することを強く求めました。あなたの説明は私が欲しかったものに到達するのに十分でした。見つける -name "* .txt" -print -o -path ./misc -prune
Vendetta V

7

実用的なソリューション(Ubuntu 12.04(Precise Pangolin)でテスト)...

find ! -path "dir1" -iname "*.mp3"

は、dir1サブフォルダーを除く現在のフォルダーとサブフォルダーでMP3ファイルを検索します。

使用する:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... dir1 AND dir2を除外する


うまくいきません。上記のいずれの回答も行いません。RedHat。
Tharpa

6

剪定のディレクトリを印刷避けるための良いトリックは使用することです-print(のための作品-execの右側の後だけでなく)を-orした後-prune。例えば、 ...

find . -path "*/.*" -prune -or -iname "*.j2"

は、現在のディレクトリの下にあるすべての非表示のディレクトリをスキップして、拡張子が.j2のすべてのファイルのパスを印刷します。ただし、上記のように、スキップする各ディレクトリのフルパスも印刷されます。ただし、次はしません...

find . -path "*/.*" -prune -or -iname "*.j2" -print

論理的に-andは、-iname演算子の後ろと-printの前に隠しファイルがあるからです。これは-or、操作のブール順序と結合性により、それを句の右側の部分にバインドします。しかし、ドキュメント-print(またはそのいとこ... -print0など)が指定されていない場合、隠しファイルがあるとドキュメントは言います。それでは、なぜ-or印刷の左側部分がないのですか?どうやら(そして、私が最初にmanページを読んでもこれを理解していなかった)、それは-print-または- スタイルの操作が句で表現されていない場合に当てはまり、隠された論理的なものはすべて消えて、指定します。正直なところ、私は逆にそれを好んだかもしれませんが、それから-exec ANYWHEREその場合、printは論理的にまとまってすべてが印刷されるようになります。一つでもprintfind説明演算子だけでは何もない場合は、明らかに何もしないのでので、私はそれが理にかなっていると思います。上記のように、これはすべて-exec同様に機能するので、以下はls -la目的の拡張子を持つ各ファイルの完全なリストを提供しますが、各隠しディレクトリの最初のレベルをリストしません...

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

私(およびこのスレッドの他の人)にとって、find構文はかなりバロックになるので、常に括弧を入れて、何が何にバインドするかを確実に理解できるようにするため、通常、型機能のマクロを作成し、のようなステートメントをすべて作成します。 ..

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

このように世界を2つの部分に設定することで、間違いを犯すことは困難です。これがお役に立てば幸いですが、誰もが30番目以上の回答を読んで投票することはありそうにありませんが、期待することはできます。:-)


5

これを行うには、プルーンオプションを使用できます。例えばのように:

find ./ -path ./beta/* -prune -o -iname example.com -print

または逆grepの「grep -v」オプション:

find -iname example.com | grep -v beta

詳細については、Linuxのfindコマンドでディレクトリを検索から除外してください


grepソリューションは、同じ名前のすべてのディレクトリを除外する唯一のソリューションです。「node_modules」を除外しようとすると非常に便利です。
bmacnaughton 2017年

3
@bmacnaughton-真実ではない!私は特に「node_modules」を除外するためにここに来て、多くの細かい回答を読んだ後、解決しましたfind . -type f -print -o -path "*/node_modules" -prune...ワイルドカードを使用して、これはどのレベルでも「node_modules」をスキップします。-print最初の代替で使用すると、-type f -printその部分のみが印刷されるため、「node_modules」ディレクトリ自体はリストされません。(それはまた、逆にすることができる。find . -path "*/node_modules" -prune -o -type f -print
スティーブン・P

* /そこで何をしているのか。除外したい正確なファイルは何ですか?ypuはそれをワイルドカードとして使用していますか?
Siju V

1
@StephenP、これを指摘してくれてありがとう。使用./node_modulesと使用の違いを学びました*/node_modules。私の場合、node_modules検索を開始するディレクトリ(およびそのnode_modulesディレクトリの下)にのみ存在する場合、他のディレクトリの下にディレクトリfind . -type f -print -o -path "./node_modules" -prune がないため、使用できますnode_modules
bmacnaughton

1
@SijuV-私が検索していたnode_modulesディレクトリにはサブディレクトリがありましたが、独自のnode_modules ...を使用して./node_modulesいるサブディレクトリもありnode_modules、現在のディレクトリの下のサブディレクトリのみに一致し、それを整理します.グロブとしてのは、プレフィックスだけでなく、などの先頭のパスプレフィックスにも一致する*/node_modulesため、match を使用してディレクトリを任意の深さでプルーニングします。ワイルドカードですが、グロブなどではない正規表現として。*./test5/main/node_modules./*
スティーブンP

5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

これを機能させることができません。find ~/Projects -name '*.js' -\! -name 'node_modules' -pruneはまだnode_modulesパスにあるファイルを表示しています
mpen 2017年

1
@mpen、stackoverflow.com / questions / 4210042 /…から、必要な構文は次のとおりですfind ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print。そのパスの名前は、ディレクトリを印刷する場合にfindが印刷するものと正確に一致する必要があります。
PatS

4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

と同じように機能するようです

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

IMOを覚えやすくなります。


4

TLDR:-path <excluded_path> -prune -oオプションを使用して、ルートディレクトリを理解し、そこから検索を調整します。/除外されたパスの最後に末尾を含めないでください。

例:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


を効果的に使用するfindには、ファイルシステムのディレクトリ構造を十分に理解することが不可欠であると考えています。自宅のコンピューターにはマルチTBのハードドライブがあり、その約半分がrsnapshot(つまりrsync)を使用してバックアップされています。物理的に独立した(重複した)ドライブにバックアップしていますが、システムのルート(/)ディレクトリの下にマウントされています/mnt/Backups/rsnapshot_backups/

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

/mnt/Backups/rsnapshot_backups/現在、ディレクトリは約2.9 TBを占め、約60Mのファイルとフォルダが含まれています。これらのコンテンツを単にトラバースするには時間がかかります。

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

したがって、自分の/(ルート)パーティションでファイルを検索する必要があるときはいつでも、バックアップパーティションのトラバースを処理する(可能な場合は回避する)必要があります。


このスレッドでさまざまに提案されているアプローチ(find。コマンドでディレクトリを除外する方法)の中で、受け入れられた回答を使用した検索ははるかに高速であることに気付きました。

解決策1

システムファイルを見つけlibname-server-2.aたいが、rsnapshotバックアップ全体を検索したくないとします。システムファイルをすばやく見つけるには、除外パスを使用します/mnt(つまり、、/mntnot /mnt/、または/mnt/Backups、...を使用します)。

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

...このファイルはほんの数秒で見つかりますが、これにはかなり時間がかかります(「除外された」ディレクトリすべてを再帰するように見えます):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

解決策2

このスレッドで提供される他のソリューション(SO#4210042)もパフォーマンスが低下します。

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

概要| 結論

ソリューション1」に示されているアプローチを使用する

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

すなわち

... -path <excluded_path> -prune -o ...

/除外されたパスにトレーリングを追加するたびに、findコマンドは(すべての)/mnt/*ディレクトリを再帰的に入力することに注意してください-私の場合、/mnt/Backups/rsnapshot_backups/*サブディレクトリのため、検索するファイルが〜2.9 TB追加されます!末尾に追加しないことにより/、検索はほぼ即座に(数秒以内に)完了するはずです。

「ソリューション2」(... -not -path <exclude path> ...)も同様に、除外されたディレクトリを再帰的に検索するように見えます。除外された一致は返されませんが、検索時間が不必要に消費されます。


それらの中を検索 rsnapshotバックアップ:

毎時/毎日/毎週/毎月のrsnapshotバックアップの1つでファイルを見つけるには:)

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

ネストされたディレクトリを除外する:

ここでは、ネストされたディレクトリを除外/mnt/Vancouver/projects/ie/claws/data/*/mnt/Vancouver/projects/ます。

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

余談:-printコマンドの最後に追加すると、除外されたディレクトリの出力が抑制されます。

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a

遅くなるのはファイルのサイズではなく、調べる必要のあるディレクトリエントリfind数です。したがって、数ギガバイトのファイルを数個持っている場合よりも、多くの小さなファイルがたくさんある場合(特に、それらがすべて多重リンクされている場合!)の方がはるかに悪いです。
Toby Speight 2018年

@TobySpeight:良い点。スケールを示すために検索スペースのサイズについて言及しました。これには、多くのファイルも含まれます。ルート(/)をすばやく検索すると、sudo ls -R / | wc -l〜76.5Mのファイルが示されます(ほとんどが「非構成」システムファイルを除いてバックアップされます)。は〜2.35Mファイル/mnt/Vancouver/ls -R | wc -l示します。/home/victoria/0.668Mファイルが含まれています。
Victoria Stuart

4

正規表現を使用して、次のようなものを使用して、一部のファイルを含める/除外する/ dirs検索を行うこともできます。

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

これは、すべてのjs、vue、cssなどのファイルのみを提供しますが、 node_modulesおよびvendorフォルダー内のます。


3

findのファイルリストの提供に使用していたためxgettext、特定のディレクトリとその内容を省略したいと考えていました。との-path組み合わせの多くの順列を試しました-pruneたが、行きたいディレクトリを完全に除外することはできませんでした。

無視したいディレクトリの内容を無視することはできましたfindが、結果の1つとしてディレクトリ自体を返しました。xgettext結果としてクラッシュしました(ディレクトリを受け入れず、ファイルのみ)。

私の解決策はgrep -v、結果に必要のないディレクトリをスキップするために単に使用することでした:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

その議論がfind100%うまくいくかどうかは確かではありません。grepいくつかの頭痛の後、使用は迅速で簡単な解決策でした。


3

Ubuntuでは、これまでの回答はどれも適切ではありません。これを試して:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

私はここでこれを見つけまし


100ポイントを超える回答がUbuntuで機能しない理由はわかりません。
Axel Beckert、2015

うーん見ましょうか。たぶん全部試したからでしょうか?
sixro

findは、すべてのLinuxディストリビューション(GNUプロジェクトからのもの)のどこでも同じ実装です。唯一の違いはバージョンです。しかし、過去10年間の変化は、おそらく許可の一致を除いて、それほど侵襲的ではありませんでした。
Axel Beckert

3

これはMacでの私に適しています。

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

接尾辞が。の検索名を除外vendorしてapp/cachedirしますphp


'* .php'を一重引用符で囲むと、探しているものが見つかりません。
Br.Bill 2018

3

古いバージョンのUNIXで-pathまたは-notを使用できないユーザー向け

SunOS 5.10 bash 3.2およびSunOS 5.11 bash 4.4でテスト済み

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

指定されたディレクトリより多くを渡すことができます。
MUYベルギー

2

How-to-Use-Prune-option-of-find-in-shは、Laurence Gonsalvesがどのように-prune機能するかについての優れた回答です。

そして、これが一般的な解決策です:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

/path/to/seach/複数回入力しないようにするにfindは、をpushd .. popdペアで囲みます。

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

1
stackoverflow.com/questions/4210042/…から、に使用される構文-pathは、ディレクトリを出力する場合に出力される名前と一致する必要があることを知りました。たとえば find . -path ./.git -prune -o -print、または find $HOME/foo -path $HOME/foo/.git -prune -o -print いくつかの回答は、-path somedir残念ながら役に立つほど正確ではありません。
PatS

2

私が必要としているものについてはlandscape.jpg、ルートから始まり、/varディレクトリ内の検索を除外して、すべてのサーバーを検索します。

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type dリストのすべてのDでirectories/

grep -v /var リストから「/ var」を除外します

xargs -I '{}' find '{}' -name landscape.jpgfind各ディレクトリ/リストからの結果などの任意のコマンドを実行する


少し待って、/まだ除外されていません。あなたが必要な場合がありsed 1dます。
シンバ

2

次のコマンドが機能します。

find . -path ./.git -prune -o -print

検索に問題がある場合は、-D treeオプションを使用して式分析情報を表示します。

find -D tree . -path ./.git -prune -o -print

または、-D allすべての実行情報を表示します。

find -D all . -path ./.git -prune -o -print

1

次のコマンドを使用して、Cソースファイルで関数名を除外し、*。oを除外し、*。swpを除外し、(通常のファイルではなく)除外し、dir出力を除外しました。

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

1

ループexecよりもアクションを使用するほうがいいforです。

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

exec ... '{}' ... '{}' \;かっこを置き換え、すべての一致するファイルに対して一度実行されます'{}'現在のファイル名で。

中括弧は、シェルスクリプトの句読点*として解釈されないように、単一引用符で囲まれていることに注意してください。


ノート

*find (GNU findutils) 4.4.2マニュアルページの「例」セクションから


1
非常に古い質問ですが、まだ改善の余地があります。同様の問題を解決しようとしてたまたま見つけましたが、どれも満足のいくものではありませんでした。
アルベルト

私はこのexecアクションを頻繁に使用しており、非常に便利です。{}与えるファイルパスにスペースがある場合は、通常、の間に引用符を追加します"{}"
Ludovic Kuty

@lkuty私はあなたのコメントを反映するように私の投稿を編集しようとしていましたが、簡単なテスト(引用なし{}で、名前に空白が含まれるファイルに対して機能します)とmanページを調べたところ、引用は避けるためにのみ必要であるようですそれらはシェルスクリプトの句読点として誤って解釈されます。このケースでは、使用する単一引用符:'{}'
アルベルト・

cpor mvまたはor を作成するために使用しなければならなかったと思いますrm。私はそれをチェックします
Ludovic Kuty

1

上記のコマンドを試してみましたが、「-prune」を使用するコマンドはどれも機能しません。最終的に私は以下のコマンドでこれを試しました:

find . \( -name "*" \) -prune -a ! -name "directory"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.