使用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
命令。 在GNU
find
中,可以使用
-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
的输出是面向行的(