假设我有一个用于安装 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 变量installed
在progressbar
函数(在其子 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