find - 帶析取的萬用字元
我之前編寫了一個腳本,它在目錄樹中搜尋 .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
從中創建所需的表達式。由於您沒有提及您正在使用什麼外殼,我正在為 POSIX
sh
外殼執行此操作: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'