Is Zenity progress bar affecting variables
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 Answers
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
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.
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.)