1

While trying to make the Cancel button on a Zenity --progress window work for my scripts I've realized I don't understand how the Cancel button works at all in the example given on the Zenity Manual page: https://help.gnome.org/users/zenity/stable/progress.html.en

#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
  --title="Update System Logs" \
  --text="Scanning mail logs..." \
  --percentage=0

if [ "$?" = -1 ] ; then
        zenity --error \
          --text="Update canceled."
fi

When that script is run, why does the process stop when the Cancel button is pushed when there is no exit or break or any other command visible?

I thought Zenity was just a program to display graphical interfaces and return exit codes that can be used to launch the actual commands desired (like exit if cancelled, etc), but it seems like Zenity must be doing something much more complicated because there doesn't seem to be any reason for the commands in the example to actually stop when the button is pressed.

Is Zenity doing something more complicated, or am I misunderstanding something? I am new to bash/sh scripting so it seems like I'm probably misunderstanding. If it's just a complex function unique to Zenity then a full technical description of how it works is not necessary; just enough of an explanation so it can be used reliably is what I would like. Thank you.

(I'd like to also ask why this example from the official manual does not actually work [on Ubuntu 14.04] because no --error Zenity window is ever shown, but I don't think StackExchange likes joint questions, so nevermind that unless it's related to how I might be misunderstanding.)

Related post: Terminate script using zenity progress bar (does not answer my question because the top answer there said to use --auto-kill when in this example the process is cancelled without using --auto-kill

2 Answers 2

1

The () syntax in sh scripts allows you to start a subshell. You can think of subshells as though the following two lines were the same:

(echo foo)
sh -c "echo foo"

i.e., there's a second process inside your shell script that handles everything between the (). By way of the pipe symbol ("|"), the standard output of that subshell is connected to the standard input of zenity.

When you click the "cancel" button in the zenity window, that will cause zenity to exit immediately. At that point, the standard output of the subshell becomes invalid. This doesn't immediately kill the subshell; however, when the next echo command in that subshell wants to write to stdout, it will receive a SIGPIPE signal, signifying that the pipe to which it is trying to write has no readers. The standard behaviour of a process upon SIGPIPE is to terminate.

You'll note that if you start your script from a terminal and click the "cancel" button just after an update has been sent to zenity, your shell prompt doesn't return immediately; since the sleep command is still running, and since sleep doesn't produce output, it takes a moment before any output is produced and the SIGPIPE is issued.

If you don't want this behaviour, then you should tell the shell not to exit upon receiving SIGPIPE:

#!/bin/sh
(
    trap -- '' PIPE
    echo "10"; sleep 1
    # ... etc, your normal script goes here
) |
zenity --progress ...

This version will ignore SIGPIPE, and continue happily when zenity exits. However, do note that in that case, the "cancel" button will be very confusing for the user; it will cause zenity to exit, but it will not cause the operation to be aborted. It might be better to just pass --no-cancel instead.

0

On Cancel zenity sends out 1 (echo $?)

#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
  --title="Update System Logs" \
  --text="Scanning mail logs..." \
  --percentage=0

if [ $? -eq 1 ] ; then
        zenity --error \
          --text="Update canceled."
fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .