コマンドから複数のパスを除外する必要があります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
例を調整して、paths
includeというファイルを作成します。
/.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
確認するために使用されます。そうでない場合は印刷してください。これは拡張の基礎として使用されます。ファイルのパターンと一致しないディレクトリパスにのみ興味がある場合grep
paths
そして複数行を含むパスがない場合は、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