2

Hi guys I am currently trying to implement zenity progress bar to my while loop, however I noticed that my variable which are meant to be incremented did not increment. Here is a sample test script I tried:

i=0
p=0

while [ $i -lt 10 ]
do
      i=$[$i + 1]
      echo $i
      p=$[$p + 1]
done | (zenity --progress --title="test" --text="test")
echo "i: $i p: $p"

I noticed that the progress bar worked, however the variable p which is meant to be a counter was affected by zenity. Is there something wrong with my code? variable i is meant to echo the value in order to move the progress bar, while variable p is meant for other purposes. The values of p and i are both 0 despite incrementing it within the while loop.

I am hoping that there is a way to make the variable p and i increment without removing the zenity progress bar. I am not sure why however, the incrementing of the variables work after the line (zenity --progress --title="test" --text="test") is removed

Addition

How to use the variables i and p after the progress bar ended? And one more question, is it required to enclose the while loop with ()?

Thanks for any help!

2

Increment and everything seems to be absolutely fine. But all the increments are taking place inside a subshell that is being passed to zenity. This is the reason why you are not getting the changes when you echo them outside the subshell. I am using your script, only adding something to print the variables inside do while loop on zenity popup window. To know more about the syntax of zenity progress dialog see the gnome help page. Run the script below and see the result,

#!/bin/bash
i=0
p=0
(while [ $i -lt 100 ]
do
    i=$[$i + 10]
    echo $i ; sleep 1
    echo "#  now i is $i and p=$p"
    p=$[$p + 1]
done) | zenity --progress --title="test" --text="test"
echo "i: $i p: $p"

I changed increment of i to 10 as i will be used to make the increment of progress bar and used sleep 1 to make the progress perceptible.

Observation: Though the value are showing to be incremented on zenity pop-up. It is showing to be unchanged on terminal, i: 0 p: 0

the zenity window

Hope this would be helpful.

How to Use subshell variables outside

The parent shell can not use variables from its subshell. You could find more about subshell here . But you can always write variables from subshell to a temporary file for its parent to read. It may not be the best of the ways but it works.

#!/bin/bash
..
(while [ $i -lt 100 ]
do
    ...
    ...
done
echo "p=$(echo $p)" > tmp
echo "i=$(echo $i)" >> tmp
) | zenity --progress --title="test" --text="test"
. tmp
rm tmp
echo "i: $i p: $p"

Now it will show up in the terminal like, i: 100 p: 10 so you an use them at your wish. And as you asked in last part, it is not the while loop rather it is subshell. It is custom to put contents of subshell inside parentheses.

  • Hi souravc, thanks for the help! My main issue now is i need to use the variable p after the progress bar ended. Any ideas on how to do that? And one more question, is it required to enclose the while loop with "()"? – pikachu Dec 3 '13 at 1:23
1

Process substitution can prevent annoying subshells from being created, but the syntax is a bit weird:

$ k=0; for x in a b; do ((k++)); done | zenity --progress; echo "$k"

→ 0 (Not OK)

$ k=0; for x in a b; do ((k++)); done > >(zenity --progress); echo "$k"

→ 2 (OK)

What I like about that is that you generally don't have to heavily modify your script for it to work properly. However, some exotic shells might be missing this feature. For Bash, check the “Process Substitution” section of the manual.

With a code more close to the example from the initial question:

  i=0
  p=0

  while [ $i -lt 10 ]
  do
        i=$[$i + 1]
        echo $((10 * i))
        sleep 0.1
        p=$[$p + 1]
  done > >(zenity --progress --title="test" --text="test")
  echo "i: $i p: $p"

(I added a sleep to make the progress more noticeable, and I echo ten times i to have a 100 when reaching the end of the loop.)

  • You can add sleep 1; after each instance of ((k++)); and notice the progress bar doesn't actually progress. It starts off with none and ends with everything showing no steps in between. – WinEunuuchs2Unix May 12 '18 at 15:44
  • @WinEunuuchs2Unix That's because my example is not very good as it does not even try to output a progress number to the loop's standard output. Try running a=0; for p in 33 67 100; do a=1; sleep 1; echo "$p"; done > >(zenity --progress --auto-close --auto-kill); echo "$a" and you should have both the progress meter working AND the kept change to a. I actually used this technique is a personal script right after I suggested it here. – Alice M. May 13 '18 at 17:49
  • That's awesome Alice! +1. Might I suggest you include the new code in your answer so people can easily copy and paste it into their terminal? – WinEunuuchs2Unix May 13 '18 at 18:01
  • I added an example using the initial question's code. Thanks for making me less lazy. – Alice M. May 14 '18 at 12:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.