如何进入每个目录并执行命令?

我如何写一个bash脚本,遍历parent_directory内的每个目录和执行每个目录中的命令

目录结构如下:

Parent_directory(名称可以是任何东西-不遵循模式)

  • 001(目录名称遵循此模式)
    • 0001.txt(文件名遵循此模式)
    • 0002.三种
    • 0003.三种
  • <李> 002
    • 0001.三种
    • 0002.三种
    • 0003.三种
    • 0004.三种
    <李> 003
    • 0001.三种

目录数量未知。

182023 次浏览

我不明白文件的格式,因为你只想遍历文件夹…你在找这样的东西吗?

cd parent
find . -type d | while read d; do
ls $d/
done

你可以使用

find .

递归搜索当前目录下的所有文件/dirs

然后您可以像这样通过xargs命令输出

find . | xargs 'command here'

如果顶层文件夹是已知的,你可以这样写:

for dir in `ls $YOUR_TOP_LEVEL_FOLDER`;
do
for subdir in `ls $YOUR_TOP_LEVEL_FOLDER/$dir`;
do
$(PLAY AS MUCH AS YOU WANT);
done
done

在$上(想玩多少就玩多少);你可以放尽可能多的代码。

注意,我没有在任何目录上使用“cd”。

欢呼,

当当前目录为parent_directory时,可以执行以下操作:

for d in [0-9][0-9][0-9]
do
( cd "$d" && your-command-here )
done

()创建了一个子shell,所以当前目录在主脚本中不会改变。

for p in [0-9][0-9][0-9];do
(
cd $p
for f in [0-9][0-9][0-9][0-9]*.txt;do
ls $f; # Your operands
done
)
done
for dir in PARENT/*
do
test -d "$dir" || continue
# Do something with $dir...
done

这个由托德发布的回答帮助了我。

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;

\( ! -name . \)避免执行当前目录下的命令。

如果你正在使用GNU find,你可以尝试-execdir参数,例如:

find . -type d -execdir realpath "{}" ';'

或(根据@gniourf_gniourf评论):

find . -type d -execdir sh -c 'printf "%s/%s\n" "$PWD" "$0"' {} \;

注意:你可以使用${0#./}代替$0来修复前面的./

或者更实际的例子:

find . -name .git -type d -execdir git pull -v ';'

如果你想包含当前目录,使用-exec会更简单:

find . -type d -exec sh -c 'cd -P -- "{}" && pwd -P' \;

或使用xargs:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'

@gniourf_gniourf给出的类似例子:

find . -type d -print0 | while IFS= read -r -d '' file; do
# ...
done

上面的示例支持名称中带有空格的目录。


或者通过在bash数组中赋值:

dirs=($(find . -type d))
for dir in "${dirs[@]}"; do
cd "$dir"
echo $PWD
done

.更改为特定的文件夹名称。如果你不需要递归运行,你可以使用:dirs=(*)代替。上面的示例不支持名称中有空格的目录。

因此,正如@gniourf_gniourf所建议的那样,在不使用显式循环的情况下将find的输出放入数组的唯一正确方法将在Bash 4.4中可用:

mapfile -t -d '' dirs < <(find . -type d -print0)

或者不是推荐的方式(涉及解析ls):

ls -d */ | awk '{print $NF}' | xargs -n1 sh -c 'cd $0 && pwd && echo Do stuff'

上面的例子会忽略当前的目录(OP请求的),但是它会中断带有空格的名称。

参见:

虽然一行程序适用于快速和不规范的使用,但我更喜欢下面更详细的脚本编写版本。这是我使用的模板,它可以处理许多边缘情况,并允许您编写更复杂的代码来在文件夹上执行。您可以在函数dir_command中编写bash代码。下面是dir_coomand在git中实现标记每个存储库的示例。脚本的其余部分为目录中的每个文件夹调用dir_command。还包括只遍历给定文件夹集的示例。

#!/bin/bash


#Use set -x if you want to echo each command while getting executed
#set -x


#Save current directory so we can restore it later
cur=$PWD
#Save command line arguments so functions can access it
args=("$@")


#Put your code in this function
#To access command line arguments use syntax ${args[1]} etc
function dir_command {
#This example command implements doing git status for folder
cd $1
echo "$(tput setaf 2)$1$(tput sgr 0)"
git tag -a ${args[0]} -m "${args[1]}"
git push --tags
cd ..
}


#This loop will go to each immediate child and execute dir_command
find . -maxdepth 1 -type d \( ! -name . \) | while read dir; do
dir_command "$dir/"
done


#This example loop only loops through give set of folders
declare -a dirs=("dir1" "dir2" "dir3")
for dir in "${dirs[@]}"; do
dir_command "$dir/"
done


#Restore the folder
cd "$cur"

你可以通过建立管道,然后使用xargs来实现这一点。问题是你需要使用-I标志,它将用每个xargs传递的子字符串替换bash命令中的子字符串。

ls -d */ | xargs -I {} bash -c "cd '{}' && pwd"

你可能想用你想在每个目录中执行的任何命令来替换pwd

  #!/bin.bash
for folder_to_go in $(find . -mindepth 1 -maxdepth 1 -type d \( -name "*" \) ) ;
# you can add pattern insted of * , here it goes to any folder
#-mindepth / maxdepth 1 means one folder depth
do
cd $folder_to_go
echo $folder_to_go "########################################## "
  

whatever you want to do is here


cd ../ # if maxdepth/mindepath = 2,  cd ../../
done


#you can try adding many internal for loops with many patterns, this will sneak anywhere you want

你可以在每个文件夹中运行一行命令序列,比如:

for d in PARENT_FOLDER/*; do (cd "$d" && tar -cvzf $d.tar.gz *.*)); done