如何在 Linux 中循环目录?
- 2024-10-17 08:46:00
- admin 原创
- 213
问题描述:
我正在 Linux 上用 bash 编写脚本,需要遍历给定目录中的所有子目录名称。我该如何循环遍历这些目录(并跳过常规文件)?
例如:
给定的目录/tmp/
具有以下子目录:/tmp/A, /tmp/B, /tmp/C
我想要检索 A、B、C。
解决方案 1:
到目前为止,所有答案都使用find
,因此这里只使用 shell。您的情况不需要外部工具:
for dir in /tmp/*/ # list directories in the form "/tmp/dirname/"
do
dir=${dir%*/} # remove the trailing "/"
echo "${dir##*/}" # print everything after the final "/"
done
解决方案 2:
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f
'
简短解释一下:
find
找到文件(很明显).
是当前目录,位于cd
is之后/tmp
(恕我直言,这比/tmp
直接在命令中使用更灵活。如果您想在此文件夹中进行更多操作find
,则只有一个地方需要更改,即)cd
-maxdepth 1
并-mindepth 1
确保find
只在当前目录中查找,并且不会将.
其自身包含在结果中-type d
仅查找目录`-printf '%f
`对于每个匹配仅打印找到的文件夹的名称(加上换行符)。
瞧!
解决方案 3:
您可以使用以下命令循环遍历所有目录,包括隐藏目录(以点开头):
for file in */ .*/ ; do echo "$file is a directory"; done
注意:仅当文件夹中至少有一个隐藏目录时,列表才在 zsh 中有效。在 bash 中,它还会显示*/ .*/
`.`..
bash 包含隐藏目录的另一种可能性是使用:
shopt -s dotglob;
for file in */ ; do echo "$file is a directory"; done
如果您想排除符号链接:
for file in */ ; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
要在每个解决方案中仅输出尾随目录名称(询问的 A、B、C),请在循环内使用它:
file="${file%/}" # strip trailing slash
file="${file##*/}" # strip path and leading slash
echo "$file is the directoryname without slashes"
示例(这也适用于包含空格的目录):
mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done
解决方案 4:
适用于包含空格的目录
灵感来自Sorpigal
while IFS= read -d $' ' -r file ; do
echo $file; ls $file ;
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)
原始帖子(不支持空格)
受到Boldewyn的启发:带有命令的循环示例find
。
for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
echo $D ;
done
解决方案 5:
find . -mindepth 1 -maxdepth 1 -type d -printf "%P
"
解决方案 6:
我最常用的技术是find | xargs
。例如,如果你想让此目录及其所有子目录中的每个文件都可读,你可以执行以下操作:
find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx
该-print0
选项以 NULL 字符而不是空格结尾。该-0
选项以相同的方式拆分其输入。因此,这是在带有空格的文件上使用的组合。
您可以将此命令链想象为获取每一行输出find
并将其粘贴在命令的末尾chmod
。
如果您想在命令中间而不是末尾运行该命令作为其参数,则必须有点创造力。例如,我需要切换到每个子目录并运行命令latemk -c
。所以我使用了(来自维基百科):
find . -type d -depth 1 -print0 | \n xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord
这会产生 的效果for dir $(subdirs); do stuff; done
,但对于名称中带有空格的目录而言是安全的。此外,对 的单独调用stuff
是在同一个 shell 中进行的,这就是为什么在我的命令中我们必须使用 返回到当前目录popd
。
解决方案 7:
总结:
(cd /tmp; for d in */; do echo "${d%/}"; done)
解释。
无需使用外部程序。您需要的是 shell 通配符模式。为了避免/tmp
事后需要删除,我在子 shell 中运行它,这可能适合您的目的,也可能不适合您。
简而言之,Shell 通配符模式:
*
匹配任何非空字符串任意次。?
匹配一个字符。[...]
与括号之间的字符匹配。您还可以指定范围([a-z]
、[A-F0-9]
等)或类别([:digit:]
、[:alpha:]
等)。[^...]
匹配括号之间以外的一个字符。
* 如果没有文件名与模式匹配,shell 将返回未改变的模式。任何不属于上述字符或字符串都代表其自身。
因此,该模式*/
将匹配以 结尾的任何文件名/
。/
文件名尾部的 明确标识了一个目录。
最后一点是删除尾部斜杠,这可以通过变量替换来实现${var%PATTERN}
,它从 中包含的字符串末尾删除最短的匹配模式var
,其中PATTERN
是任何有效的通配符模式。所以我们写${d%/}
,这意味着我们要从 表示的字符串中删除尾部斜杠d
。
解决方案 8:
如果要在 for 循环中执行多个命令,可以将find
with mapfile
(bash >= 4) 的结果保存为变量,然后使用 遍历数组${dirlist[@]}
。它也适用于包含空格的目录。
该find
命令基于Boldewyn 的回答。有关该find
命令的更多信息可在此处找到。
IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f
' )
for dir in ${dirlist[@]}; do
echo ">${dir}<"
# more commands can go here ...
done
解决方案 9:
你可以构建一个最小的 bash 循环(基于 ghostdog74 的答案)
for dir in directory/*
do
echo ${dir}
done
按目录压缩一大堆文件
for dir in directory/*
do
zip -r ${dir##*/} ${dir}
done
解决方案 10:
find . -type d -maxdepth 1
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)