如何递归列出某个位置的所有目录,广度优先?
Posted
技术标签:
【中文标题】如何递归列出某个位置的所有目录,广度优先?【英文标题】:How do I recursively list all directories at a location, breadth-first? 【发布时间】:2010-10-07 01:51:21 【问题描述】:在这里,广度优先列表很重要。此外,限制搜索的深度会很好。
$ 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; )
【问题讨论】:
您能否对此进行扩展以包括您选择的语言和操作系统(Linux?) Arg!这是一个“社区维基”问题。烦人。 是什么让这成为社区 wiki 问题? 提问者检查了“社区维基”框。我认为这是一个案例:***.uservoice.com/pages/general/suggestions/… 这可能是一个有趣的采访/电话屏幕问题。 【参考方案1】:没有应得的排序: 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"
然后您可以使用参数基目录和深度调用此脚本。
【讨论】:
这正是我想要的,但顺序错误。我更改了问题以澄清,谢谢! 看我的补充!我还没说完:)【参考方案2】:我认为使用内置实用程序无法做到这一点,因为在遍历目录层次结构时,您几乎总是需要深度优先搜索,无论是自上而下还是自下而上。这是一个 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
-module 代替os.stat
-function 和stat
-module。
使用list.pop
和list.extend
代替del
和+=
运算符。
【讨论】:
【参考方案3】:我试图找到一种方法来使用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
我偶然发现了这个,所以我不知道它是否一般有效(我只是在你询问的特定目录结构上测试它)
如果你想限制深度,在外循环中放一个计数器变量,像这样(我也在这个中添加 cmets):
# 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
【讨论】:
再看一遍,这绝对是我“在 Bash 中永远不应该做的事情”的清单;-) 你也可以不把它格式化成一个单行,以便更容易理解代码吗? (但是是的,不要在 bash 中这样做 :-) 也打印基本目录中的常规文件。 ls 的 -1 选项是不必要的——如果 stdout 不是终端(即如果它是管道),则 ls 会自动打印在一列中。 k,修复了常规文件问题【参考方案4】:如果您想使用标准工具执行此操作,则应该使用以下管道:
find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2
也就是说,
-
一阶深度查找并打印此处的所有目录
计算每个目录中的斜杠数量并将其添加到路径中
按深度排序(即斜线数)
只提取路径。
要限制找到的深度,请将 -maxdepth 参数添加到 find 命令中。
如果您希望以查找输出它们的相同顺序列出的目录,请使用“sort -n -s”而不是“sort -n”; “-s”标志稳定了排序(即,保留相同比较的项目之间的输入顺序)。
【讨论】:
在 find 命令中添加“2>/dev/null”,即 find 。 -type d 2>/dev/null 将确保 find 错误不会搞砸结果。 按字母排序怎么样? 如果目录名有空格则不起作用。例如,如果目录是“/data/Mundial/Trinidad\ y\ Tobago/”,您将只有“/data/arbol/Mundial/Trinidad”。 谢谢,这是我发现的用于对路径进行广度优先排序的最佳方法(忽略路径名中的空格等问题)。如果您需要深度优先排序,请参阅此说明,了解在每个路径元素上使用 strcmp() 进行排序回调,如果组件全部匹配,则返回 length1 - length2(相当于将不存在的组件视为空字符串)***.com/a/4820233/539149【参考方案5】:这是一种可能的方法,使用 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
【讨论】:
【参考方案6】:类似这样的:
find . -type d |
perl -lne'push @_, $_;
print join $/,
sort
length $a <=> length $b ||
$a cmp $b
@_ if eof'
【讨论】:
【参考方案7】:我的感觉是,这是一个比前面提到的更好的解决方案。它涉及 grep 等以及一个循环,但我发现它工作得很好,特别是对于您希望行缓冲而不是完整的 find 缓冲的情况。
它更耗费资源,因为:
很多分叉 很多发现 当前深度之前的每个目录被 find 命中的次数与文件结构的总深度一样多(如果您几乎有任何数量的 ram,这应该不是问题...)这很好,因为:
它使用 bash 和基本的 gnu 工具 它可以随时被打破(就像你看到你正在寻找的东西飞过一样) 它按行而不是按查找工作,因此后续命令不必等待查找和排序 它是根据实际的文件系统分离工作的,所以如果你有一个带有斜杠的目录,它不会被列出比它更深的地方;如果您配置了不同的路径分隔符,您仍然可以。#!/bin/bash 深度=0 同时找到-mindepth $depth -maxdepth $depth | grep '.' 做 深度=$((深度+1)) 完成
你也可以很容易地将它放在一行上(?):
depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done
但我更喜欢小脚本而不是打字...
【讨论】:
【参考方案8】:find
命令支持-printf
选项,该选项可识别大量占位符。
一个这样的占位符是%d
,它呈现给定路径的深度,相对于find
开始的位置。
因此,您可以使用以下简单的单线:
find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-
它非常简单,不依赖于像 perl
这样的繁重工具。
它是如何工作的:
它在内部生成文件列表,每个文件都呈现为两个字段的行 第一个字段包含深度,用于(反向)数字排序,然后切掉 结果是简单的文件列表,每行一个文件,最深的优先顺序【讨论】:
【参考方案9】:你可以使用 find 命令, 查找 /path/to/dir -type d 所以下面是当前目录中目录的示例列表:
find . -type d
【讨论】:
这不是广度优先,正如问题中的字面意思。以上是关于如何递归列出某个位置的所有目录,广度优先?的主要内容,如果未能解决你的问题,请参考以下文章