Basic progress bar for each line of output in an async bash script

Clash Royale CLAN TAG#URR8PPP
Say I have this basic bash script for installing Vim plugins:
#!/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"
for repo in $plugins[@]; do
installplugin “$repo” &
done
wait
It clones each repository in the array plugins to ~/.vim/pack/bundle/start, and does so asynchronously.
Ignoring the async element of the script (the & at the end of installplugin “$repo” &) for the moment, how would I add a . to the end of a line such as Installing $plugin (which would show at the start of the installation process of a given plugin) every second or so, as a form of progress bar, perhaps outputting Done. on the same line after completion of that plugin, then moving on to the next plugin?
Here is my stab at the issue:
#!/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() 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
It does not work, but I do not understand why.
What I assume is a simple thing to solve becomes much more complicated if you remember that the original script was asynchronous, as you would have to remember how many lines up the output of each Installing message is from the bottom, and then update the lines with dots until their respective plugin has been installed. I need to modify the original script to show the basic form of progress bar I described earlier?
bash shell-script
add a comment |
Say I have this basic bash script for installing Vim plugins:
#!/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"
for repo in $plugins[@]; do
installplugin “$repo” &
done
wait
It clones each repository in the array plugins to ~/.vim/pack/bundle/start, and does so asynchronously.
Ignoring the async element of the script (the & at the end of installplugin “$repo” &) for the moment, how would I add a . to the end of a line such as Installing $plugin (which would show at the start of the installation process of a given plugin) every second or so, as a form of progress bar, perhaps outputting Done. on the same line after completion of that plugin, then moving on to the next plugin?
Here is my stab at the issue:
#!/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() 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
It does not work, but I do not understand why.
What I assume is a simple thing to solve becomes much more complicated if you remember that the original script was asynchronous, as you would have to remember how many lines up the output of each Installing message is from the bottom, and then update the lines with dots until their respective plugin has been installed. I need to modify the original script to show the basic form of progress bar I described earlier?
bash shell-script
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21
add a comment |
Say I have this basic bash script for installing Vim plugins:
#!/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"
for repo in $plugins[@]; do
installplugin “$repo” &
done
wait
It clones each repository in the array plugins to ~/.vim/pack/bundle/start, and does so asynchronously.
Ignoring the async element of the script (the & at the end of installplugin “$repo” &) for the moment, how would I add a . to the end of a line such as Installing $plugin (which would show at the start of the installation process of a given plugin) every second or so, as a form of progress bar, perhaps outputting Done. on the same line after completion of that plugin, then moving on to the next plugin?
Here is my stab at the issue:
#!/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() 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
It does not work, but I do not understand why.
What I assume is a simple thing to solve becomes much more complicated if you remember that the original script was asynchronous, as you would have to remember how many lines up the output of each Installing message is from the bottom, and then update the lines with dots until their respective plugin has been installed. I need to modify the original script to show the basic form of progress bar I described earlier?
bash shell-script
Say I have this basic bash script for installing Vim plugins:
#!/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"
for repo in $plugins[@]; do
installplugin “$repo” &
done
wait
It clones each repository in the array plugins to ~/.vim/pack/bundle/start, and does so asynchronously.
Ignoring the async element of the script (the & at the end of installplugin “$repo” &) for the moment, how would I add a . to the end of a line such as Installing $plugin (which would show at the start of the installation process of a given plugin) every second or so, as a form of progress bar, perhaps outputting Done. on the same line after completion of that plugin, then moving on to the next plugin?
Here is my stab at the issue:
#!/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() 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
It does not work, but I do not understand why.
What I assume is a simple thing to solve becomes much more complicated if you remember that the original script was asynchronous, as you would have to remember how many lines up the output of each Installing message is from the bottom, and then update the lines with dots until their respective plugin has been installed. I need to modify the original script to show the basic form of progress bar I described earlier?
bash shell-script
bash shell-script
edited Dec 12 at 18:06
Rui F Ribeiro
38.8k1479128
38.8k1479128
asked Dec 12 at 11:45
Aramis Razzaghipour
1
1
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21
add a comment |
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21
add a comment |
1 Answer
1
active
oldest
votes
It does not work since the shell variable installed is two different variables in the progressbar function (in its subshell environment) and in the installplugin function. The progressbar function is executed in a subshell since you start it as a background task. It will inherit the value from its parent environment when the function is started, but the parent will not be able to set a new value in the child environment (the progressbar subshell).
This still uses progressbar as a background task, but lets it set up a trap to exit the infinite loop. The main function, foo, triggers the trap by sending it the appropriate signal when it's done.
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
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when runningfoo &multiple times? If it helps, it is known how many timesfoowill be run.
– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basicallyworking...is echoed multiple times, each on its own line, and then the dots fromprogressbarappear on each line independently. I’m guessing that thee[xAescape sequence will be used to overwrite specific lines?
– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort ofcurseslibrary to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.
– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f487557%2fbasic-progress-bar-for-each-line-of-output-in-an-async-bash-script%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
It does not work since the shell variable installed is two different variables in the progressbar function (in its subshell environment) and in the installplugin function. The progressbar function is executed in a subshell since you start it as a background task. It will inherit the value from its parent environment when the function is started, but the parent will not be able to set a new value in the child environment (the progressbar subshell).
This still uses progressbar as a background task, but lets it set up a trap to exit the infinite loop. The main function, foo, triggers the trap by sending it the appropriate signal when it's done.
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
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when runningfoo &multiple times? If it helps, it is known how many timesfoowill be run.
– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basicallyworking...is echoed multiple times, each on its own line, and then the dots fromprogressbarappear on each line independently. I’m guessing that thee[xAescape sequence will be used to overwrite specific lines?
– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort ofcurseslibrary to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.
– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
add a comment |
It does not work since the shell variable installed is two different variables in the progressbar function (in its subshell environment) and in the installplugin function. The progressbar function is executed in a subshell since you start it as a background task. It will inherit the value from its parent environment when the function is started, but the parent will not be able to set a new value in the child environment (the progressbar subshell).
This still uses progressbar as a background task, but lets it set up a trap to exit the infinite loop. The main function, foo, triggers the trap by sending it the appropriate signal when it's done.
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
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when runningfoo &multiple times? If it helps, it is known how many timesfoowill be run.
– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basicallyworking...is echoed multiple times, each on its own line, and then the dots fromprogressbarappear on each line independently. I’m guessing that thee[xAescape sequence will be used to overwrite specific lines?
– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort ofcurseslibrary to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.
– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
add a comment |
It does not work since the shell variable installed is two different variables in the progressbar function (in its subshell environment) and in the installplugin function. The progressbar function is executed in a subshell since you start it as a background task. It will inherit the value from its parent environment when the function is started, but the parent will not be able to set a new value in the child environment (the progressbar subshell).
This still uses progressbar as a background task, but lets it set up a trap to exit the infinite loop. The main function, foo, triggers the trap by sending it the appropriate signal when it's done.
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
It does not work since the shell variable installed is two different variables in the progressbar function (in its subshell environment) and in the installplugin function. The progressbar function is executed in a subshell since you start it as a background task. It will inherit the value from its parent environment when the function is started, but the parent will not be able to set a new value in the child environment (the progressbar subshell).
This still uses progressbar as a background task, but lets it set up a trap to exit the infinite loop. The main function, foo, triggers the trap by sending it the appropriate signal when it's done.
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
edited Dec 12 at 13:42
answered Dec 12 at 13:19
Kusalananda
121k16228372
121k16228372
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when runningfoo &multiple times? If it helps, it is known how many timesfoowill be run.
– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basicallyworking...is echoed multiple times, each on its own line, and then the dots fromprogressbarappear on each line independently. I’m guessing that thee[xAescape sequence will be used to overwrite specific lines?
– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort ofcurseslibrary to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.
– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
add a comment |
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when runningfoo &multiple times? If it helps, it is known how many timesfoowill be run.
– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basicallyworking...is echoed multiple times, each on its own line, and then the dots fromprogressbarappear on each line independently. I’m guessing that thee[xAescape sequence will be used to overwrite specific lines?
– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort ofcurseslibrary to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.
– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when running
foo & multiple times? If it helps, it is known how many times foo will be run.– Aramis Razzaghipour
Dec 14 at 21:50
Wow, thank you! This works perfectly ignoring the async part of the script. How would I adapt it so it works when running
foo & multiple times? If it helps, it is known how many times foo will be run.– Aramis Razzaghipour
Dec 14 at 21:50
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
@AramisRazzaghipour How would you envisage multiple progress bars being displayed?
– Kusalananda
Dec 14 at 21:54
Basically
working... is echoed multiple times, each on its own line, and then the dots from progressbar appear on each line independently. I’m guessing that the e[xA escape sequence will be used to overwrite specific lines?– Aramis Razzaghipour
Dec 14 at 21:57
Basically
working... is echoed multiple times, each on its own line, and then the dots from progressbar appear on each line independently. I’m guessing that the e[xA escape sequence will be used to overwrite specific lines?– Aramis Razzaghipour
Dec 14 at 21:57
@AramisRazzaghipour You would probably need some sort of
curses library to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.– Kusalananda
Dec 14 at 22:00
@AramisRazzaghipour You would probably need some sort of
curses library to do that. Any implementation that just prints dots in a background subshell can not be aware of how many other progress bars are currently running concurrently. I might get back to this late though.– Kusalananda
Dec 14 at 22:00
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
Hmm, it seems the recommended way to do something like this involves temporary files …
– Aramis Razzaghipour
Dec 14 at 22:06
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f487557%2fbasic-progress-bar-for-each-line-of-output-in-an-async-bash-script%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
– nwildner
Dec 12 at 13:21