Command-Line

查找:使用正則表達式獲取路徑中具有特定目錄名稱但路徑中沒有另一個特定目錄名稱的所有文件

  • October 29, 2021

我正在嘗試使用 find 返回在其路徑中具有特定目錄但在文件路徑中的任何位置都沒有另一個特定目錄的所有文件名。就像是:

myRegex= <regex> 
targetDir= <source directory>
find $targetDir -regex $myRegex -print

我知道我也可以通過將一個 find 命令傳遞到另一個命令來做到這一點,但我想知道如何使用單個正則表達式來做到這一點。

例如,我希望每個文件的路徑中都有目錄“好”,但無論組合如何,在其路徑中的任何地方都沒有目錄“壞”。一些例子:

/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

我的研究表明我應該使用 Negative Lookahead 和 Negative Lookbehind。但是,到目前為止,我嘗試過的任何方法都沒有奏效。一些幫助將不勝感激。謝謝。

正如 Inian 所說,您不需要-regex(這是非標準的,並且支持-regex¹的實現之間的語法差異很大)。

您可以使用-path它,但您也可以告訴find不要輸入名為 的目錄bad,這比發現其中的每個文件以便以後使用 過濾它們更有效-path

LC_ALL=C find . -name bad -prune -o -path '*/good/*.txt' -type f -print

LC_ALL=Csofind*萬用字元不會阻塞字節序列在區域設置中不形成有效字元的文件名)。

或者對於多個文件夾名稱:

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.)

In zsh -o extendedglob,~例外(和非)萬用字元運算符,而^是否定運算符,並且#是 0 或更多的前面的東西,如 regexp *${(~j[|])array}將數組的元素與 連接起來|,將|其視為全域運算符而不是文字|~.

zsh中,您可以在之後使用 PCRE 匹配set -o rematchpcre

set -o rematchpcre
regex='^(?!.*/bad/).*/good/.*\.txt\Z'
print -rC1 -- **/*(ND.e['[[ $REPLY =~ $regex ]]'])

但是,對每個文件(包括bad目錄中的文件)的 shell 程式碼的評估可能會比其他解決方案慢很多。

還要注意 PCRE(與 zsh glob 相反)會阻塞在區域設置中不形成有效字元的字節序列,並且不支持 UTF-8 以外的多字節字元集。將語言環境修復為C喜歡find上述內容將解決此特定模式的問題。

如果您[[ =~ ]]只想像 in 那樣進行擴展的正則表達式匹配bash,您也可以只載入 pcre 模組 ( zmodload zsh/pcre) 並使用[[ -pcre-match ]]而不是[[ =~ ]]進行 PCRE 匹配。

或者您可以使用grep -zP(假設 GNUgrep或兼容)進行過濾:

regex='^(?!.*/bad/).*/good/.*\.txt\Z'
find . -type f -print0 |
 LC_ALL=C grep -zPe "$regex" |
 tr '\0' '\n'

(儘管find仍然發現所有目錄中的所有bad文件)。

如果您需要對這些文件執行任何操作(每行列印一個除外),請替換tr '\0' '\n'為。xargs -r0 cmd


¹在任何情況下,我都不知道任何find支持類似 perl 或類似 vim 的正則表達式的實現,您需要環視運算符。

引用自:https://unix.stackexchange.com/questions/674938