Find

find - 帶析取的萬用字元

  • December 6, 2021

我之前編寫了一個腳本,它在目錄樹中搜尋 .h 和 .c 文件,然後在它們上執行 clang-format:

find $directory -name '*.[hc]' -exec clang-format -i {} \;

這正如預期的那樣工作。現在我想將 .cpp 文件添加到搜尋中。然而,既不

-name '*.{[hc],cpp}'

也不

-name '{*.[hc],*.cpp}'

工作。也就是說,他們找不到文件。

我知道如果我使用find’s-o選項,我可以讓我的邏輯工作。但是,必須有一種方法可以使用單個-name指令來執行此操作。

-name支持與 shell glob 不同的模式,但它不支持大括號(GNU find 手冊頁明確提及),也不支持 ksh 樣式的擴展 glob。

但是很多人都find支持-regex,你也許可以使用它。根據您find支持的正則表達式方言,標準的基本正則表達式支持交替。

使用 GNU find,這應該可以工作:

find . -regextype posix-extended -regex '.*\.(c|h|cpp)'

(另請注意,匹配與整個路徑匹配,而不僅僅是文件名部分,但如果您只匹配文件名的最終後綴,那將不是問題。)

-name謂詞一起使用的模式find是標准文件名通配模式。您嘗試使用的是find不支持的大括號擴展。

請注意,沒有一個.c標準的通配模式可以匹配以,.h或結尾的文件名.cpp

您可能想使用類似'*.'{c,h,cpp}, 擴展為*.c,*.h和 的東西*.cpp,但不包括-name謂詞也不包括-o.

接下來要嘗試的是'-o -name "*.'{c,h,cpp}'"',但這會擴展到三個字元串-o -name "*.c" -o -name "*.h",和 -o -name "*.cpp"。這也不能使用,因為您必須將它們拆分為空格才能find辨識單獨的子字元串(並-o從第一個子字元串中刪除)。雖然它可能會起作用eval,但它似乎比它的價值更麻煩。

取而代之的是,您可以使用兩個 -name帶有 OR 的測試:

find  "$directory" -type f \( -name '*.[ch]' -o -name '*.cpp' \) \
   -exec clang-format -i {} +

這使用了-name前面描述的兩個測試(-o是 OR 運算符),並且還clang-format通過將找到的路徑名批量傳遞給工具而不是為每個文件呼叫一次來盡可能少地呼叫。

通過一點點額外的程式,您可以將所有想要選擇的文件名後綴儲存在一個列表中,並find從中創建所需的表達式。

由於您沒有提及您正在使用什麼外殼,我正在為 POSIXsh外殼執行此操作:

set -- c h cpp

for suffix do
   set -- "$@" -o -name "*.$suffix"
   shift
done

shift # shifts off the initial "-o"

find "$directory" -type f \( "$@" \) -exec clang-format -i {} +

或者

set --
for suffix in c h cpp; do
   set -- "$@" -o -name "*.$suffix"
done

shift

find "$directory" -type f \( "$@" \) -exec clang-format -i {} +

"$@"在這個例子中展開的列表相當於

-name '*.c' -o -name '*.h' -o -name '*.cpp'

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