Answers:
for D in `find . -type d`
do
//Do whatever you need with D
done
find
如果要递归或非递归行为,则需要调整参数。
find . -mindepth 1 -type d
mkdir 'directory name with spaces'
分为四个单独的词。
-mindepth 1 -maxdepth 1
或者它太深了。
避免创建子流程的版本:
for D in *; do
if [ -d "${D}" ]; then
echo "${D}" # your processing here
fi
done
或者,如果您的操作是单个命令,则此方法更为简洁:
for D in *; do [ -d "${D}" ] && my_command; done
或更简洁的版本(感谢@enzotib)。请注意,在此版本中,的每个值都D
将带有斜杠:
for D in */; do my_command; done
if
或[
用:for D in */; do
for D in *; do [ -d "${D}" ] && my_command; done
或两个最新命令的组合:for D in */; do [ -d $D ] && my_command; done
for D in .* *; do
改用for D in *; do
。
最简单的非递归方法是:
for d in */; do
echo "$d"
done
将/
在年底告诉,只使用目录。
不需要
shopt -s dotglob
在扩展通配符时可以用来包含dotfiles / dotdirs。参见:gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
/*
,而不是*/
与/
代表您要使用的路径。
/*
用于绝对路径,*/
但包括当前位置的子目录
${d%/*}
find
命令。在GNU中find
,可以使用-execdir
参数:
find . -type d -execdir realpath "{}" ';'
或使用-exec
参数:
find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;
或使用xargs
命令:
find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'
或使用for循环:
for d in */; { echo "$d"; }
为了获得递归效果,请尝试使用扩展球形(**/
)(启用:)shopt -s extglob
。
有关更多示例,请参见:如何转到每个目录并执行命令?在SO
-exec {} +
是POSIX指定的,-exec sh -c 'owd=$PWD; for arg; do cd -- "$arg" && pwd -P; cd -- "$owd"; done' _ {} +
是另一个合法选项,并且调用的shell少于-exec sh -c '...' {} \;
。
方便的单线
for D in *; do echo "$D"; done
for D in *; do find "$D" -type d; done ### Option A
find * -type d ### Option B
选项A是正确的文件夹之间有空格。而且,通常更快,因为它不会将文件夹名称中的每个单词都打印为单独的实体。
# Option A
$ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
real 0m0.327s
user 0m0.084s
sys 0m0.236s
# Option B
$ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
real 0m0.787s
user 0m0.484s
sys 0m0.308s
find . -type d -print0 | xargs -0 -n 1 my_command
my_command
。
这将创建一个子shell(这意味着当while
循环退出时变量值将丢失):
find . -type d | while read -r dir
do
something
done
这不会:
while read -r dir
do
something
done < <(find . -type d)
如果目录名称中有空格,则任何一种都将起作用。
find ... -print0
和while IFS="" read -r -d $'\000' dir
-d ''
对bash语法和功能的误导性较小,因为-d $'\000'
隐含(错误地)$'\000'
有所不同''
-实际上,一个人可以轻易地(再一次错误地)推断出bash支持Pascal样式的字符串(指定长度,能够包含NUL文字),而不是C字符串(NUL分隔,不能包含NUL)。
您可以尝试:
#!/bin/bash
### $1 == the first args to this script
### usage: script.sh /path/to/dir/
for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
cd "$f"
<your job here>
done
或类似...
说明:
find . -maxdepth 1 -mindepth 1 -type d
:仅查找最大递归深度为1(仅子目录为$ 1)和最小深度为1(不包括当前文件夹.
)的目录
cd "$f"
。当from的输出find
是字符串拆分时,它不起作用,因此您将名称的不同部分作为中的单独值$f
,从而可以更好地理解或不引用$f
的扩展模拟。
find
的输出是面向行的(从理论上讲,它是行的名称,但请参见下文),且具有默认-print
操作。
find -print
,不是传递任意文件名的安全方法,因为一个人可以运行某些文件mkdir -p $'foo\n/etc/passwd\nbar'
并获得/etc/passwd
名称中带有单独一行的目录。毫不费力地处理文件/upload
或/tmp
目录中文件的名称是获得特权升级攻击的好方法。
如果目录名称包含空格,则可接受的答案将在空格上中断,并且首选语法是$()
bash / ksh。使用GNU find
-exec
选项,+;
例如
find .... -exec mycommand +;
#this is same as passing to xargs
或使用while循环
find .... | while read -r D
do
...
done
find -exec
和传递给之间有一个微妙的区别xargs
:find
将忽略正在执行的命令的退出值,而xargs
在非零退出时失败。可能是正确的,具体取决于您的需求。
find ... -print0 | while IFS= read -r d
更安全-支持以空格开头或结尾的名称,以及包含换行文字的名称。
mkdir 'foo * bar'
会造成foo
和bar
即使要遍历它们不存在,并且*
将被所有文件名(甚至非目录文件名)的列表替换)。