Find

將 POSIX 查找限制在特定深度?

  • August 19, 2021

我最近注意到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不是pruned。

您可以通過以下方式解決它:

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),因為它會阻塞$dirlike!-print…的值


-o與否定相結合是執行兩組獨立/ -conditionin-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 '*'

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