使用「尋找」僅列出沒有更多子目錄的目錄

使用「尋找」僅列出沒有更多子目錄的目錄

如何只列出沒有其他子目錄的目錄?

/A /A/AA /A/AB /A/AB/ABB /B /C /C/CC /C/CC/CCC /C/CC/CCC/CCCC想像一下我只想用來find列出的結構/A/AA /A/AB/ABB /B /C/CC/CCC/CCCC

起點是find . -type d,但既不能使用-mindepth,也-maxdepth不能使用,可以-noleaf提供幫助(我無法讓它按照我想要的方式做出反應)?

答案1

這是一個符合 POSIX 標準的解決方案,可對輸出進行後處理find以刪除具有列出的子目錄的目錄。它假定目錄名稱中沒有換行符號。

{ find . -type d; echo; } |
awk 'index($0,prev"/")!=1 && NR!=1 {print prev}
     1 {sub(/\/$/,""); prev=$0}'

說明:awk 腳本延遲列印每一行,直到讀取下一行,並且僅在不是前綴時才列印上一行。這利用了find子目錄緊接著其父目錄之後列出的事實。額外的"/"目的是避免在存在foo時錯誤地刪除。foobar不優雅的做法NR!=1是避免列印初始空行,並且不優雅的做法echo;是不為最後一行提供同樣不優雅的特殊情況。呼叫會sub從頂級目錄中刪除尾部斜杠,以防find ./調用eg。


像往常一樣,有一個神秘的 zsh 一行。

echo **/.(e\''test -z $REPLY/*(/DN[1])'\':h)

更長、更易讀的版本:

is_leaf () { [ -z $REPLY/*(/DN[1]) ] }
echo **/.(+is_leaf:h)

如果echo **/(+is_leaf)您不介意尾隨/.

總結說明:括號裡的內容是全域限定符,記錄在zshexpn手冊頁中。我們過濾 glob 的結果**/(擴展到目前目錄及其所有子目錄),僅保留函數is_leaf(或 之間的程式碼)'…'傳回 0 的結果。使其在第一個子目錄之後停止)並返回一個狀態,指示是否至少找到一個子目錄。 glob 限定符限制目錄的擴充;如果沒有符合則表示擴展為空;導致包含點文件;是一個歷史修飾符,會導致後綴被刪除(通常意味著)。$REPLY[1]/ND:h/.dirname

只是為了說明 zsh 的 glob 限定符的可能性,這裡有兩個其他變體(更長,我認為更晦澀)以及相應的is_leaf函數:

echo **/.(e\''tmp=($REPLY/*(/DN[1])); ((!#tmp))'\':h)
echo **/.(e\''$REPLY/*(/DN[1]e:REPLY=false:)'\':h)
is_leaf () { set -- $REPLY/*(/DN[1]); ((!#)); }
is_leaf () { return $REPLY/*(/DN[1]e:REPLY=1:) }

答案2

這就是我使用的:

leaf () { find "${1:-.}" -depth -type d | sed  'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'; }

使用起始目錄來呼叫它:

leaf /start/dir

答案3

若要尋找沒有子目錄的目錄:

find dir -type d -links 2

解釋:目錄中的每個子目錄都有一個鏈接,一個來自其父目錄的鏈接和一個指向自身的鏈接,因此如果它沒有子目錄,則計數為 2 個鏈接。

相關內容