我正在Linux上编写bash脚本,需要遍历给定目录中的所有子目录名。如何遍历这些目录(并跳过常规文件)?
例如: 指定目录为/tmp/ 目录包括:/tmp/A、/tmp/B、/tmp/C
我想找回A B C。
我正在Linux上编写bash脚本,需要遍历给定目录中的所有子目录名。如何遍历这些目录(并跳过常规文件)?
例如: 指定目录为/tmp/ 目录包括:/tmp/A、/tmp/B、/tmp/C
我想找回A B C。
当前回答
TL; diana:
(cd /tmp; for d in */; do echo "${d%/}"; done)
解释。
没有必要使用外部程序。您所需要的是一个外壳填充模式。为了避免之后需要删除/tmp,我在一个子shell中运行它,这可能不适合您的目的。
概括地说,Shell globbing模式:
*匹配任意次数的非空字符串。 ? 精确匹配一个字符。 […匹配括号内的字符。您还可以指定范围([a-z], [A-F0-9]等)或类([:digit:], [:alpha:]等)。 [^……匹配一个不是在大括号之间的字符。
*如果没有文件名与模式匹配,shell将原封不动地返回模式。任何不是上述之一的字符或字符串都表示其本身。
因此,模式*/将匹配任何以/结尾的文件名。文件名后面的/可以清楚地标识一个目录。
最后一点是删除后面的斜杠,这是通过变量替换${var%PATTERN}实现的,它从var中包含的字符串末尾删除最短的匹配模式,其中PATTERN是任何有效的通配符模式。因此我们写入${d%/},这意味着我们想要从d表示的字符串中删除后面的斜杠。
其他回答
找到。-type d -maxdepth
我最常用的技术是找到|个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 | \
xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord
它的作用是for dir $(subdirs);做的东西;完成,但是对于名称中有空格的目录是安全的。另外,对stuff的单独调用是在同一个shell中进行的,这就是为什么在我的命令中,我们必须使用popd返回到当前目录。
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'
简单解释一下:
find finds files (quite obviously) . is the current directory, which after the cd is /tmp (IMHO this is more flexible than having /tmp directly in the find command. You have only one place, the cd, to change, if you want more actions to take place in this folder) -maxdepth 1 and -mindepth 1 make sure that find only looks in the current directory and doesn't include . itself in the result -type d looks only for directories -printf '%f\n prints only the found folder's name (plus a newline) for each hit.
就是这样!
你可以循环遍历所有目录,包括隐藏目录(以点开始):
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
如果你想在一个for循环中执行多个命令,你可以用mapfile (bash >= 4)将find的结果保存为一个变量,然后用${dirlist[@]}遍历数组。它还适用于包含空格的目录。
find命令基于Boldewyn的回答。关于find命令的更多信息可以在这里找到。
IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n' )
for dir in ${dirlist[@]}; do
echo ">${dir}<"
# more commands can go here ...
done