如何将 GUI 添加到 Linux Shell 脚本

已发表: 2022-01-29

从 Ubuntu 终端启动的 zenity 信息窗口。

您可以在 Bash 脚本中使用 GUI 窗口、滑块、单选按钮、进度条等。 了解如何使用zenity工具包,并让您的 Bash 脚本焕然一新。 我们会告诉你怎么做。

Bash 脚本是一种功能强大的编程语言,因为它内置在 Bash shell 中,所以每个人都可以轻松使用它。 它是一种易于开始编程的语言。因为它是解释型的,所以您不需要编译脚本。 一旦您编辑了脚本文件并使其可执行,您就可以运行它。 这使得编码、运行和调试周期非常高效。

人们对 Bash 脚本有两个主要抱怨,首先是速度。 因为 Bash shell 解释脚本中的命令,所以它们的执行速度不如编译的代码。 然而,这就像抱怨拖拉机不如汽车快; 它们适用于不同的事物。

不过,有两种速度。 您通常可以拼凑一个快速脚本并使用它来执行任务,这比使用编译语言(例如 C)开发解决方案要快得多。

人们对 Bash 脚本的第二个抱怨是用户界面——它是一个终端窗口。 当然,有时界面并不重要。 如果唯一会使用脚本的人是它的作者,那么界面可能就没有那么重要了。 对于执行后台和批处理类型处理的脚本也无关紧要。 通常,此类脚本不需要太多(如果有的话)用户交互。

广告

有时您确实需要比终端窗口更直观和现代的东西。 大多数人都熟悉图形用户界面 (GUI)。 要为人们提供尽可能顺畅的体验,您必须从脚本中创建和使用 GUI 元素。

zenity 应用程序

zenity允许您在 Bash 脚本中加入各种图形界面元素。 这是一个功能强大的工具包,可为您的脚本提供现代感和现代、熟悉的外观。

zenity预装在 Ubuntu、Fedora 和 Manjaro 发行版上。 它是 GNOME 的一部分。 如果您使用 KDE,您可能想要查看kdialog ,尽管zenity确实可以在任何桌面环境中运行。

本文中的示例向您展示了如何从命令行创建不同的对话框窗口,如何在变量中捕获它们的返回值和用户选择,以及如何在脚本中使用对话框窗口。

我们完成了一个使用所有三种类型的对话窗口的小应用程序。

日历对话框窗口

日历对话窗口允许某人选择日期。 要创建一个zenity需要两个单词的单个命令:

 zenity--日历
广告

出现日历对话窗口。 它具有标准日期选择器所期望的所有功能。 您可以更改月份和年份,然后单击某一天以选择该日期。 默认情况下,当窗口出现时,今天的日期会突出显示。

2019 年 7 月的 Zenity 日历窗口。

单击“确定”关闭对话窗口并选择突出显示的日期。 双击一个日期做同样的事情。

如果您不想选择日期,请单击“取消”,按键盘上的“Esc”键,或关闭对话窗口。

选择了 2019 年 8 月 19 日的 Zenity 日历窗口。

在上面的示例中,选择了 2019 年 8 月 19 日。 如果用户单击“确定”,则日历将关闭,所选日期将打印在终端窗口中。

在终端窗口中显示的日历 (08/19/2019) 上选择的日期。

你可以忽略这一行,“GTKDialog mapped without a transient parent。 这是不鼓励的。”

GTK 代表 GIMP Tool Kit,它是用于开发 GNOME 界面的工具包。 它最初是由 GNU Image Manipulation Program (GIMP) 的作者设计的。 GNU 代表 GNU's Not Unix。

广告

GTK 引擎警告zenity的作者,他们以非标准方式使用了 GTK 组件。

捕获日期值

将日期打印到终端对我们来说并没有多大作用。 如果我们要从我们的脚本之一调用这个日历,我们需要捕获选定的日期值,以便我们可以在我们的脚本中使用它做一些有用的事情。 我们还将稍微定制日历。

我们将在日历中使用以下选项。 它们都必须与双破折号“–”标志一起使用:

  • –text指定要在日历中显示的文本字符串。 它取代了默认的“从下面选择一个日期”。
  • –title设置日历对话窗口的标题。
  • –day设置日历打开时选择的日期。
  • –month 设置日历打开时选择的月份。
  • –year设置日历打开时选择的年份。

我们使用一个名为ChosenDate的变量来捕获从日历返回的日期。 我们正在使用echo $ChosenDate将该日期打印到终端窗口。

是的,我们在前面的示例中获得了相同的结果,但是在这里,我们将选定的日期存储在一个变量中。 在前面的示例中,它被打印并忘记了。

 ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --day 1 --month 9 --year 2019); 回声 $ChosenDate 

现在,日历显示我们的提示和我们的窗口标题。 日期设置为我们选择的开始日期,而不是今天的日期。

选择了开始日期(2019 年 9 月 1 日)的 zenity 日历。

广告

我们还可以自定义选择时返回的日期字符串的格式。 --date-format选项必须后跟格式说明符。 这是一串标记,用于定义要包含在输出中的数据和格式。 这些标记与用于strftime() C 语言函数的标记相同,并且有大量的选择。

我们使用的令牌是:

  • %A星期几的全名。
  • %d以数字表示的月份中的日期。
  • %m以数字表示的月份。
  • %y年份为两位数(无世纪)。
 ChosenDate=$(zenity -- calendar --text "选择一个日期" --title "How-To Geek Rota" --date-format="%A %d/%m/%y" --day 1 --第 9 个月——2019 年); 回声 $ChosenDate 

有人选择日期:

选择了 2019 年 9 月 16 日的 zenity 日历窗口。

并且使用我们的格式返回日期。 它显示星期几的名称,后跟按欧洲顺序排列的日期:日、月、年。

文件选择对话框窗口:选择文件

文件选择对话框窗口相当复杂。 人们可以浏览文件系统,突出显示一个或多个文件,然后单击“确定”以选择这些文件或完全取消选择。

zenity提供了所有这些功能,甚至更多。 它与日历对话窗口一样易于使用。

我们将使用的新选项是:

  • –file-selection告诉zenity我们要使用文件选择对话框窗口。
  • –multiple允许某人选择多个文件。
  • –file-filter告诉文件对话框窗口要显示哪些文件类型。
 zenity --file-selection --tile "How-To Geek" --multiple --file-filter='*.mm *.png *.page *.sh *.txt' 

文件选择对话框窗口的功能与任何其他文件选择窗口一样。

zenity 文件部分对话框窗口,其中选择了一个文件夹。

用户可以浏览文件系统并选择她选择的文件。

zenity 文件选择对话框窗口,其中选择了一个文件

广告

我们已经浏览到一个新目录并选择了一个名为“button_hybrid.png”的文件。

单击“确定”时,文件选择对话窗口关闭,文件名和路径打印在终端窗口中。

如果您需要在任何进一步的处理中使用文件名,您可以在变量中捕获它,就像您对日历中的日期所做的那样。

文件选择对话框窗口:保存文件

如果我们添加一个选项,我们可以将文件选择对话框窗口变成文件保存对话框窗口。 选项是--save 。 我们还将使用--confirm-overwrite选项。 这会提示该人确认他想要覆盖现有文件。

 响应=$(zenity --file-selection --save --confirm-overwrite); 回声$响应

出现文件保存对话框窗口。 请注意,有人可以在其中键入文件名的文本字段。

zenity 文件保存对话框窗口。

用户可以浏览到他在文件系统中选择的位置,为文件提供名称,或单击现有文件以覆盖它。

选择现有文件的 zenity 文件保存对话框。

广告

在上面的示例中,用户突出显示了现有文件。

当他单击“确定”时,会出现一个确认对话框窗口,要求他确认是否要替换现有文件。 请注意文件名出现在警告对话框中。 正是这种对细节的关注赋予了zenity专业的外观。

如果我们没有使用--confirm-overwrite选项,该文件将被静默覆盖。

zenity 覆盖确认对话框。

文件的名称存储在变量Response中,该变量会打印到终端窗口。

通知对话框窗口

使用zenity ,在您的脚本中包含光滑的通知对话框窗口是毫不费力的。 您可以调用一些常用的对话窗口来为用户提供信息、警告、错误消息和问题。

要创建错误消息对话框窗口,请使用以下命令:

 zenity --error --width 300 --text "权限被拒绝。无法写入文件。"

我们使用的新选项是:

  • –error :告诉zenity我们要使用错误对话框窗口。
  • –width设置窗口的初始宽度。

广告

错误对话框窗口以指定的宽度出现。 它使用标准的 GTK 错误图标。

zenity 错误对话框窗口。

要创建信息对话窗口,请使用以下命令:

 zenity --info --width 300 --text "更新完成。点击确定继续。"

我们使用的新选项是--info ,它告诉zenity创建一个信息对话窗口。

zenity 信息对话窗口。

要创建问题对话窗口,请使用以下命令:

 zenity --question --width 300 --text "你乐意继续吗?"; 回声$?

我们使用的新选项是--question ,它告诉zenity创建一个问题对话窗口。

$? 是一个特殊的参数。 它保存最近执行的前台管道的返回值。 一般而言,这是来自最近关闭的流程的值。 零值表示“OK”,一个或多个值表示“取消”。

广告

这是一种通用技术,您可以将其应用于任何zenity对话窗口。 通过在您的脚本中检查该值,您可以确定从对话窗口返回的数据是否应该被处理或忽略。

zenity 问题对话框。

我们单击“是”,因此返回代码为零,表示“确定”。

要创建警告对话框窗口,请使用以下命令:

 zenity --warning --title "硬盘空间不足" --width 300 --text "可能没有足够的硬盘空间来保存备份。"

我们使用的新选项是--warning ,它告诉zenity创建一个警告对话框窗口。

出现警告对话框窗口。 这不是一个问题,所以它只有一个按钮。

zenity 警告对话框窗口。

进度对话框窗口

您可以使用zenity进度对话框窗口来显示一个进度条,指示您的脚本距离完成有多近。

广告

进度条根据从您的脚本中输入的值进行推进。 为了演示原理,请使用以下命令:

 (for i in $(seq 0 10 100); do echo $i; sleep 1; done) 

该命令分解如下:

  • seq命令以 10 为步长遍历从 0 到 100 的序列。
  • 在每一步,值都存储在变量i中。 这将打印到终端窗口。
  • 由于sleep 1命令,该命令暂停一秒钟。

我们可以将它与zenity进度对话框窗口一起使用来演示进度条。 请注意,我们将上一个命令的输出通过管道传输到zenity:

 (for i in $(seq 0 10 100); do echo $i; sleep 1; done) | zenity --progress --title "How-To Geek" -- 自动关闭

我们使用的新选项是:

  • –progress :告诉zenity我们要使用进度对话框窗口。
  • –auto-close当进度条达到 100% 时关闭对话框。

出现进度对话框窗口,进度条向 100% 前进,在每一步之间暂停一秒钟。

zenity 进度对话框。

我们可以使用管道值到zenity的概念来在脚本中包含进度对话框窗口。

在编辑器中输入此文本并将其保存为“progress.sh”。

 !/bin/bash

功能工作清单(){

echo "# 第一个工作项" 
回声“25”
睡觉 1

echo "# 第二个工作项" 
回声“50”
睡觉 1

echo "# 第三个工作项" 
回声“75”
睡觉 1

echo "# 最后一个工作项" 
回声“100”
睡觉 1

}

工作清单 | zenity --progress --title "How-To Geek" --auto-close

出口 0

以下是脚本的细分:

  • 该脚本定义了一个名为work-list的函数。 这是您放置命令和指令以执行实际工作的地方。 将每个sleep 1命令替换为您的真实命令。
  • zenity接受echo "# ..."行并在进度对话框窗口中显示它们。 更改这些行的文本,以便它们将信息性消息传递给用户。
  • 包含数字的echo显行,例如echo "25" ,也被zenity接受并设置进度条的值。
  • 工作列表函数被调用并通过管道传输到zenity

使用此命令使脚本可执行:

 chmod +x 进度.sh 

使用此命令运行脚本:

 ./progress.sh 

脚本运行,并且文本消息随着脚本的每个阶段的执行而变化。 进度条逐步向 100% 移动。

zenity 进度条对话框窗口。

比例对话框窗口

比例对话框窗口允许用户移动滑块来选择数值。 这意味着她不能输入太高或太低的值。

我们使用的新选项是:

  • –scale 告诉zenity我们要使用比例对话框窗口。
  • –min-value设置刻度的最小值。
  • –max-value设置刻度的最大值。
  • –step设置使用箭头键时滑块移动的量。 如果有人使用鼠标,这不会影响滑块的移动。
  • –value设置滑块的初始值和位置。

这是我们正在使用的命令:

 Response=$(zenity --scale --title "How-To Geek" --text "选择放大倍率。" --min-value=0 --max-value=30 --step=3 --value15); 回声$响应

广告

滑块对话窗口出现,滑块设置为 15。

zenity 比例对话框窗口。

用户可以移动滑块来选择一个新值。

带有用户选择的 zenity 比例对话框

当她单击“确定”时,该值将传输到变量Response并打印到终端窗口。

条目对话窗口

输入对话窗口允许某人输入文本。

我们使用的新选项是:

  • –entry :告诉zenity我们要使用一个条目对话窗口。
  • –entry-text如果您想在文本输入字段中输入建议值,可以使用它。 我们使用“”来强制一个空字段。 这不是严格要求的,但我们想记录该选项。

完整的命令如下所示:

 Response=$(zenity --entry --text "输入你的搜索词" --title "Howe-To Geek" --entry-text=""); 回声$响应

将出现一个简单的对话窗口,其中包含一个文本输入字段。

zenity 进入对话框窗口。

有人可以键入和编辑文本。

zenity 输入对话框窗口,在文本字段中输入文本。

当他单击“确定”时,他键入的值将分配给变量 Response。 我们使用 echo 在终端窗口中打印变量的值。

把它们放在一起

让我们将这些技术放在一起并创建一个功能性脚本。 该脚本将执行硬件信息扫描并在滚动文本窗口中将结果呈现给用户。 她可以选择长或短扫描类型。

广告

对于这个脚本,我们将使用三种类型的对话窗口,其中两种对我们来说是新的:

  • 第一个是列表对话窗口。 它允许某人做出选择。
  • 第二个是进度对话框窗口,让用户知道正在发生的事情,她应该等待。
  • 第三个是文本信息窗口,向用户显示结果。

在编辑器中输入此文本并将其保存为“hardware-info.sh”。

 #!/bin/bash

# 显示此计算机的硬件列表

临时文件=$(mktemp)

ListType=`zenity --width=400 --height=275 --list --radiolist \
     --title '硬件扫描' \
     --text '选择扫描类型:' \
     --列'选择'\
     --column '扫描类型' TRUE "Short" FALSE "Long"`

如果 [[ $? -eq 1]]; 然后

  # 他们按下了取消或关闭了对话窗口 
  zenity --error --title="扫描被拒绝" --width=200 \
       --text="跳过硬件扫描"
  1号出口
 
elif [ $ListType == "短" ]; 然后

  # 他们选择了短单选按钮 
  标志="--短"
 
别的

  # 他们选择了长单选按钮 
  标志="" 
菲

# 在 $Flag 中搜索具有适当值的硬件信息
hwinfo $标志 | 三通 >(zenity --width=200 --height=100 \
     --title="整理信息" --progress \
     --pulsate --text="正在检查硬件..." \
     --auto-kill --auto-close) >${TempFile}
 
# 在滚动窗口中显示硬件信息
zenity --width=800 --height=600 \
     --title "硬件详细信息" \
     --text-info --filename="${TempFile}"
 
出口 0

使用此命令使其可执行:

 chmod +x 硬件信息.sh 

“chmod +x haredware-info.sh in a”终端窗口。

此脚本创建一个临时文件,文件名保存在 TempFile 变量中:

 临时文件=$(mktemp)

该脚本使用--list选项创建一个称为列表对话窗口的zenity对话窗口。 行尾的“\”字符告诉脚本将它们视为一个环绕的长行。 这是过程:

  • 我们指定窗口的宽度和高度。
  • 列表对话框窗口支持列。 --radiolist选项使第一列成为单选按钮列。
  • 我们为窗口设置了标题和文本提示。
  • 我们将第一列的标题设置为“选择”。 此列的内容将是单选按钮。
  • 我们将第二列的标题设置为“选择”,并提供第二列的内容。 此列包含两个文本标签:“短”和“长”。 TRUE 和 FALSE 指示符表示对话框窗口出现时默认选择“Short”选项。
  • 我们将此对话窗口的结果存储在一个名为ListType的变量中。
 ListType=`zenity --width=400 --height=275 --list --radiolist \ 
     --title '硬件扫描' \ 
     --text '选择扫描类型:' \ 
     --列'选择'\ 
     --column '扫描类型' TRUE "Short" FALSE "Long"`

如果用户按下“取消”,我们不需要检查ListType,我们可以简单地退出。 如果他按下“OK”,我们需要确定他是否选择了“Short”或“Long”单选按钮:

  • 特殊参数$? 如果用户按下“确定”,则为零。 如果他按下“取消”或关闭窗口,则等于 1。
  • 如果它等于 1,则脚本显示错误信息对话框窗口并退出。 如果他按下“OK”,我们继续测试ListType变量中的值。
  • 如果ListType变量包含值“Short”,则脚本将名为Flag的变量设置为等于“–short”。
  • 如果ListType变量不包含值“Short”,则它必须包含值“Long”。 该脚本将一个名为Flag的变量设置为等于“”,这是一个空字符串。
  • 该脚本将在下一节中使用Flag变量。
 如果 [[ $? -eq 1]]; 然后 

  # 他们按下了取消或关闭了对话窗口 
  zenity --error --title="扫描被拒绝" --width=200 \ --text="硬件扫描被跳过" 
  1号出口 

elif [ $ListType == "短" ]; 然后 

 # 他们选择了短单选按钮 
 标志="--短" 

别的 

 # 他们选择了长单选按钮 
 标志="" 
菲
广告

现在脚本知道用户想要哪种类型的扫描,我们可以执行硬件信息扫描:

  • 该脚本调用hwinfo命令并将Flag变量中的值传递给它。
  • 如果Flag包含“–short”,则hwinfo命令执行短扫描。 如果Flag的值为“”,则不会向hwinfo传递任何内容,并且会执行默认的长扫描。
  • 该脚本将hwinfo的输出通过管道传输到teetee将输出发送到zenityTempFile
  • 该脚本创建一个进度条对话窗口。 它设置对话窗口的宽度和高度,以及标题和提示文本。
  • 该脚本无法预先知道hwinfo命令将产生多少信息,因此它无法将进度条正确设置为 100%。 --pulsate选项使进度对话框显示移动指示器。 这会通知用户正在发生某些事情,他应该等待。
  • 如果有人单击“取消”, --auto-kill选项将终止脚本。
  • --auto-close选项会导致进度对话框在其监控的进程完成时自动关闭。
 # 在 $Flag 中搜索具有适当值的硬件信息
hwinfo $标志 | 三通 >(zenity --width=200 --height=100 \
     --title="整理信息" --progress \
     --pulsate --text="正在检查硬件..." \
     --auto-kill --auto-close) >${TempFile}

hwinfo扫描完成时,脚本调用zenity来创建一个带有--text-info选项的文本信息对话窗口。 文本信息对话框窗口显示TempFile文件的内容:

  • 该脚本设置对话窗口的宽度和高度以及标题文本。
  • --flename选项用于读取保存在TempFIle变量中的文件的内容。
 # 在滚动窗口中显示硬件信息 
zenity --width=800 --height=600 \ 
     --title "硬件详细信息" \ 
     --text-info --filename="${TempFile}"

当用户关闭文本信息对话窗口时,脚本退出。

 出口 0

让我们把它烧起来看看。

 ./硬件信息.sh 

出现列表框。 默认选择“短”选项。

选择了“短”选项的列表对话框。

让我们选择“Long”,然后单击“OK”。

选择了“长”选项的列表对话框。

进度窗口出现,带有一个滑动指示器。 它会一直保留在屏幕上,直到硬件扫描完成。

带有滑动指示器的进度窗口。

硬件扫描完成后,将出现文本信息对话框窗口,其中包含扫描的详细信息。

文本信息对话窗口中的硬件扫描信息。

点击“确定”。

广告

即使是顽固的命令行专家也不得不承认,几个 GUI 对话框窗口可以给不起眼的 Bash 脚本带来专业的感觉。