簡體   English   中英

如何以廣度優先的方式遞歸列出某個位置的所有目錄?

[英]How do I recursively list all directories at a location, breadth-first?

在這里,廣度優先列表很重要。 另外,限制搜索的深度會很好。

$ find . -type d
/foo
/foo/subfoo
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub
/bar
/bar/subbar

$ find . -type d -depth
/foo/subfoo/subsub/subsubsub
/foo/subfoo/subsub
/foo/subfoo
/foo
/bar/subbar
/bar

$ < what goes here? >
/foo
/bar
/foo/subfoo
/bar/subbar
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub

如果可能的話,我想使用 bash 單行代碼來做到這一點。 如果有一個javascript-shell,我會想象像

bash("find . -type d").sort( function (x) x.findall(/\//g).length; )

find命令支持-printf選項,它可以識別很多占位符。

一個這樣的占位符是%d ,它呈現給定路徑的深度,相對於find開始的位置。

因此,您可以使用以下簡單的一行代碼:

find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-

它非常簡單,不依賴於像perl這樣的重型工具。

怎么運行的:

  • 它在內部生成文件列表,每個文件呈現為兩行
  • 第一個字段包含深度,用於(反向)數值排序,然后切掉
  • 結果是簡單的文件列表,每行一個文件,按最深的優先順序

如果你想使用標准工具來完成它,下面的管道應該可以工作:

find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2

那是,

  1. 查找並打印這里的所有目錄
  2. 計算每個目錄中斜杠的數量並將其添加到路徑中
  3. 按深度排序(即斜杠數)
  4. 只提取路徑。

要限制找到的深度,請將 -maxdepth 參數添加到查找命令。

如果您希望目錄以與 find 輸出它們相同的順序列出,請使用“sort -n -s”而不是“sort -n”; “-s”標志穩定排序(即,保留比較相等的項目之間的輸入順序)。

您可以使用 find 命令,find /path/to/dir -type d 下面是當前目錄中目錄的示例列表:

find . -type d

我的感覺是,這是比前面提到的更好的解決方案。 它涉及 grep 和循環,但我發現它工作得很好,特別是對於你想要緩沖行而不是緩沖完整查找的情況。

它需要更多的資源,因為:

  • 很多分叉
  • 很多發現
  • 當前深度之前的每個目錄被 find 命中的次數與文件結構的總深度一樣多(如果您實際上有任何數量的 ram,這應該不是問題......)

這很好,因為:

  • 它使用 bash 和基本的 gnu 工具
  • 它可以隨時被打破(就像你看到你正在尋找的東西飛過一樣)
  • 它按行工作而不是按查找工作,因此后續命令不必等待查找和排序
  • 它基於實際的文件系統分隔工作,所以如果你有一個目錄中有一個斜線,它不會被列得比它更深; 如果您配置了不同的路徑分隔符,您仍然可以。
#!/bin/bash 
depth=0

while find -mindepth $depth -maxdepth $depth | grep '.'
do
    depth=$((depth + 1))
done

你也可以很容易地將它放在一條線上(?):

depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done

但我更喜歡小腳本而不是打字......

我認為您不能使用內置實用程序來完成此操作,因為在遍歷目錄層次結構時,您幾乎總是希望進行深度優先搜索,無論是自上而下還是自下而上。 這是一個 Python 腳本,可以為您提供廣度優先搜索:

import os, sys

rootdir = sys.argv[1]
queue = [rootdir]

while queue:
    file = queue.pop(0)
    print(file)
    if os.path.isdir(file):
        queue.extend(os.path.join(file,x) for x in os.listdir(file))

編輯:

  1. 使用os.path -module 而不是os.statstat -module。
  2. 使用list.poplist.extend代替del+=運算符。

我試圖找到一種使用find來執行此操作的方法,但它似乎沒有-breadth選項之類的東西。 如果沒有為它編寫補丁,請嘗試以下 shell 咒語(用於 bash):

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
while test -n "$LIST"; do
    for F in $LIST; do
        echo $F;
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    LIST=$NLIST;
    NLIST="";
done

我有點偶然發現了這個,所以我不知道它是否一般有效(我只在你詢問的特定目錄結構上測試它)

如果你想限制深度,在外循環中放置一個計數器變量,就像這樣(我也在為這個添加注釋):

# initialize the list of subdirectories being processed
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
# initialize the depth counter to 0
let i=0;
# as long as there are more subdirectories to process and we haven't hit the max depth
while test "$i" -lt 2 -a -n "$LIST"; do
    # increment the depth counter
    let i++;
    # for each subdirectory in the current list
    for F in $LIST; do
        # print it
        echo $F;
        # double-check that it is indeed a directory, and if so
        # append its contents to the list for the next level
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    # set the current list equal to the next level's list
    LIST=$NLIST;
    # clear the next level's list
    NLIST="";
done

(將-lt 2中的 2 替換為深度)

基本上,這實現了標准的廣度優先搜索算法,使用$LIST$NLIST作為目錄名稱隊列。 這是后一種方法,作為易於復制和粘貼的單行方法:

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; let i=0; while test "$i" -lt 2 -a -n "$LIST"; do let i++; for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done

沒有應有的順序:find -maxdepth -type d

要獲得應有的順序,您必須使用這個小的 shellscript 自己進行遞歸:

#!/bin/bash
r () 
{
    let level=$3+1
    if [ $level -gt $4 ]; then return 0; fi
    cd "$1"
    for d in *; do
        if [ -d "$d" ]; then
            echo $2/$d
        fi;
    done
    for d in *; do
        if [ -d "$d" ]; then
            (r "$d" "$2/$d" $level $4)
        fi;
    done
}
r "$1" "$1" 0 "$2"

然后你可以用參數基目錄和深度調用這個腳本。

這是一種可能的方法,使用 find。 我還沒有徹底測試它,所以用戶要小心......

depth=0
output=$(find . -mindepth $depth -maxdepth $depth -type d | sort); 
until [[ ${#output} -eq 0 ]]; do 
  echo "$output"
  let depth=$depth+1
  output=$(find . -mindepth $depth -maxdepth $depth -type d | sort)
done

像這樣:

find . -type d | 
  perl -lne'push @_, $_;
    print join $/,
      sort { 
        length $a <=> length $b || 
          $a cmp $b 
        } @_ if eof'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM