如何仅循环遍历 bash 中的目录?

rub*_*o77 389 bash directory files

我有一个文件夹,里面有一些目录和一些文件(有些是隐藏的,以点开头)。

for d in *; do
 echo $d
done
Run Code Online (Sandbox Code Playgroud)

将遍历所有文件和目录,但我只想遍历目录。我怎么做?

cho*_*oba 518

您可以在末尾指定斜杠以仅匹配目录:

for d in */ ; do
    echo "$d"
done
Run Code Online (Sandbox Code Playgroud)

  • 请注意,它还包含指向目录的符号链接。 (10认同)
  • @choroba:`[[ -L "$f" ]]` 在这种情况下不会用 `*/` 排除符号链接,你必须用 `[[ -L "${f%/}" ] 去掉尾部斜杠]`(请参阅[使用尾随斜杠测试链接](http://unix.stackexchange.com/questions/96913/test-for-link-with-trailing-slash)) (8认同)
  • @rubo77:您可以使用 `[[ -L $d ]]` 测试 $d 是否为符号链接。 (5认同)
  • 那么你将如何排除符号链接呢? (3认同)
  • 添加 `shopt -s nullglob` 以防止当前文件夹中没有目录时出现问题 (3认同)
  • 您也可以使用“for d in */ .*/ : do ...”循环遍历隐藏文件。但是如何循环遍历除“../”之外的隐藏文件? (2认同)
  • @timbram:`*` 是一个通配符,它​​代表“任何东西”。`/` 表示“任何东西”必须是目录才能匹配通配符表达式。`;` 是 for 循环的一部分,它将 `do` 与 `for` 分开。 (2认同)

gol*_*cks 109

你可以测试-d

for f in *; do
    if [ -d "$f" ]; then
        # $f is a directory
    fi
done
Run Code Online (Sandbox Code Playgroud)

这是文件测试操作符之一

  • `if [[ -d "$f" && ! -L "$f" ]]` 将排除符号链接 (29认同)
  • 请注意,它将包含指向目录的符号链接。 (10认同)

小智 58

请注意,choroba 的解决方案虽然优雅,但如果当前目录中没有可用目录,则可能会引发意外行为。在这种状态下,forbash 将只运行一次循环,而不是跳过循环,其中d等于*/

#!/usr/bin/env bash

for d in */; do
    # Will print */ if no directories are available
    echo "$d"
done
Run Code Online (Sandbox Code Playgroud)

我建议使用以下方法来防止这种情况:

#!/usr/bin/env bash

for f in *; do
    if [ -d "$f" ]; then
        # Will not run if no directories are available
        echo "$f"
    fi
done
Run Code Online (Sandbox Code Playgroud)

此代码将遍历当前目录中的所有文件,检查是否f为目录,f如果条件返回 true ,则回显。如果f等于*/echo "$f"则不会执行。

  • 更容易`shopt -s nullglob`。 (8认同)

rub*_*o77 29

如果您需要选择比仅使用目录更具体的文件find并将其传递给while read

shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do 
    echo "$d"
done
Run Code Online (Sandbox Code Playgroud)

使用shopt -u dotglob排除隐藏的目录(或setopt dotglob/unsetopt dotglob中的zsh)。

IFS=避免拆分包含其中之一的文件名$IFS,例如:'a b'

有关更多选项,请参阅下面的AsymLabs 答案find


编辑:
如果您需要在 while 循环中创建退出值,您可以通过以下技巧绕过额外的子外壳:

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)
Run Code Online (Sandbox Code Playgroud)

  • 我在以下位置找到了这个解决方案:http://stackoverflow.com/a/8489394/1069083 (3认同)

rus*_*ush 15

您可以为此使用纯 bash,但最好使用 find:

find . -maxdepth 1 -type d -exec echo {} \;
Run Code Online (Sandbox Code Playgroud)

(另外查找将包括隐藏目录)

  • 请注意,它不包含指向目录的符号链接。你可以使用 `shopt -s dotglob` 为 `bash` 包含隐藏目录。你的也将包括`.`。另请注意,`-maxdepth` 不是标准选项(`-prune` 是)。 (9认同)
  • `dotglob` 选项很有趣,但 `dotglob` 仅适用于使用 `*`。`find .` 将始终包含隐藏目录(以及当前目录) (3认同)

Asy*_*abs 9

这样做是为了在当前工作目录中查找可见和隐藏目录,不包括根目录:

只循环遍历目录:

 find -path './*' -prune -type d
Run Code Online (Sandbox Code Playgroud)

在结果中包含符号链接:

find -L -path './*' -prune -type d
Run Code Online (Sandbox Code Playgroud)

对每个目录做一些事情(不包括符号链接):

find -path './*' -prune -type d -print0 | xargs -0 <cmds>
Run Code Online (Sandbox Code Playgroud)

排除隐藏目录:

find -path './[^.]*' -prune -type d
Run Code Online (Sandbox Code Playgroud)

对返回值执行多个命令(一个非常人为的例子):

find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"
Run Code Online (Sandbox Code Playgroud)

代替 'sh -c' 也可以使用 'bash -c' 等。

  • 我在底部的答案中添加了一个示例,即如何使用带有 `find * | 的函数对每个目录执行某些操作。读取文件时;做...` (2认同)