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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:59:31  来源:igfitidea点击:

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

linuxbashshellksh

提问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 findcommand supports -printfoption which recognizes a lot of placeholders.

find命令支持-printf识别大量占位符的选项。

One such placeholder is %dwhich renders the depth of given path, relative to where findstarted.

一个这样的占位符是%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:

编辑:

  1. Using os.path-module instead of os.stat-function and stat-module.
  2. Using list.popand list.extendinstead of deland +=operators.
  1. 使用os.path-module 而不是os.stat-function 和stat-module。
  2. 使用list.popandlist.extend代替deland+=运算符。

回答by David Z

I tried to find a way to do this with findbut it doesn't appear to have anything like a -breadthoption. 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 2with the depth)

(用-lt 2深度替换 2 in )

Basically this implements the standard breadth-first search algorithm using $LISTand $NLISTas 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,

那是,

  1. find and print all the directories here in depth first order
  2. count the number of slashes in each directory and prepend it to the path
  3. sort by depth (i.e., number of slashes)
  4. extract just the path.
  1. 查找并打印所有目录
  2. 计算每个目录中的斜杠数并将其添加到路径中
  3. 按深度排序(即斜线数)
  4. 只提取路径。

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