Zenity 进度对话框的取消按钮如何发挥作用?

Zenity 进度对话框的取消按钮如何发挥作用?

在尝试使CancelZenity--progress窗口上的按钮适用于我的脚本时,我意识到我根本不明白CancelZenity 手册页面上给出的示例中的按钮是如何工作的: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

Cancel当该脚本运行时,为什么在没有exitbreak任何其他命令可见的情况下按下按钮时进程会停止?

我认为 Zenity 只是一个显示图形界面并返回退出代码的程序,可用于启动所需的实际命令(例如exit取消等),但看起来 Zenity 必须做一些更复杂的事情,因为没有似乎是示例中的命令在按下按钮时实际停止的任何原因。

Zenity 是否在做更复杂的事情,或者我误解了什么?我是 bash/sh 脚本编写的新手,所以看来我可能误解了。如果它只是 Zenity 独有的复杂功能,那么就没有必要对其工作原理进行完整的技术描述;我想要的是足够的解释,以便它可以可靠地使用。谢谢。

(我还想问为什么这个例子来自官方手册实际上不起作用[在 Ubuntu 14.04 上] 因为--error从未显示过 Zenity 窗口,但我认为 StackExchange 不喜欢联合问题,所以没关系,除非它与我可能会产生误解有关。)

相关帖子: 使用 zenity 进度条终止脚本(没有回答我的问题,因为那里的最高答案说要使用,--auto-kill在此示例中,进程被取消而不使用--auto-kill

答案1

()脚本中的语法允许sh您启动子外壳。您可以将子 shell 视为相同的以下两行:

(echo foo)
sh -c "echo foo"

即,您的 shell 脚本中有第二个进程,用于处理().通过管道符号(“ |”),该子 shell 的标准输出连接到 zenity 的标准输入。

当您单击 zenity 窗口中的“取消”按钮时,将导致 zenity 立即退出。此时,子 shell 的标准输出将变得无效。这不会立即杀死子 shell;但是,当echo该子 shell 中的下一个命令想要写入 stdout 时,它将收到一个SIGPIPE信号,表明它尝试写入的管道没有读取器。进程的标准行为SIGPIPE是终止。

您会注意到,如果您从终端启动脚本并单击“取消”按钮更新已发送至 zenity,您的 shell 提示不会立即返回;由于 sleep 命令仍在运行,并且 sleep 不会产生输出,因此需要一段时间才能产生任何输出并SIGPIPE发出 。

如果您不希望出现这种行为,那么您应该告诉 shell 在收到 SIGPIPE 后不要退出:

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

这个版本将忽略SIGPIPE,并在 zenity 退出时愉快地继续。但请注意,在这种情况下,“取消”按钮会让用户感到非常困惑;它将导致 zenity 退出,但它会不是导致操作中止。直接通过可能会更好--no-cancel

答案2

取消时 zenity 发出 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

相关内容