findを使用して、パスに特定のディレクトリがあるがファイルパスに他の特定のディレクトリが含まれていないすべてのファイル名を返そうとします。それは次のとおりです。
myRegex= <regex>
targetDir= <source directory>
find $targetDir -regex $myRegex -print
ある find コマンドを別のコマンドにパイプすることでこれを行うこともできますが、単一の正規表現を使用してこれを実行する方法を知りたいです。
たとえば、すべてのファイルのパスに「good」ディレクトリがありますが、組み合わせに関係なく、パスのどこにも「bad」ディレクトリがないことを望みます。いくつかの例:
/good/file_I_want.txt #Captured
/good/bad/file_I_dont_want.txt #Not captured
/dir1/good/file_I_want.txt #Captured
/dir2/good/bad/file_I_dont_want.txt #Not captured
/dir1/good/dir2/file_I_want.txt #Captured
/dir1/good/dir2/bad/file_I_want.txt #Not captured
/bad/dir1/good/file_I_dont_want.txt #Not captured
一部のファイル名には「良い」または「悪い」を含めることができますが、ディレクトリ名だけを考慮したいと思います。
/good/bad.txt #Captured
/bad/good.txt #Not captured
私の研究では、否定的な予測と否定的な予測を使用する必要があることがわかりました。しかし、これまで試したことは何も機能しませんでした。助けてくれてありがとう。ありがとうございます。
答え1
Inianが言ったように、そうする必要はありません-regex
(非標準であり、構文はサポートされている実装によって大きく異なります-regex
)。
これを使用することもできますが、名前付きディレクトリに移動しないように指示すること-path
もできます。これは、後でそのファイルをフィルタリングできるように、その中のすべてのファイルを検索するよりも効率的です。find
bad
-path
LC_ALL=C find . -name bad -prune -o -path '*/good/*.txt' -type f -print
(LC_ALL=C
したがって、ワイルドカードは、バイトfind
シーケンスが*
ロケールで有効な文字を形成しないファイル名をブロックしません。)
または複数のフォルダ名の場合:
LC_ALL=C find . '(' -name bad -o -name worse ')' -prune -o \
'(' -path '*/good/*' -o -path '*/better/*' ')' -name '*.txt' -type f -print
を使用すると、zsh
次の操作も実行できます。
set -o extendedglob # best in ~/.zshrc
print -rC1 -- (^bad/)#*.txt~^*/good/*(ND.)
print -rC1 -- (^(bad|worse)/)#*.txt~^*/(good|better)/*(ND.)
または配列リストの場合:
good=(good better best)
bad=(bad worse worst)
print -rC1 -- (^(${(~j[|])bad})/)#*.txt~^*/(${(~j[|])good})/*(ND.)
到着いいえbad
または(など効率が悪い)という名前のディレクトリを入力します-path '*/good/*' ! -path '*/bad/*'
。
print -rC1 -- **/*.txt~*/bad/*~^*/good/*(ND.)
中zsh -o extendedglob
、~
うんとは別に(NAND)ワイルドカード演算子while^
は否定演算子であり、#
regexpのようにゼロ個以上の先行コンテンツです*
。${(~j[|])array}
配列の要素を連結し|
、|
それをリテラルではなくグローバル演算子として扱うために|
使用されます~
。
では、zsh
一致後にPCREを使用できますset -o rematchpcre
。
set -o rematchpcre
regex='^(?!.*/bad/).*/good/.*\.txt\Z'
print -rC1 -- **/*(ND.e['[[ $REPLY =~ $regex ]]'])
ただし、すべてのファイル(ディレクトリ内のファイルを含む)のシェルコードを評価することは、bad
他のソリューションよりはるかに遅くなる可能性があります。
また、PCRE(zsh globとは反対)は、ロケールで有効な文字を形成しないバイトシーケンスをブロックし、UTF-8以外のマルチバイト文字セットをサポートしないことに注意してください。ロケールをC
上記のように変更すると、find
この特定のモードの問題が解決されます。
[[ =~ ]]
のように拡張正規表現マッチングを実行したい場合は、PCREマッチングを実行する代わりにPCREモジュール()をbash
ロードして使用することもできます。zmodload zsh/pcre
[[ -pcre-match ]]
[[ =~ ]]
または、次のコマンドを使用してフィルタリングできますgrep -zP
(GNUgrep
または互換性があると仮定)。
regex='^(?!.*/bad/).*/good/.*\.txt\Z'
find . -type f -print0 |
LC_ALL=C grep -zPe "$regex" |
tr '\0' '\n'
(find
すべてのディレクトリbad
内のすべてのファイルがまだ見つかりますが)。
これらのファイルに対して操作を実行する必要がある場合(1行に1つずつ印刷することを除く)tr '\0' '\n'
に置き換えます。xargs -r0 cmd
find
とにかく、私はツアー演算子として必要なPerl様またはVim様の正規表現をサポートする実装を知りません。
答え2
このために正規表現を使用する必要はありません。述語を使用して、任意の-path
レベルで特定の名前のディレクトリを除外できます。
find . -type f -path '*/good/*' '!' -path '*/bad/*'
答え3
おそらく強力なフィルタリングよりも効率が低く(確かではありませんが)、「正確さ」は少なくなりますfind
(たとえば、grep
ここで無実の内容は改行文字を含む名前には適用されません。より簡単です。grep
より単純なマッチングとリバースマッチングを使用して結果を継続的にフィルタリングするために、いくつかのインスタンスをスタックします。-v
実際にディレクトリ名を見つけるには、部分文字列にもう少し注意が必要ですが、一般的に理解しやすく、必要なすべてのことを行う構文を提供します。
find ./ | grep "/good/" | grep -v "/bad/" | grep '\.txt$'