使用Bash在每个子目录中执行操作
我正在编写一个脚本,该脚本需要在特定文件夹的每个子目录中执行操作使用Bash在每个子目录中执行操作,bash,command,directory-traversal,Bash,Command,Directory Traversal,我正在编写一个脚本,该脚本需要在特定文件夹的每个子目录中执行操作 最有效的编写方法是什么?查找-键入d-print0 | xargs-0-n 1 my_命令避免创建子进程的版本: for D in `find . -type d` do //Do whatever you need with D done for D in *; do if [ -d "${D}" ]; then echo "${D}" # your processing here
最有效的编写方法是什么?查找-键入d-print0 | xargs-0-n 1 my_命令避免创建子进程的版本:
for D in `find . -type d`
do
//Do whatever you need with D
done
for D in *; do
if [ -d "${D}" ]; then
echo "${D}" # your processing here
fi
done
或者,如果您的操作是单个命令,则更简洁:
for D in *; do [ -d "${D}" ] && my_command; done
或者更简洁的版本()。请注意,在此版本中,D
的每个值都有一个尾随斜杠:
for D in */; do my_command; done
如果目录名中有空格,则可接受的答案将以空格分隔,对于bash/ksh,首选语法是
$()
。与+一起使用GNU find
-exec
选项代码>例如
查找-exec mycommand+代码>#这与传递给xargs相同
或者使用while循环
find .... | while read -r D
do
# use variable `D` or whatever variable name you defined instead here
done
这将创建一个子shell(这意味着当循环退出时变量值将丢失):
这不会:
while read -r dir
do
something
done < <(find . -type d)
读取时-r dir
做
某物
完成<方便的一行程序
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
命令。
在GNUfind
中,可以使用-execdir
参数:
find . -type d -execdir realpath "{}" ';'
find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;
或者使用-exec
参数:
find . -type d -execdir realpath "{}" ';'
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循环:
对于递归性,请尝试使用扩展全局搜索(***/
)代替(通过以下方式启用:shopt-s extglob
)
有关更多示例,请参见:在SO上,您可以尝试:
#!/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
#/bin/bash
###$1==此脚本的第一个参数
###用法:script.sh/path/to/dir/
对于f in`find-maxdepth 1-mindepth 1-类型d`;做
cd“$f”
完成
或类似的
说明:
find-maxdepth 1-mindepth 1-类型d
:
仅查找最大递归深度为1(仅子目录为$1)且最小深度为1(不包括当前文件夹
)的目录。最简单的非递归方法是:
for d in */; do
echo "$d"
done
结尾的/
告诉我们,只使用目录
不需要
- 发现
- awk
我可以将该查找的返回值输入for循环吗?这是更大脚本的一部分…@Mike,不太可能。$?可能会得到find或xargs命令的状态,而不是my_命令
。这将在空白处中断。因此,请注意,如果需要递归或非递归行为,则需要调整find
参数。上面的答案还提供了自我目录,所以下面的方法对我来说更有效:find-mindepth 1-键入d
@JoshC,这两个变体都会将由mkdir'directory name with spaces'
创建的目录分解为四个单独的单词。我需要添加-mindepth 1-maxdepth 1
或它太深。如果或[
with:for D in*/;do
+1,因为目录名不是以开头的。/与公认的答案相反,即使在目录名+1中的空格内,此选项也是正确的。最后一个命令有一个问题:如果您位于没有子目录的目录中,它将返回“*/”因此,最好使用第二个命令表示D in*;do[-D“${D}]”和&my_命令;done
或两个最新命令的组合:表示D in*/;do[-D$D]&&my_command;done
注意,此答案忽略隐藏目录。要包含隐藏目录,请对D in.*;do
使用代替D in.*;do
。要更好地处理奇怪的文件名(包括以空格结尾的名称和/或包含换行符),请使用查找…-print0
和,而IFS=“”read-r-d$'\000'dir
@GordonDavisson,…事实上,我甚至认为-d'
对bash语法和功能的误导性较小,因为-d$'\000'
暗示(错误地)$'\000'
在某种程度上不同于'
——事实上,人们可以很容易地(再次错误地)理解它由此推断bash支持Pascal样式的字符串(指定长度,能够包含NUL文本),而不是C字符串(NUL分隔,不能包含NUL)。哪个参数将保存目录名?例如,chmod+x$DIR_name(是的,我知道只有目录才有chmod选项)find-exec
和传递到xargs
之间有一个细微的区别:find
将忽略正在执行的命令的退出值,而xargs
将在非零退出时失败。根据您的需要,两者都可能是正确的。find…-print0;而IFS=read-rd
更安全——支持s以空格开头或结尾的名称,以及包含换行文字的名称。注意:这不包括dot dirs(这可能是一件好事,但知道它很重要)。需要注意的是,在扩展通配符时,您可以使用shopt-s dotglob
来包含点文件/dotdir。另请参见:我认为您的意思是/*
而不是*/
,其中/
表示您要使用的路径。@Shule/*
将表示绝对路径,而*/
将包含子目录来自当前位置的ies帮助提示:如果需要从$d中修剪尾部“/”,请使用${d%/*}
这是错误的--请尝试使用带空格的目录名。请参阅,和。带空格的目录名用引号括起来,因此可以工作,而OP不会尝试从文件中读取行。它在cd“$f”中工作
。当find
的输出是字符串拆分时,它不起作用,因此您将在$f
中将名称的各个部分作为单独的值,这使得您引用$f
的扩展没有意义。我没有说他们试图从文件中读取行。find
的输出是面向行的(