將 POSIX 查找限制在特定深度?
我最近注意到POSIX 規範
find
不包括-maxdepth
主要規範。對於那些不熟悉它的人來說,主要的目的是限制將下降
-maxdepth
多少層。只處理命令行參數;只會在命令行參數等中直接處理結果。find``-maxdepth 0``-maxdepth 1
如何
-maxdepth
僅使用 POSIX 指定的選項和工具獲得與非 POSIX 主節點等效的行為?(注意:當然,我可以
-maxdepth 0
通過將-prune
其用作第一個操作數來獲得等價物,但這不會擴展到其他深度。)
您可以使用
-path
匹配給定的深度並在那裡修剪。例如find . -path '*/*/*' -prune -o -type d -print
將是 maxdepth 1,因為
*
匹配.
、*/*
matches./dir1
和*/*/*
match./dir1/dir2
被修剪。如果您使用絕對起始目錄,您還需要添加一個/
前導-path
。
@meuh 的方法效率低下,因為他的
-maxdepth 1
方法仍然允許find
讀取級別 1 的目錄內容,以便稍後忽略它們。如果某些目錄名稱包含在使用者區域設置中不形成有效字元的字節序列(例如不同字元編碼的文件名),它也無法與某些find
實現(包括 GNU )一起正常工作。find
find . \( -name . -o -prune \) -extra-conditions-and-actions
是實現 GNU 的更規範的方式
-maxdepth 1
。一般來說,它是你想要的深度 1(
-mindepth 1 -maxdepth 1
)因為你不想考慮.
(深度 0),然後它更簡單:find . ! -name . -prune -extra-conditions-and-actions
對於
-maxdepth 2
,則變為:find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
這就是您遇到無效字元問題的地方。
例如,如果您有一個名為的目錄,
Stéphane
但它é
以 iso8859-1(又名 latin1)字元集(0xe9 字節)編碼,這在 2000 年代中期之前在西歐和美國最常見,那麼該 0xe9 字節不是UTF-8 中的有效字元。因此,在 UTF-8 語言環境中,*
萬用字元(在某些實現中find
)不會匹配0 個或更多字元,並且 0xe9 不是字元。Stéphane``*
$ locale charmap UTF-8 $ find . -maxdepth 2 . ./St?phane ./St?phane/Chazelas ./Stéphane ./Stéphane/Chazelas ./John ./John/Smith $ find . \( ! -path './*/*' -o -prune \) . ./St?phane ./St?phane/Chazelas ./St?phane/Chazelas/age ./St?phane/Chazelas/gender ./St?phane/Chazelas/address ./Stéphane ./Stéphane/Chazelas ./John ./John/Smith
我的
find
(當輸出到終端時)顯示無效的 0xe9 字節,?
如上所述。你可以看到那St<0xe9>phane/Chazelas
不是prune
d。您可以通過以下方式解決它:
LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
但請注意,這會影響所有區域設置
find
及其執行的任何應用程序(例如通過-exec
謂詞)。$ LC_ALL=C find . \( ! -path './*/*' -o -prune \) . ./St?phane ./St?phane/Chazelas ./St??phane ./St??phane/Chazelas ./John ./John/Smith
現在,我真的明白了,
-maxdepth 2
但請注意第二個 Stéphane 中正確編碼為 UTF-8 的 é 如何顯示為 é 的 UTF-8 編碼??
的 0xc3 0xa9 字節(在 C 語言環境中被視為兩個單獨的未定義字元) C 語言環境中不可列印的字元。如果我添加了
-name '????????'
,我會得到錯誤的 Stéphane(以 iso8859-1 編碼的那個)。要應用於任意路徑而不是
.
,您可以:find some/dir/. ! -name . -prune ...
對於
-mindepth 1 -maxdepth 1
或:find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...
為
-maxdepth 2
.我仍然會做一個:
(cd -P -- "$dir" && find . ...)
首先,因為這使得路徑更短,這使得它不太可能遇到路徑太長或arg 列表太長的
find
問題,而且還可以解決不能支持任意路徑參數的事實(-f
使用 FreeBSD除外find
),因為它會阻塞$dir
like!
或
-o
與否定相結合是執行兩組獨立/-condition
in-action
的常用技巧find
。如果您想在文件會議上執行並在文件
-action1
會議上-condition1
獨立執行,您不能這樣做:-action2``-condition2
find . -condition1 -action1 -condition2 -action2
As
-action2
只會對同時滿足這兩個條件的文件執行。也不:
find . -contition1 -action1 -o -condition2 -action2
-action2
不會對同時滿足這兩個條件的文件執行。find . \( ! -condition1 -o -action1 \) -condition2 -action2
就像每個文件
\( ! -condition1 -o -action1 \)
都解析為true一樣工作。假設是一個總是返回true-action1
的動作(如-prune
, ) 。對於這樣的操作可能會返回false,您可能需要添加另一個where是無害的但返回true ,就像在 GNU or or or中一樣(儘管請注意上面關於無效字元的問題)。-exec ... {} +``-exec ... \;``-o -something``-something``-true``find``-links +0``! -name ''``-name '*'