execを使用するためにforループをリファクタリングする

execを使用するためにforループをリファクタリングする

次のタスクを実行する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

ループの変数はとforです。ループ内のファイルで指定されたパス名から計算されます。srcdstsrcfinddstsrc

ループは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上記と同じコマンドですが、これらのディレクトリへの移動も停止します-prunefind

.gitディレクトリを消去すると、.symファイルの検索が開始されます。 1つが見つかると、ループ内のコマンドが実行されます。コマンドは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)、そのパス名を繰り返し操作してください。

関連:

おすすめ記事