비동기 bash 스크립트의 각 출력 줄에 대한 기본 진행률 표시줄

비동기 bash 스크립트의 각 출력 줄에 대한 기본 진행률 표시줄

Vim 플러그인을 설치하기 위한 기본 bash 스크립트가 있다고 가정해 보겠습니다.

#!/usr/bin/env bash

plugins=(
tpope/vim-endwise
tpope/vim-fugitive
tpope/vim-surround
tpope/vim-unimpaired
)

rm -rf $HOME/.vim/pack/bundle/*
mkdir $HOME/.vim/pack/bundle/start

installplugin() {
  plugin=”$(echo “$1" | sed -e ‘s/.*[\/]//’)”
  git clone –depth=1 -q https://github.com/$1.git \
    $HOME/.vim/pack/bundle/start/$plugin
  rm -rf $HOME/.vim/pack/bundle/start/$plugin/.git*
  echo $plugin installed!
}

for repo in ${plugins[@]}; do
  installplugin “$repo” &
done

wait

이는 배열의 각 저장소를 plugins복제하고 ~/.vim/pack/bundle/start이를 비동기식으로 수행합니다.

지금은 스크립트의 비동기 요소( &의 끝에 위치)를 무시합니다.installplugin “$repo” &.Installing $plugin시작주어진 플러그인의 설치 프로세스) 매초마다 진행률 표시줄로 Done.해당 플러그인을 마친 후 같은 줄에 출력하고 다음 플러그인을 계속할 수 있습니까?

이 문제에 대한 나의 견해는 다음과 같습니다.

#!/usr/bin/env bash

plugins=(
tpope/vim-endwise
tpope/vim-fugitive
tpope/vim-surround
tpope/vim-unimpaired
)

rm -rf $HOME/.vim/pack/bundle/*
mkdir $HOME/.vim/pack/bundle/start

progressbar() {
  until [ $installed -eq 1 ]; do
    sleep 0.1
    echo -n '.'
  done
}

installplugin() {
  installed=0
  echo -n "Installing $plugin"
  progressbar &
  plugin=”$(echo “$1" | sed -e ‘s/.*[\/]//’)”
  git clone –depth=1 -q https://github.com/$1.git \
    $HOME/.vim/pack/bundle/start/$plugin
  rm -rf $HOME/.vim/pack/bundle/start/$plugin/.git*
  installed=1
  echo ' Done.'
}

for repo in ${plugins[@]}; do
  installplugin “$repo”
done

wait

작동하지 않지만 이유를 이해하지 못합니다.

해결하기가 간단하다고 생각합니다. 원본 스크립트가 비동기라는 것을 기억하면 Installing각 메시지의 출력이 맨 아래부터 몇 줄인지 기억한 다음 설치될 때까지 점으로 줄을 업데이트해야 하기 때문에 해결하기가 더 복잡해집니다. 해당 플러그인. 앞서 설명한 진행률 표시줄의 기본 형태를 표시하려면 원본 스크립트를 수정해야 합니까?

답변1

쉘 변수는 함수 installed내 (하위 쉘 환경에서)와 함수 내에서 두 개의 서로 다른 변수이기 때문에 작동하지 않습니다 . 백그라운드 작업으로 시작하기 때문에 함수는 하위 셸에서 실행됩니다. 함수가 시작되면 상위 환경에서 값을 상속하지만 상위는 하위 환경(subshell )에서 새 값을 설정할 수 없습니다.progressbarinstallpluginprogressbarprogressbar

이는 여전히 progressbar백그라운드 작업으로 작동하지만 무한 루프를 종료하도록 트랩을 설정할 수 있습니다. 주 함수는 foo적절한 신호를 보내 트랩을 완료하고 트리거합니다.

progressbar () {
    trap 'break' USR1

    while printf '.' >&2; do
        sleep 0.25
    done
}

foo () {
    progressbar & pid="$!"

    echo 'working...'
    sleep 5
    echo 'done.'

    kill -s USR1 "$pid"
}

foo

관련 정보