我如何编写一个bash脚本,遍历parent_directory内的每个目录,并在每个目录中执行命令。
目录结构如下:
Parent_directory(名称可以是任何东西-不遵循模式) 001(目录名称遵循此模式) 0001.txt(文件名遵循此模式) 0002.三种 0003.三种 002 0001.三种 0002.三种 0003.三种 0004.三种 003 0001.三种 目录数量未知。
我如何编写一个bash脚本,遍历parent_directory内的每个目录,并在每个目录中执行命令。
目录结构如下:
Parent_directory(名称可以是任何东西-不遵循模式) 001(目录名称遵循此模式) 0001.txt(文件名遵循此模式) 0002.三种 0003.三种 002 0001.三种 0002.三种 0003.三种 0004.三种 003 0001.三种 目录数量未知。
当前回答
如果你正在使用GNU find,你可以尝试-execdir parameter,例如:
find . -type d -execdir realpath "{}" ';'
or (as for @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请求的),但是它会中断带有空格的名称。
参见:
Bash:用于SO的每个目录 如何进入当前路径下的每个目录并执行脚本?在SE Ubuntu
其他回答
如果顶层文件夹是已知的,你可以这样写:
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”。
欢呼,
for dir in PARENT/*
do
test -d "$dir" || continue
# Do something with $dir...
done
当当前目录为parent_directory时,可以执行以下操作:
for d in [0-9][0-9][0-9]
do
( cd "$d" && your-command-here )
done
(和)创建一个子shell,因此当前目录不会在主脚本中更改。
While one liners are good for quick and dirty usage, I prefer below more verbose version for writing scripts. This is the template I use which takes care of many edge cases and allows you to write more complex code to execute on a folder. You can write your bash code in the function dir_command. Below, dir_coomand implements tagging each repository in git as an example. Rest of the script calls dir_command for each folder in directory. The example of iterating through only given set of folder is also include.
#!/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替换为您想在每个目录中执行的任何命令。