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위와 동일한 명령이지만 이러한 디렉터리로의 이동도 중지합니다 -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) 해당 경로 이름을 반복하여 작업을 수행합니다.

관련된:

관련 정보