异步 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,并且异步执行此操作。

暂时忽略脚本的异步元素(位于&的末尾),我如何将 a 添加到行的末尾,例如(这将显示在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

它不起作用,因为 shell 变量installedprogressbar函数(在其子 shell 环境中)和installplugin函数中是两个不同的变量。progressbar由于您将其作为后台任务启动,因此该函数在子 shell 中执行。当函数启动时,它将从其父环境继承该值,但父级将无法在子环境(子 shell progressbar)中设置新值。

这仍然用作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

相关内容