在 bash 中循环遍历目录和子目录

在 bash 中循环遍历目录和子目录

我尝试使用此行,从包含我想要循环的文件夹的父文件夹开始:

for dir in */; do  
    cd $dir  
    for dir2 in */; do  
        cd $dir2  
        ls -d $PWD/*  
        cd ..  
    done  
    cd ..  
done

但它只是输出我整个计算机的全部内容并返回到根文件夹/~...对这种行为有什么解释吗?

答案1

bash的默认“通配符匹配”(通配符匹配/扩展)行为是,如果通配符不匹配任何内容,则返回通配符表达式本身。因此,如果您cd进入一个没有子目录的目录,您最终会尝试cd进入字面上的“*/”(字面上是名称为星号的目录),并且会失败,因此您将停留在比您认为此时循环中高一个目录的位置。因此,当您然后 时cd ..,您将再次高出一个目录。最终,您将返回到文件系统的根级别。

find(1)许多 shell 脚本编写者在希望脚本遍历目录树时选择使用而不是 shell 循环。您的整个脚本片段将变成:

find . -type d

...或者,如果你确实想要绝对路径而不是相对路径:

find "$PWD" -type d

如果您想坚持使用 shell 循环,您可以尝试如下操作:

#!/bin/bash
set -evx
for dir in */; do
    if [ -d "$dir" ]; then
        cd "$dir"
        for dir2 in */; do
            if [ -d "$dir2" ]; then
                cd "$dir2"
                ls -d "$PWD"/*
                cd ..
            fi
        done
        cd ..
    fi
done

请注意我如何使用if语句来测试每个值dirdir2确保它们确实是目录,如果不是,我会跳过它们。

还要注意这一set -evx行,这是第一次编写/调试脚本时要设置的一组很好的选项:
-e在出现第一个错误时停止。
-v在执行每一行之前打印它。
-x打印每一行在执行之前,各种替换/扩展都已完成。

另外,如果您不喜欢在无法匹配任何内容时返回通配符表达式本身的默认通配符行为,那么可以考虑花一些时间在bash(1)手册页中查看诸如nullglob和之类的 shell 选项。failglob

答案2

您可以简单地使用多个星号:

for dir in */*; do 
    ls -d $PWD/* &
done

使用来&并行运行代码。

答案3

ls这可以纯粹通过使用 Bash 的选项来完成globstar,该选项可以在整个系统范围内启用.bashrc,也可以仅为当前终端会话启用:

shopt -s globstar # enable the globstar option
ls -d $PWD/** # recursively search through $PWD and subdirectories

这仅为当前终端会话设置 Bashglobstar选项,然后递归遍历 $PWD 及其所有子目录。

相关内容