親ディレクトリに特定のファイルが含まれている場合に検索結果からディレクトリを除外する方法

親ディレクトリに特定のファイルが含まれている場合に検索結果からディレクトリを除外する方法

findコマンドを使用してディレクトリツリーを再帰的に検索し、指定された名前と一致するディレクトリのすべての結果を返します。

find . -type d -name '<NAME>'

ログファイルに印刷される返されたパスのリストを取得します。親ディレクトリにomit.txtというファイルを含む結果を無視できるようにしたいです。

./parent_directory/名前>

私はこれを持って努力してきました。

find . -type d -name '<NAME>' \( ! -wholename "*omit.txt*" -prune \)

ファイルを含む結果を無視するためにpruneコマンドを使用しようとしていますが、この方法はディレクトリにのみ適用されるようです。どんな助けでも大変感謝します。 1つのコマンドでこれを行い、出力ファイルをできるだけ維持したいと思います。

答え1

find作業中にディレクトリ内のファイルを表示できる必要があるため、内部でこれを正しく実行することはできないと思います。-pruneディレクトリ自体は機能する必要がありますが、他の条件ではディレクトリ自体に置かれたファイル名のみが表示されます-pathfind

私が考えることができるのは、シェルを分離してディレクトリの内部を見るだけです。このような:

$ mkdir -p x y/z ; touch x/foo y/omit.txt
$ find -type d \( -exec sh -c '[ -e "$1/omit.txt" ]' sh {} \; -prune -o -print \)
.
./x

foo -o barbar成功は評価されないため、fooディレクトリがクリーンアップされると印刷は実行されません。-o -print最後に追加すると、ディレクトリの内容も印刷できます。exec ... {} +各ディレクトリの条件として個別に必要なため、ここでは使用できません。

答え2

システムでbusyboxが利用可能な場合は、次のことができます。

busybox find . -type d '(' -exec [ -e '{}/omit.txt' ] ';' -prune \
  -o -name '<NAME>' -print ')'

busyboxはfindGNUと同様に{}ファイルパスまで拡張されます。部分この主張はこれに頼る必要を避けますshが、もっと重要なのは、最新バージョンではfork()またはexecve()なしで小さなプログラムを実行できるため、他のほとんどの実装Magnitudeよりも数倍効率的です[find

名前付きディレクトリ<NAME>自体にaが含まれている可能性があり、omit.txtその場合はそれを印刷したい場合は、まだ切り捨てられても次のように変更できます。

busybox find . -type d '(' -exec [ ! -e '{}/omit.txt' ] ';' -o -prune ')' \
  -name '<NAME>'

bash以外のboshシェルにはfind(li​​ke [)が組み込まれており、-callその述語を分岐することなくいくつかのシェルコードを実行できます。これはfork()とexecve()も節約します。

find . -type d '(' -call '[ -e "$1/omit.txt" ]' {} ';' -prune \
  -o -name '<NAME>' -print ')'

より移植性に優れた代替手段findは のFile::Findモジュールを使用することです。

perl -MFile::Find -le '
  find sub {
    if (-e "$_/omit.txt") {
      $File::Find::prune = 1;
    } else {
      print $File::Find::name if ($_ eq "<NAME>") && -d;
    }
  }, @ARGV' -- .

答え3

@ilkkachuがしばらく私を悩ませてきた質問に素晴らしい答えを与えました!彼らにぜひ投票してください。私は他の人に役立ついくつかのバリエーションを追加したかったです。 :)

出力例は、次の構造に基づいています。

./
├── a/
│   ├── b/
│   │   └── world.txt
│   └── hello.txt
├── foo.txt
└── some_git_repo/
    ├── .git/
    ├── README
    └── c/
        └── some_git_submodule/
            ├── .git/
            └── README

git reposを除くすべてのディレクトリを印刷します。

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -print \)
.
./a
./a/b

1. git reposを含むすべてのディレクトリを印刷します。

2. Gitリポジトリに再帰しないでください。

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -print \)
.
./a
./a/b
./some_git_repo

gitリポジトリのファイルを除くすべてのファイルを印刷します。

find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt

1. git reposのファイルを除くすべてのファイルを印刷します。

2.除外されたgitディレクトリの印刷

find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt
./some_git_repo

それから反対...

すべてのGitリポジトリを印刷

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune \)
./some_git_repo

サブモジュールを含むすべてのgitリポジトリを印刷します。

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print \) -o \( -name '.git' -prune \)
./some_git_repo
./some_git_repo/c/some_git_submodule

関連情報