除外ファイルにリストされているパスを検索するコマンド

除外ファイルにリストされているパスを検索するコマンド

コマンドから複数のパスを除外する必要がありますfind。たとえば、

find "$(pwd)" -not \( \
 -path "*/.git"\
 -o -path "*/.git/*"\
 -o -path "*/.vscode"\
 -o -path "*/.vscode/*"\
 -o -path "*/node_modules"\
 -o -path "*/node_modules/*"\
 -o -path "*/Image"\
 -o -path "*/Image/*"\
 -o -path "*/Rendered"\
 -o -path "*/Rendered/*"\
 -o -path "*/iNotebook"\
 -o -path "*/iNotebook/*"\
 -o -path "*/GeneratedTest"\
 -o -path "*/GeneratedTest/*"\
 -o -path "*/GeneratedOutput"\
 -o -path "*/GeneratedOutput/*"\
 -o -path "*/*_files" \) -type d

しかし、コマンドラインにすべてのパスを一覧表示するのではなく、テキストファイルからこれらのパスを読みたいのです。どうすればいいですか?

答え1

後で呼び出しに使用する配列を設定しますfind。次のスクリプトは、標準入力から改行で区切られたパスパターンを読み取り、次を呼び出しますfind

#!/bin/sh

set --

while IFS= read -r path; do
    set -- "$@" -o -path "$path"
done

shift   # remove initial "-o" from $@

find . -type d ! '(' "$@" ')'

あなたはこれを実行します

./script.sh <paths.txt

どこpaths.txtのように見えますか?

*/.git
*/.git/*
*/.vscode
*/.vscode/*
*/node_modules
*/node_modules/*
*/Image
*/Image/*
*/Rendered
*/Rendered/*
*/iNotebook
*/iNotebook/*
*/GeneratedTest
*/GeneratedTest/*
*/GeneratedOutput
*/GeneratedOutput/*
*/*_files

または、パスパターンはデフォルトではディレクトリ名なので、次のようになります。

#!/bin/sh

set --

while IFS= read -r dirname; do
    set -- "$@" -o '(' -name "$dirname" -prune ')'
done

shift   # remove initial "-o" from $@

find . -type d ! '(' "$@" ')'

スキーマファイルには以下が含まれます。

.git
.vscode
node_modules
Image
Rendered
iNotebook
GeneratedTest
GeneratedOutput
*_files

このコードバリアントはfindファイルのパターンと一致するディレクトリに降りることを停止しますが、最初のスクリプト(およびコード)はそのパスに-path興味がないかどうかにかかわらず、除外されたディレクトリ内のすべてのアイテムに対してパターンをテストします。次のいずれかに興味があります。

答え2

grepとを使用して、パスのリスト(正規表現または固定文字列)に基づいてファイルをフィルタリングfindできます。-exec例を調整して、pathsincludeというファイルを作成します。

/.git$
/.git/
/.vscode$
/.vscode/
/node_modules$
/node_modules/
/Image$
/Image/
/Rendered$
/Rendered/
/iNotebook$
/iNotebook/
/GeneratedTest$
/GeneratedTest/
/GeneratedOutput$
/GeneratedOutput/
/.*_files$

その後実行

find /your/search/path -type d ! -exec sh -c "echo {} | grep -q -f paths" \; -print

これは、以下のディレクトリを検索し、見つかった各ディレクトリのパターンと一致することを/your/search/path確認するために使用されます。そうでない場合は印刷してください。これは拡張の基礎として使用されます。ファイルのパターンと一致しないディレクトリパスにのみ興味がある場合greppathsそして複数行を含むパスがない場合は、grep単一の呼び出しで出力を後処理できます。

find /your/search/path -type d | grep -v -f paths

実際に一部のルートにまったく興味がない場合(つまりパターンは常にディレクトリ名と一致し、そのディレクトリの下のすべてのエントリと一致します。クリーンアップにより、作業をより簡単にすることができます。

find /your/search/path -type d \( -exec sh -c "echo {} | grep -q -f paths" \; -prune -o -print \)

パスには以下が含まれます。

/.git$
/.vscode$
/node_modules$
/Image$
/Rendered$
/iNotebook$
/GeneratedTest$
/GeneratedOutput$
/.*_files$

答え3

あなたができることは、ビルドコマンドを使用し、awkそれfindを「ラッパー」スクリプトまたはシェル関数の変数として渡すことです。

p=$( awk '{printf "-not -path %s ",$0}' "$1" )
find "$PWD"  $p -type d

参照パスのリストがある./find_wrapper.sh paths.txt場所でそれを呼び出します。path.txt

'*/.git'
'*/.git/*'
'*/.vscode'
'*/.vscode/*'
'*/node_modules'
'*/node_modules/*'
'*/Image'
...

なぜこれをしましたか?完全な行を作成する理由awkは、スクリプトでこれを行う理由がないためです。\行連続はコマンドをより体系的に見せるために存在しますが、機能的には何の利点も提供しません。$pここでは実際に単語分割をしたいので引用しませんでした。それ以外の場合は、find別のフラグとパラメータではなく1つの巨大な文字列として扱います。一重引用符の場合グローバルを避けるために二重引用符の中に効果があります。

またはパイプラインで

awk '{printf "-not -path %s ",$0}' "$1" | xargs -L 1  find "$PWD" -type d 

関連情報