如何只列出沒有其他子目錄的目錄?
/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]
/
N
D
: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 個鏈接。