我尝试使用此行,从包含我想要循环的文件夹的父文件夹开始:
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
语句来测试每个值dir
以dir2
确保它们确实是目录,如果不是,我会跳过它们。
还要注意这一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 及其所有子目录。