web-dev-qa-db-ja.com

特定の場所にあるすべてのディレクトリを幅優先で一覧表示するにはどうすればよいですか?

ここでは、幅優先のリストが重要です。また、検索される深さを制限することは素晴らしいことです。

$ 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 one-linerを使用してこれを行いたいです。 javascript-Shellがある場合、次のようなものを想像します

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

findコマンドは、多くのプレースホルダーを認識する-printfオプションをサポートします。

そのようなプレースホルダーの1つは%dです。これは、findが開始された場所を基準にして、指定されたパスの深さをレンダリングします。

したがって、次のシンプルなワンライナーを使用できます。

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

それは非常に簡単で、Perlのような重いツールに依存しません。

使い方:

  • 内部的にファイルのリストを生成し、それぞれが2フィールドの行としてレンダリングされます
  • 最初のフィールドには深さが含まれます。これは(逆)数値ソートに使用され、その後切り取られます
  • 結果は、単純なファイルリストであり、1行に1ファイル、最深順
28
Petr Kozelka

標準ツールを使用してそれを行う場合、次のパイプラインが機能するはずです。

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

あれは、

  1. ここですべてのディレクトリを見つけて印刷します。
  2. 各ディレクトリのスラッシュの数をカウントし、パスの先頭に追加します
  3. 深さ(つまり、スラッシュの数)でソートする
  4. パスのみを抽出します。

検出される深さを制限するには、findコマンドに-maxdepth引数を追加します。

出力を見つけるのと同じ順序でディレクトリをリストする場合は、「sort -n」ではなく「sort -n -s」を使用します。 「-s」フラグはソートを安定させます(つまり、同等に比較するアイテム間の入力順序を保持します)。

21
Emil Sit

私の考えでは、これは前述のソリューションよりも優れたソリューションです。これにはgrepなどとループが関係しますが、特に、完全な検索バッファリングではなく、行バッファリングが必要な場合に非常にうまく機能します。

次の理由により、より多くのリソースを消費します。

  • たくさんのフォーク
  • たくさんの発見
  • 現在の深さより前の各ディレクトリは、ファイル構造の深さの合計と同じ回数だけ検索されます(実際にRAMがあれば、これは問題になりません...)

これは、次の理由により優れています。

  • Bashと基本的なgnuツールを使用します
  • 必要なときにいつでも壊れる可能性があります(探しているものがフライバイで見えるように)
  • 検索ごとではなく行ごとに機能するため、後続のコマンドは検索と並べ替えを待つ必要がありません
  • 実際のファイルシステムの分離に基づいて機能するため、スラッシュが含まれるディレクトリがある場合、それ以上深く表示されません。別のパス区切り文字を構成している場合でも、問題ありません。
#!/ bin/bash 
 depth = 0 
 
 while find -mindepth $ depth -maxdepth $ depth | grep '。' 
 do 
 depth = $((depth + 1))
 done

また、簡単に公平に(?)1行に収めることができます。

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

しかし、私は入力よりも小さなスクリプトを好む...

5
ClashTheBunny

Findコマンドを使用して、find/path/to/dir -type dを使用できます。現在のディレクトリ内のディレクトリの例を以下に示します。

find . -type d
5
dayanand

ディレクトリ階層を走査するとき、ほとんど常にトップダウンまたはボトムアップの深さ優先検索が必要なので、組み込みユーティリティを使用してそれを行うことができるとは思いません。 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- functionおよびstat- moduleの代わりにos.stat- moduleを使用します。
  2. delおよびlist.pop演算子の代わりにlist.extendおよび+=を使用します。
5
Adam Rosenfield

findでこれを行う方法を見つけようとしましたが、-breadthオプションのようなものはないようです。パッチを作成する前に、次のシェルの呪文(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
3
David Z

値する順序なし:find -maxdepth -type d

値する順序を取得するには、この小さなシェルスクリプトを使用して、自分で再帰を実行する必要があります。

#!/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"

その後、パラメーターのベースディレクトリと深さでこのスクリプトを呼び出すことができます。

2
ypnos

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
1
Rog

このようなもの:

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