重构 for 循环来使用 exec

重构 for 循环来使用 exec

我有一个 bash 脚本,其功能类似于以下内容:

for src in $(find -H "$DOTFILES_ROOT" -maxdepth 2 -name '*.sym' -not -path '*.git*')
 do
   dst="$HOME/$(basename "${src%.*}")"
   link_file "$src" "$dst"
 done

我已经在我的脚本上运行了 shellcheck 并且它返回了

For loops over find output are fragile. Use find -exec or a while read loop.

我读过并理解了,这对我来说很有意义,例如

find -H "$(pwd)" -maxdepth 2 -name '*.sym' -not -path '*.git*' -exec echo {} \;

但我不确定如何使其与 for 循环中的变量一起使用

答案1

循环中的变量forsrcdstsrc是由 赋予循环的文件的路径名find并由dst计算得出src

您的循环可以转换为find -exec如下命令:

find -H "$DOTFILES_ROOT" -maxdepth 2 -type d -name '.git' -prune -o \
    -type f -name '*.sym' -exec sh -c '
        link_file "$1" "$HOME/$( basename "${1%.*}" )"' sh {} ';'

我假设您-not -path '*.git*'不打算查看.git目录。这与-type d -name '.git' -prune上面的命令相同,但-prune我们find甚至停止进入这些目录。

一旦我们清除了.git目录,我们就开始寻找.sym文件。当找到一个时,循环中的命令就会被执行。该命令通过sh -c(以便能够通过参数替换和 执行一些奇特的事情)执行basename,并且找到的文件的路径名在内部可用$1

人们甚至可以将您的循环(几乎)按照您所写的那样合并:

find -H "$DOTFILES_ROOT" -maxdepth 2 -type d -name '.git' -prune -o \
    -type f -name '*.sym' -exec sh -c '
        for src do
            dst="$HOME/$( basename "${src%.*}" )"
            link_file "$src" "$dst"
        done' sh {} +

在这种情况下,sh -c脚本给出的不是单个路径名,而是多个路径名(由于+末尾的-exec),因此我们循环遍历这些路径名并执行操作。

有关的:

相关内容