Linux 如何以广度优先的方式递归列出某个位置的所有目录?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/539583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I recursively list all directories at a location, breadth-first?
提问by Andrey Fedorov
Breadth-first list is important, here. Also, limiting the depth searched would be nice.
广度优先列表很重要,在这里。此外,限制搜索的深度会很好。
$ 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
I'd like to do this using a bash one-liner, if possible. If there were a javascript-shell, I'd imagine something like
如果可能的话,我想使用 bash one-liner 来做到这一点。如果有一个 javascript-shell,我会想象像
bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
采纳答案by Petr Kozelka
The find
command supports -printf
option which recognizes a lot of placeholders.
该find
命令支持-printf
识别大量占位符的选项。
One such placeholder is %d
which renders the depth of given path, relative to where find
started.
一个这样的占位符是%d
呈现给定路径的深度,相对于find
开始的位置。
Therefore you can use following simple one-liner:
因此,您可以使用以下简单的单行:
find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-
It is quite straightforward, and does not depend on heavy tooling like perl
.
它非常简单,并且不依赖于像perl
.
How it works:
这个怎么运作:
- it internally generates list of files, each rendered as a two-field line
- the first field contains the depth, which is used for (reverse) numerical sorting, and then cut away
- resulting is simple file listing, one file per line, in the deepest-first order
- 它在内部生成文件列表,每个文件都呈现为两个字段的行
- 第一个字段包含深度,用于(反向)数值排序,然后切掉
- 结果是简单的文件列表,每行一个文件,按最深优先顺序
回答by ypnos
Without the deserved ordering: find -maxdepth -type d
没有应有的排序: find -maxdepth -type d
To get the deserved ordering, you have to do the recursion yourself, with this small shellscript:
要获得应得的排序,您必须自己使用这个小 shellscript 进行递归:
#!/bin/bash
r ()
{
let level=+1
if [ $level -gt ]; then return 0; fi
cd ""
for d in *; do
if [ -d "$d" ]; then
echo /$d
fi;
done
for d in *; do
if [ -d "$d" ]; then
(r "$d" "/$d" $level )
fi;
done
}
r "" "" 0 ""
Then you can call this script with parameters base directory and depth.
然后您可以使用参数基本目录和深度调用此脚本。
回答by Adam Rosenfield
I don't think you could do it using built-in utilities, since when traversing a directory hierarchy you almost always want a depth-first search, either top-down or bottom-up. Here's a Python script that will give you a breadth-first search:
我不认为您可以使用内置实用程序来做到这一点,因为在遍历目录层次结构时,您几乎总是希望进行自上而下或自下而上的深度优先搜索。这是一个 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))
Edit:
编辑:
- Using
os.path
-module instead ofos.stat
-function andstat
-module. - Using
list.pop
andlist.extend
instead ofdel
and+=
operators.
- 使用
os.path
-module 而不是os.stat
-function 和stat
-module。 - 使用
list.pop
andlist.extend
代替del
and+=
运算符。
回答by David Z
I tried to find a way to do this with find
but it doesn't appear to have anything like a -breadth
option. Short of writing a patch for it, try the following shell incantation (for bash):
我试图找到一种方法来做到这一点,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
I sort of stumbled upon this accidentally so I don't know if it works in general (I was testing it only on the specific directory structure you were asking about)
我有点偶然发现了这一点,所以我不知道它是否一般有效(我仅在您询问的特定目录结构上对其进行了测试)
If you want to limit the depth, put a counter variable in the outer loop, like so (I'm also adding comments to this one):
如果您想限制深度,请在外循环中放置一个计数器变量,如下所示(我也在为此添加注释):
# 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
(replace the 2 in -lt 2
with the depth)
(用-lt 2
深度替换 2 in )
Basically this implements the standard breadth-first search algorithm using $LIST
and $NLIST
as a queue of directory names. Here's the latter approach as a one-liner for easy copy-and-paste:
基本上,这使用$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
回答by Emil Sit
If you want to do it using standard tools, the following pipeline should work:
如果您想使用标准工具执行此操作,则应使用以下管道:
find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2
That is,
那是,
- find and print all the directories here in depth first order
- count the number of slashes in each directory and prepend it to the path
- sort by depth (i.e., number of slashes)
- extract just the path.
- 查找并打印所有目录
- 计算每个目录中的斜杠数并将其添加到路径中
- 按深度排序(即斜线数)
- 只提取路径。
To limit the depth found, add the -maxdepth argument to the find command.
要限制找到的深度,请将 -maxdepth 参数添加到 find 命令。
If you want the directories listed in the same order that find output them, use "sort -n -s" instead of "sort -n"; the "-s" flag stabilizes the sort (i.e., preserves input order among items that compare equally).
如果您希望以查找输出的相同顺序列出目录,请使用“sort -n -s”而不是“sort -n”;“-s”标志稳定排序(即,在比较相等的项目之间保留输入顺序)。
回答by Rog
Here's a possible way, using find. I've not thoroughly tested it, so user beware...
这是一种可能的方法,使用 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
回答by Dimitre Radoulov
Something like this:
像这样的东西:
find . -type d |
perl -lne'push @_, $_;
print join $/,
sort {
length $a <=> length $b ||
$a cmp $b
} @_ if eof'
回答by ClashTheBunny
My feeling is that this is a better solution than previously mentioned ones. It involves grep and such and a loop, but I find it works very well, specifically for cases where you want things line buffered and not the full find buffered.
我的感觉是,这是一个比前面提到的更好的解决方案。它涉及 grep 之类的循环,但我发现它工作得很好,特别是对于您想要缓冲行而不是缓冲完整查找的情况。
It is more resource intensive because of:
它更占用资源,因为:
- Lots of forking
- Lots of finds
- Each directory before the current depth is hit by find as many times as there is total depth to the file structure (this shouldn't be a problem if you have practically any amount of ram...)
- 很多分叉
- 很多发现
- 查找当前深度之前的每个目录与文件结构的总深度一样多(如果您实际上有任何数量的内存,这应该不是问题......)
This is good because:
这很好,因为:
- It uses bash and basic gnu tools
- It can be broken whenever you want (like you see what you were looking for fly by)
- It works per line and not per find, so subsequent commands don't have to wait for a find and a sort
- It works based on the actual file system separation, so if you have a directory with a slash in it, it won't be listed deeper than it is; if you have a different path separator configured, you still are fine.
- 它使用 bash 和基本的 gnu 工具
- 它可以随时被打破(就像你看到你正在寻找的东西一样)
- 它按行工作,而不是按查找工作,因此后续命令不必等待查找和排序
- 它基于实际的文件系统分离工作,所以如果你有一个带有斜杠的目录,它不会被列出得比它更深;如果您配置了不同的路径分隔符,您仍然可以。
#!/bin/bash depth=0 while find -mindepth $depth -maxdepth $depth | grep '.' do depth=$((depth + 1)) done
You can also fit it onto one line fairly(?) easily:
你也可以很容易地把它放在一行上(?):
depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done
But I prefer small scripts over typing...
但我更喜欢小脚本而不是打字...
回答by dayanand
You can use find command, find /path/to/dir -type d So below example list of directories in current directory :
您可以使用 find 命令, find /path/to/dir -type d 下面是当前目录中的目录示例列表:
find . -type d