ここでは、幅優先のリストが重要です。また、検索される深さを制限することは素晴らしいことです。
$ 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; )
find
コマンドは、多くのプレースホルダーを認識する-printf
オプションをサポートします。
そのようなプレースホルダーの1つは%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
あれは、
検出される深さを制限するには、findコマンドに-maxdepth引数を追加します。
出力を見つけるのと同じ順序でディレクトリをリストする場合は、「sort -n」ではなく「sort -n -s」を使用します。 「-s」フラグはソートを安定させます(つまり、同等に比較するアイテム間の入力順序を保持します)。
私の考えでは、これは前述のソリューションよりも優れたソリューションです。これにはgrepなどとループが関係しますが、特に、完全な検索バッファリングではなく、行バッファリングが必要な場合に非常にうまく機能します。
次の理由により、より多くのリソースを消費します。
これは、次の理由により優れています。
#!/ 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
しかし、私は入力よりも小さなスクリプトを好む...
Findコマンドを使用して、find/path/to/dir -type dを使用できます。現在のディレクトリ内のディレクトリの例を以下に示します。
find . -type d
ディレクトリ階層を走査するとき、ほとんど常にトップダウンまたはボトムアップの深さ優先検索が必要なので、組み込みユーティリティを使用してそれを行うことができるとは思いません。 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))
編集:
os.path
- functionおよびstat
- moduleの代わりにos.stat
- moduleを使用します。del
およびlist.pop
演算子の代わりにlist.extend
および+=
を使用します。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
値する順序なし: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"
その後、パラメーターのベースディレクトリと深さでこのスクリプトを呼び出すことができます。
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'