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

hir*_*hme 4 bash ubuntu

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

for dir in */; do  
    cd $dir  
    for dir2 in */; do  
        cd $dir2  
        ls -d $PWD/*  
        cd ..  
    done  
    cd ..  
done
Run Code Online (Sandbox Code Playgroud)

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

Spi*_*iff 8

bash\ 的默认“通配符”(通配符匹配/扩展)行为是,如果通配符不匹配任何内容,则返回通配符表达式本身。因此,如果您cd进入一个没有子目录的目录,您最终将尝试进入cd字面上的“*/”(字面意思是一个名称为星号的目录),这将失败,所以您将保持一个状态目录比您想象的循环中此时所在的目录要高。因此,当您这样做时cd ..,您将再次上升一个目录。最终您将返回到文件系统的根级别。

\n\n

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

\n\n
find . -type d\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\xa6或者,如果您确实想要绝对路径而不是相对路径:

\n\n
find "$PWD" -type d\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果你想坚持使用 shell 循环,你可以尝试这样的事情:

\n\n
#!/bin/bash\nset -evx\nfor dir in */; do\n    if [ -d "$dir" ]; then\n        cd "$dir"\n        for dir2 in */; do\n            if [ -d "$dir2" ]; then\n                cd "$dir2"\n                ls -d "$PWD"/*\n                cd ..\n            fi\n        done\n        cd ..\n    fi\ndone\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

另请注意这一set -evx行,这是当您第一次编写/调试脚本时要设置的一组很好的选项:
\n -e在第一个错误时停止。
\n -v在执行之前打印每一行。
\n 在执行所有各种替换/扩展 之后-x,在执行之前打印每一行。

\n\n

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

\n