非同期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内(サブシェル環境で)と関数内で2つの異なる変数なので、機能しません。バックグラウンドジョブから始まるため、関数はサブシェルで実行されます。関数が起動すると、親環境から値を継承しますが、親は子環境(subshel​​l)で新しい値を設定できません。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

おすすめ記事