Find

Linux find <DOCKER_MOUNTED_DIR> -type d:如何列出最深的目錄,例如./dir1/dir2沒有./dir1?

  • October 27, 2021
find . -type d

通常會顯示

./dir1
./dir1/dir2
./dir3
./dir3/dir4
./dir3/dir4/dir5
...

我只想要

./dir1/dir2
./dir3/dir4/dir5

, 沒有它的父 ./dir1, …

換句話說,我只想查看其中沒有任何子目錄的目錄。

任何想法?

編輯:我發現-links 2在正常的 linux 環境中確實可以工作,例如,

docker run -it --rm ubuntu:bionic find /etc -type d -links 2

完美執行。

但是,當我將一個目錄(從 MacOS 或 Windows)掛載到 docker 容器中時,事情發生了變化,它不起作用,你可以試試這個:

docker run -it --rm -v /etc:/etc_of_host ubuntu:bionic find /etc_of_host -type d -links 2

zsh

has_subdirs() () (( $# )) ${1-$REPLY}/*(ND/Y1)
print -rC1 -- **/*(ND/^+has_subdirs)

或者直接不帶中介功能:

print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])

那是:

  • fn() some-command定義一個fn函式,some-command就像在 Bourne-shell 和大多數 Bourne-like shell 中一樣。
  • () { code } args作為位置參數執行的匿名函式codeargs
  • (( $# ))此處,該匿名函式的主體是一個算術表達式,如果(參數的數量)非零,則該表達式解析為真。$#
  • ${param-default}(來自 Bourne shell)擴展為$param是否設置了參數default。在這裡${1-$REPLY},我們允許我們的函式被直接呼叫(as has_subdirs mydir)或作為一個萬用字元函式,如下所示。
  • $dir/*(ND/Y1)擴展為$dir( /) 中目錄類型的文件,包括隱藏文件 ( Dotglob),如果沒有匹配項 (ullglob),則不會出錯N。但是Y1,我們在第一場比賽中停止。has_subdirs因此,如果目錄包含至少一個子目錄,匿名函式(因此)將返回 true。
  • print -rC1在olumn上列印其參數raw1 C
  • ^+has_subdirs僅限於has_subdirs函式不 ( ^) 返回 true 的文件。

如果您必須使用bash外殼,只需執行以下操作:

zsh &lt;&lt; 'EOF'
 print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF

或者將結果儲存在 bash 數組中(需要 bash-4.4+):

readarray -td '' array &lt; &lt;(zsh &lt;&lt; 'EOF'
 print -rNC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
)

(使用 NUL 分隔的記錄以便能夠儲存任意路徑)。

如果你沒有zsh,但你有perl,你可以這樣做:

find . -depth -type d -print0 |
 perl -l -0ne 'print if rindex $prev, "$_/", 0; $prev = $_'

或者如果你有 GNU awk

find . -depth -type d -print0 |
 gawk -v 'RS=\0' 'index(prev, $0"/") != 1; {prev = $0}'

那些首先find列印目錄深度(在他們所在的分支之前離開)並獲取perl/awk以列印未找到的記錄,然後/在上一條記錄的開頭列印。

同樣,要將文件儲存在 bash 4.4+ 數組中,您需要通過將-lafter -0inperl或 add -v 'ORS=\0'in切換到輸出上的 NUL 分隔記錄gawk

readarray -td array &lt; &lt;(
 find . -depth -type d -print0 |
   perl -0lne 'print if rindex $prev, "$_/", 0; $prev = $_'
)
readarray -td array &lt; &lt;(
 find . -depth -type d -print0 |
   gawk -v 'RS=\0' -v 'ORS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
)

在某些系統和文件系統(例如ext4基於 Linux 的系統上的文件系統)上,您可能能夠依賴於這樣一個事實,即具有子目錄的目錄的連結計數大於 2(dir以及dir/.每個附加連結dir/subdir/..)。

print -rC1 -- **/*(ND/l-3)

find在任何外殼中使用:

find . -type d -links -3

這將不起作用btrfs(在幾個 Linux 發行版中已被替換ext4為預設文件系統),例如目錄的連結計數始終為 1,因此我不建議將其作為一般解決方案。

與您的情況相同的聯合文件系統,例如overlayfs我發現一些合併目錄的連結計數為 1,無論它們是否包含子目錄。

但是,無論它在哪裡可用,if 都比手動計算不需要對目錄的讀取訪問權限的子目錄的解決方案具有優勢(僅搜尋對其父目錄的訪問權限)。

你要找的是:

find . -type d -links 2

文件系統中的每個目錄至少有兩個硬連結——父目錄中的目錄本身和“.”。入口。子目錄中的每個“..”條目都會為目錄添加一個新的硬連結。所以你只需要找到有兩個硬連結的目錄。

另一個答案中建議的命令

find . -type d -links -3

做同樣的事情,但聲明“目錄少於三個硬連結”。

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