Got a Debian package set up for a little application I was working on, this isn't really relevant for the question but for some context, the application is a simple bash script that deploys some docker containers on the local machine. But I wanted to add a dependency check to make sure the system had docker before it attempted to do anything. If it doesn't, download it, if it does, ignore it. Figured it be nice to have a little zenity dialog alongside it to show what was going on.
In that process, I check for internet before starting for obvious reasons and for some reason, the way I check if there is internet if zenity has the --auto-close flag, will instantly close the entire progress block.
Here is a little dummy example, that if statement is a straight copy-paste from my code, everything else is filler. :
#!/bin/bash
condition=0
if [[ $condition ]]; then
(
echo "0"
# Check for internet
if ping -c 3 -W 3 gcr.io; then
echo "# Internet detected, starting updates..."; sleep 1
echo "10"
else
err_msg="# No internet detected. You may be missing some dependencies.
Services may not function as expected until they are installed."
echo $err_msg
zenity --error --text="$err_msg"
echo "100"
exit 1
fi
echo "15"
echo "# Downloading a thing" ; sleep 1
echo "50"
if zenity --question --text="Do you want to download a special thing?"; then
echo "# Downloading special thing" ; sleep 1
else
echo "# Not downloading special thing" ; sleep 1
fi
echo "75"
echo "# downloading big thing" ; sleep 3
echo "90"
echo "# Downloading last thing" ; sleep 1
echo "100"
) |
zenity --progress --title="Dependency Management" --text="downloading dependencies, please wait..." \
--percentage=0 --auto-close
fi
So im really just wondering why this is making zenity freak-out. If you comment out that if statement, everything works as you expect and zenity progress screen closes once it hits 100. If you keep the if statement but remove the auto-close flag, it will execute as expected. It's like its initializing at 100 and then going to 0 to progress normally. But if that was the case, --auto-close would never work but in the little example they give you in the help section, it works just fine. https://help.gnome.org/users/zenity/stable/progress.html.en
Thank you for a fun puzzle! Spoiler is at the end, but I thought it might be helpful to look over my shoulder while I poked at the problem. ️ If you're more interested in the answer than the journey, feel free to scroll. I'll never know, anyway.
Following my own advice (see 1st comment beneath the question), I set out to create a small, self-contained, complete example. But, as they say in tech support: Before you can debug the problem, you need to debug the customer. (No offense; I'm a terrible witness myself unless I know ahead of time that someone's going to need to reproduce a problem I've found.)
I interpreted your comment about checking for Internet to mean "it worked before I added the
ping
and failed afterward," so the most sensible course of action seemed to be commenting out that part of the code... and then it worked! So what happens differently when theping
is added?Changes in timing wouldn't make sense, so the problem must be that
ping
generates output that gets piped tozenity
. So I changed the command to redirect its output to the bit bucket:ping -c 3 -W 3 gcr.io
&>/dev/null
;
...and that worked, too! Interesting!
I explored what turned out to be a few ratholes:
ping
from the command line and piped its output throughod -xa
to check for weird control characters, but nope.if
block in parentheses (()), which executes the commands in a sub-shell, I tried braces ({}) to execute them in the same shell. Nope, again.Then I realized I could just do
ping -c 3 -W 3 gcr.io | zenity --progress --auto-close
directly from the command line. That failed with the
--auto-close
flag but worked normally without it. Boy, did that simplify things! That's about as "smallest" as you can get. But it's not, actually: I used up all of my remaining intelligence points for the day by redirecting the output fromping
into a file, so I could just(cat output; sleep 1) | zenity --progress --auto-close
and not keep poking at poor
gcr.io
until I finally figured this thing out. (Thesleep
gave me enough time to see the pop-up when it worked, becausezenity
exits when the pipe closes at the end of the input. So, what's in thatoutput
file?The magic
zenity
-killer must be in there somewhere! All that was left (ha, "all"!) was to make my "smallest" example even smaller by deleting pieces of the file until it stopped breaking. Then I'd put back whatever I'd deleted last, and I deleted something else, da capo, ad nauseam, or at leastad minimus
. (Or whatever; I don't speak Latin.) Eventually the file dwindled toand I started deleting stuff from the beginning. Eventually I found that it would break regardless of the length of the line, as long as it started with a number that wasn't 0 and had at least 3 digits somewhere within it. Huh. It'd also break if it did start with a 0 and had at least 4 digits within... unless the second digit was also 0! What's more, a period would make it even weirder: none of the digits anywhere after the period would make it break, no matter what they were.
And then, then came the ah-ha! moment. The
zenity
documentation says:Wow, really? It can't be that ridiculous, can it?
I found the source for
zenity
, downloaded it, extracted it (withtar -xf zenity-3.42.1.tar.xz
), openedprogress.c
, and found the function that checks to see if "a line contains only a number." The function is called only if the first character in the line is a number.Do you see it yet? Here, I'll give you a sscce, with comments:
Now do you see it?
The author decides "[i]f a line contains only a number" by checking (only!) that the first character is a number. If it is, then it plucks out all the digits (and the first decimal, if there is one), mashes them all together, and returns whatever it found, ignoring anything else it may have seen.
So of course it failed if there were 3 digits and the first wasn't 0, or if there were 4 digits and the first 2 weren't 0... because a 3-digit number is always at least 100, and
zenity
will--auto-close
as soon as the progress is 100 or higher.Spoiler:
The
ping
statement generates output that confuseszenity
into thinking the progress has reached 100%, so it closes the dialog.By the way, congratulations: you found one of the rookiest kinds of rookie mistakes a programmer can make... and it's not your bug! For whatever reason, the author of
zenity
decided to roll their own function to convert a line of text to a floating-point number, and it doesn't do at all what the doc says, or what any normal person would expect it to do. (Protip: libraries will do this for you, and they'll actually work most of the time.)You can score a bunch of karma points if you can figure out how to report the bug, and you'll get a bonus if you submit your report in the form of a fix. ️