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

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












0














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?










share|improve this question























  • Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
    – nwildner
    Dec 12 at 13:21















0














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?










share|improve this question























  • Hi Aramis. This could help you - stackoverflow.com/questions/238073/…
    – nwildner
    Dec 12 at 13:21













0












0








0







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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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
















  • 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










1 Answer
1






active

oldest

votes


















0














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





share|improve this answer






















  • 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










  • 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










  • Hmm, it seems the recommended way to do something like this involves temporary files …
    – Aramis Razzaghipour
    Dec 14 at 22:06










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
);



);













draft saved

draft discarded


















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









0














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





share|improve this answer






















  • 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










  • 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










  • Hmm, it seems the recommended way to do something like this involves temporary files …
    – Aramis Razzaghipour
    Dec 14 at 22:06















0














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





share|improve this answer






















  • 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










  • 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










  • Hmm, it seems the recommended way to do something like this involves temporary files …
    – Aramis Razzaghipour
    Dec 14 at 22:06













0












0








0






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





share|improve this answer














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






share|improve this answer














share|improve this answer



share|improve this answer








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 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










  • 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










  • 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










  • @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










  • @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















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

















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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






Popular posts from this blog

Peggy Mitchell

The Forum (Inglewood, California)

Palaiologos