假设我所在的目录有一些子目录 、dir1
、dir2
和dir3
。每个目录都有一个文件foo
,我想在foo
每个目录中的每个目录上执行相同的命令,并从该目录内部执行该命令。
如果我“手工”完成它,它看起来会像这样:
cd dir1
(execute on foo)
cd ../dir2
(execute on foo)
cd ../dir3
(execute on foo)
必须执行该命令从每个目录。 foo
是一个批处理调度脚本(对于 HTCondor,如果您想知道)并且必须从每个子目录执行,以便调度脚本启动的运行的输出将最终出现在每个子目录中。
问题“查找文件并在文件目录中执行命令据我所知,没有回答我的问题。该问题的第一个答案更多的是一种解决方法,在我的情况下不起作用,第二个答案没有足够的解释让我知道如何使用它。
答案1
假设您find
支持它,请使用该-execdir
选项而不是-exec
find . -type f -name 'foo' -execdir pwd \;
这将依次更改为每个目录,如果foo
那里存在文件,它将运行pwd
。
注意:您无法重新利用此解决方案在名为 的目录中运行命令foo
。为此,您需要恢复到一种简单的-exec sh -c '...'
方法,迭代提供给每个参数sh
并cd
依次使用每个参数。此示例pwd
在每个目录中运行:
find . -type d -name 'foodir' -exec sh -c '
for d in "$@"; do ( cd "$d" || exit; pwd ); done
' _ {} +
答案2
假设您确切知道在哪些目录中运行命令,
for dir in dir1 dir2 dir3; do
( cd "$dir" && somecommand foo )
done
或者,循环遍历foo
文件,
for foo in ./*/foo; do
( cd "${foo%/foo}" && somecommand foo )
done
子 shell 可以防止cd
影响脚本其余部分的工作目录。参数${foo%/foo}
替换扩展到文件所在目录的名称(通过从 的值中foo
删除 Knows 后缀字符串)。/foo
$foo
使用标准来做同样的事情(在文件可能位于目录结构深处的find
情况下):foo
find . -type f -name foo -exec sh -c '
for foo do
( cd "${foo%/foo}" && somecommand foo )
done' sh {} +
用言语来说:查找当前目录或以下任意位置的所有名为“foo”的常规文件,并将其路径名批量提供给此 shell 脚本。 shell 脚本应迭代给定的路径名,将目录更改为每个路径名的目录部分,如果成功,则执行somecommand foo
.
有关使用非标准的解决方案-execdir
,请参阅罗艾玛的回答。他的回答适合我的例子:
find . -type f -name foo -execdir somecommand foo ';'
答案3
也许不漂亮,但我认为它可以完成工作
find . -name 'foo' -type f -exec sh -c 'cd $(echo {}|cut -d"/" -f2) && ./foo' \;
答案4
在 Win 10 上的 WSL 和 GitBash 中进行了测试。
以前的解决方案中的 execdir 将不起作用,因为该命令将使用当前目录作为参数执行,而不是进入其中。
您只需 cd 进入该目录并执行您想要的操作即可。
例如,这是我在开始工作之前用来更新所有存储库的方法
find $HOME/workspace/ -maxdepth 1 -type d -name "repo*" -exec bash -c "cd \"{}\" && echo ____Pulling from \"{}\" && git pull" \;
编辑:
如果您不在个人电脑/笔记本电脑上并且需要更强大的代码,您应该编写一个不可使用外部命令注入的脚本,例如:
#!/bin/sh
find "$HOME/workspace/" -maxdepth 1 -type d -exec sh -c '
for dir in "$@"
do
echo "____Pulling from $dir"
cd "$dir"
git pull
done' sh {} +