如何在Linux Shell脚本中添加GUI
我们可以在Bash脚本中使用GUI窗口,滑块,单选按钮,进度条等。了解如何使用zenity
工具包,并使Bash脚本焕然一新。我们将向我们展示如何。
Bash脚本是一种功能强大的编程语言,由于它内置在Bash Shell中,因此每个人都可以使用。这是一种易于编程的语言。由于它是经过解释的,因此我们无需编译脚本。编辑脚本文件并使其可执行后,即可运行它。这使得编码,运行和调试周期非常有效。
人们对Bash脚本有两个主要的抱怨,第一个是速度。由于Bash shell会解释脚本中的命令,因此它们的执行速度不如编译后的代码快。但是,这就像在抱怨拖拉机不如汽车快。它们意味着不同的东西。
但是,速度有两种。与使用诸如C之类的编译语言开发解决方案相比,我们通常可以将快速脚本组合在一起并使用它来执行任务要快得多。
人们对Bash脚本的第二个抱怨是用户界面,它是终端窗口。当然,有时界面并不重要。如果唯一会使用脚本的人是脚本的作者,那么界面可能并不那么重要,对于执行后台和批处理类型的脚本也不重要。通常,此类脚本不需要太多(如果有)的用户交互。
在某些情况下,我们确实需要比终端窗口更直观,更现代的功能。大多数人都熟悉图形用户界面(GUI)。为了给人们带来尽可能流畅的体验,我们必须从脚本中创建和使用GUI元素。
zenity应用
zenity允许我们在Bash脚本中合并各种图形界面元素。它是一个功能强大的工具包,可为脚本带来现代感和现代感,熟悉的外观。
zenity已预装在Ubuntu,Fedora和Manjaro发行版上。它是GNOME的一部分。如果使用KDE,尽管zenity
可以在任何桌面环境上运行,但我们可能想签出kdialog
。
本文中的示例向我们展示如何从命令行创建不同的对话框窗口,如何在变量中捕获它们的返回值和用户选择以及如何在脚本中使用对话框窗口。
我们以一个小型应用程序结束,该应用程序使用了所有三种类型的对话框窗口。
日历对话框窗口
日历对话框窗口允许某人选择日期。用zenity
创建一个需要两个单词的单个命令:
zenity --calendar
出现日历对话框窗口。它具有我们希望标准日期选择器提供的所有功能。我们可以更改月份和年份,然后单击一天以选择该日期。默认情况下,当窗口出现时,今天的日期会突出显示。
单击"确定"关闭对话框窗口,然后选择突出显示的日期。双击日期会做同样的事情。
如果不想选择日期,请单击"取消",按键盘上的Esc键,或者关闭对话框窗口。
在上面的示例中,选择了2019年8月19日。如果用户单击"确定",日历将关闭,并且所选日期将显示在终端窗口中。
我们可以忽略没有临时父级的GTKDialog映射行。不鼓励这样做。
GTK代表GIMP Tool Kit,这是用于开发GNOME界面的工具包。它最初是由GNU图像处理程序(GIMP)的作者设计的。 GNU代表GNU的Not Unix。
GTK引擎警告" zenity"的作者,他们以非标准的方式使用了GTK组件。
捕获日期值
在终端上打印日期对我们没有多大帮助。如果要从其中一个脚本中调用此日历,则需要捕获所选的日期值,以便可以在脚本中使用它进行一些有用的操作。我们还将稍微自定义日历。
我们将在日历中使用以下选项。它们都必须与双破折号一起使用:
text:指定要在日历中显示的文本字符串。它代替了默认值,从下面选择一个日期。
title:设置日历对话框窗口的标题。
日:设置日历打开时所选的日期。
month:设置日历打开时选择的月份。
year:设置日历打开时选择的年份。
我们正在使用名为ChosenDate
的变量来捕获日历返回的日期。我们正在使用echo $ ChosenDate
将日期打印到终端窗口。
是的,我们在上一个示例中获得了相同的结果,但是在这里,我们将所选日期存储在变量中。在前面的示例中,它已被打印并遗忘了。
ChosenDate=$(zenity -- calendar --text "Choose a date" --title "iGiftIdea Rota" --day 1 -- month 9 --year 2019); echo $ChosenDate
现在,日历显示我们的提示和窗口标题。该日期设置为我们选择的开始日期,而不是今天的日期。
我们还可以自定义选择后返回的日期字符串的格式。 --date-format
选项后必须跟随格式说明符。这是一串令牌,用于定义将包含在输出中的数据和格式。令牌与strftime()
C语言函数中使用的令牌相同,并且有很多选择。
我们使用的令牌是:
%A:星期几的全名。
%d:月份中的数字。
%m:以数字表示的月份。
%y:两位数字的年份(无世纪)。
ChosenDate=$(zenity -- calendar --text "Choose a date" --title "iGiftIdea Rota" --date-format="%A %d/%m/%y" --day 1 -- month 9 --year 2019); echo $ChosenDate
有人选择一个日期:
并使用我们的格式返回日期。它显示星期几的名称,然后按照欧洲顺序显示日期:日,月,年。
"文件选择"对话框窗口:选择文件
文件选择对话框窗口非常复杂。人们可以浏览文件系统,突出显示一个或者多个文件,然后单击"确定"以选择那些文件或者完全取消选择。
zenity提供所有这些功能,以及更多。它和日历对话框窗口一样容易使用。
我们将使用的新选项是:
文件选择:告诉" zenity"我们要使用文件选择对话框窗口。
多个:允许某人选择多个文件。
文件过滤器:告诉文件对话框窗口要显示的文件类型。
zenity --file-selection --tile "iGiftIdea" --multiple --file-filter='*.mm *.png *.page *.sh *.txt'
文件选择对话框窗口与任何其他文件选择窗口一样功能。
用户可以浏览文件系统并选择自己选择的文件。
我们已经浏览到新目录,然后选择了一个名为button_hybrid.png的文件。
单击确定时,文件选择对话框窗口关闭,文件名和路径在终端窗口中打印。
如果需要在进一步处理中使用文件名,则可以将其捕获到变量中,就像处理日历中的日期一样。
"文件选择"对话框窗口:保存文件
如果添加一个选项,则可以将文件选择对话框窗口变成文件保存对话框窗口。选项是--save
。我们还将使用--confirm-overwrite选项。这会提示该人确认他要覆盖现有文件。
Response=$(zenity --file-selection --save --confirm-overwrite); echo $Response
出现文件保存对话框窗口。请注意,存在一个文本字段,用户可以其中输入文件名。
用户可以浏览到文件系统中自己选择的位置,为文件提供名称,或者单击现有文件以覆盖它。
在上面的示例中,用户突出显示了一个现有文件。
当他单击"确定"时,将出现一个确认对话框窗口,要求他确认要替换现有文件。注意,文件名出现在警告对话框中。这就是对细节的关注,使" zenity"具有专业外观。
如果我们不使用--confirm-overwrite
选项,该文件将被静默覆盖。
文件名存储在变量" Response"中,该变量显示在终端窗口中。
通知对话框窗口
使用" zenity",可以轻松地在脚本中包含通知对话框。我们可以调用一些库存对话框窗口来为用户提供信息,警告,错误消息和问题。
要创建错误消息对话框窗口,请使用以下命令:
zenity --error --width 300 --text "Permission denied. Cannot write to the file."
我们正在使用的新选项是:
错误:告诉" zenity"我们要使用一个错误对话框窗口。
width:设置窗口的初始宽度。
错误对话框窗口以指定的宽度出现。它使用标准的GTK错误图标。
要创建信息对话框窗口,请使用以下命令:
zenity --info --width 300 --text "Update complete. Click OK to continue."
我们使用的新选项是--info,它告诉Zenity创建一个信息对话框窗口。
要创建问题对话框窗口,请使用以下命令:
zenity --question --width 300 --text "Are you happy to proceed?"; echo $?
我们正在使用的新选项是--question,它告诉Zenity创建一个问题对话框窗口。
$是一个特殊参数。它保存了最近执行的前台管道的返回值。一般而言,这是来自最近关闭的过程的价值。零值表示"确定",而一个或者多个值表示"取消"。
这是一种通用技术,我们可以将其应用于任何" zenity"对话框窗口。通过检查脚本中的该值,可以确定是否应该处理或者忽略从对话框窗口返回的数据。
我们单击是,因此返回代码为零,表示确定。
要创建警告对话框窗口,请使用以下命令:
zenity --warning --title "Low Hard Drive Space" --width 300 --text "There Jan not be enough hard drive space to save the backup."
我们正在使用的新选项是--warning,它告诉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 "iGiftIdea" -- auto-close
我们正在使用的新选项是:
progress:告诉" zenity"我们要使用进度对话框窗口。
自动关闭:进度条达到100%时,关闭对话框。
出现进度对话框窗口,进度条向100%前进,在每个步骤之间暂停一秒钟。
我们可以使用将值传递到" zenity"中的概念在脚本中包含进度对话框窗口。
在编辑器中输入此文本,然后将其另存为progress.sh。
!/bin/bash function work-list () { echo "# First work item" echo "25" sleep 1 echo "# Second work item" echo "50" sleep 1 echo "# Third work item" echo "75" sleep 1 echo "# Last work item" echo "100" sleep 1 } work-list | zenity --progress --title "iGiftIdea" --auto-close exit 0
这是脚本的细分:
该脚本定义了一个名为"工作列表"的函数。在这里放置命令和说明以执行实际工作。用实际的命令替换每个" sleep 1"命令。
zenity接受echo"#..."行并将其显示在进度对话框窗口中。更改这些行的文本,以便它们将信息传递给用户。
包含数字的" echo"行(例如" echo" 25"")也被" zenity"接受并设置进度条的值。
工作列表函数被调用并通过管道传递给" zenity"。
使用以下命令使脚本可执行:
chmod +x progress.sh
使用此命令运行脚本:
./progress.sh
脚本将运行,并且文本消息会在脚本的每个阶段执行时发生变化。进度栏逐步向100%移动。
比例对话框窗口
比例对话框窗口允许某人移动滑块以选择数字值。这意味着她不能输入太高或者太低的值。
我们正在使用的新选项是:
比例尺:告诉" zenity"我们要使用比例尺对话窗口。
最小值:设置刻度的最小值。
max-value:设置比例尺的最大值。
步骤:设置使用箭头键时滑块的移动量。如果有人使用鼠标,这不会影响滑块的移动。
值:设置滑块的初始值和位置。
这是我们正在使用的命令:
Response=$(zenity --scale --title "iGiftIdea" --text "Select magnification." --min-value=0 --max-value=30 --step=3 --value15); echo $Response
出现滑块对话框窗口,并将滑块设置为15.
用户可以移动滑块以选择新值。
当她单击"确定"时,该值将传输到变量"响应"并打印到终端窗口。
输入对话框窗口
输入对话框窗口允许某人输入文本。
我们正在使用的新选项是:
entry:告诉" zenity"我们要使用一个输入对话框窗口。
entry-text:如果要在文本输入字段中输入建议值,则可以使用此选项。我们用来强制一个空字段。这不是严格要求,但我们想记录该选项。
完整的命令如下所示:
Response=$(zenity --entry --text "Enter your search term" --title "Howe-To data" --entry-text=""); echo $Response
出现一个简单的对话框窗口,其中包含一个文本输入字段。
有人可以键入和编辑文本。
当他单击"确定"时,他键入的值将分配给变量Response。我们使用echo在终端窗口中打印变量的值。
放在一起
让我们将这些技术放在一起,创建一个功能脚本。该脚本将执行硬件信息扫描,并在滚动文本窗口中将结果呈现给用户。她可以选择长扫描或者短扫描类型。
对于此脚本,我们将使用三种类型的对话框窗口,其中两种对我们来说是新的:
第一个是列表对话框窗口。它允许某人做出选择。
第二个是进度对话框窗口,让用户知道正在发生什么,她应该等待。
第三个是文本信息窗口,该窗口将结果显示给用户。
在编辑器中输入此文本,然后将其另存为hardware-info.sh。
#!/bin/bash # Display hardware listing for this computer TempFile=$(mktemp) ListType=`zenity --width=400 --height=275 --list --radiolist \ --title 'Hardware Scan' \ --text 'Select the scan type:' \ --column 'Select' \ --column 'Scan Type' TRUE "Short" FALSE "Long"` if [[ $? -eq 1 ]]; then # they pressed Cancel or closed the dialog window zenity --error --title="Scan Declined" --width=200 \ --text="Hardware scan skipped" exit 1 elif [ $ListType == "Short" ]; then # they selected the short radio button Flag="--short" else # they selected the long radio button Flag="" fi # search for hardware info with the appropriate value in $Flag hwinfo $Flag | tee >(zenity --width=200 --height=100 \ --title="Collating Information" --progress \ --pulsate --text="Checking hardware..." \ --auto-kill --auto-close) >${TempFile} # Display the hardware info in a scrolling window zenity --width=800 --height=600 \ --title "Hardware Details" \ --text-info --filename="${TempFile}" exit 0
使用此命令使其可执行:
chmod +x hardware-info.sh
此脚本创建一个临时文件,文件名保存在TempFile变量中:
TempFile=$(mktemp)
该脚本使用--list选项来创建一个名为Zenity的对话窗口,称为列表对话窗口。行尾的\字符告诉脚本将它们视为一条环绕的长行。过程如下:
我们为窗口指定宽度和高度。
列表对话框窗口支持列。 --radiolist选项使第一列成为单选按钮的列。
我们为窗口设置标题和文本提示。
我们将第一列的标题设置为"选择"。该列的内容将是单选按钮。
我们将第二列的标题设置为"选择",并提供第二列的内容。此列包含两个文本标签:短和长。 TRUE和FALSE指示符表示在出现对话框窗口时默认选择Short选项。
我们将来自此对话框窗口的结果存储在名为" ListType"的变量中。
ListType=`zenity --width=400 --height=275 --list --radiolist \ --title 'Hardware Scan' \ --text 'Select the scan type:' \ --column 'Select' \ --column 'Scan Type' TRUE "Short" FALSE "Long"`
如果用户按"取消",则无需检查" ListType"中的值,只需退出即可。如果他按下OK,我们需要找出他是否选择了Short或者Long单选按钮:
如果用户按"确定",则特殊参数" $"等于零。如果他按"取消"或者关闭窗口,则等于1.
如果等于1,脚本将显示一个错误信息对话框窗口并退出,如果他按OK,我们继续测试ListType变量中的值。
如果
ListType
变量的值是Short,则脚本会将名为Flag
的变量设置为等于short。如果
ListType
变量不包含值Short,则它必须包含值Long。脚本将名为" Flag"的变量设置为equal,这是一个空字符串。该脚本在下一节中使用
Flag
变量。
if [[ $? -eq 1 ]]; then # they pressed Cancel or closed the dialog window zenity --error --title="Scan Declined" --width=200 \ --text="Hardware scan skipped" exit 1 elif [ $ListType == "Short" ]; then # they selected the short radio button Flag="--short" else # they selected the long radio button Flag="" fi
既然脚本知道了用户想要的扫描类型,我们就可以执行硬件信息扫描:
该脚本调用" hwinfo"命令,并将其值传递给" Flag"变量。
如果
Flag
包含short,则hwinfo
命令执行简短扫描。如果Flag
的值是,则没有任何信息传递给hwinfo
,并且默认执行长时间扫描。该脚本将来自" hwinfo"的输出通过管道传递给" tee"。 tee将输出发送到zenity和TempFile中。
该脚本将创建一个进度条对话框窗口。它设置对话框窗口的宽度和高度,以及标题和提示文本。
该脚本无法预先知道" hwinfo"命令将产生多少信息,因此无法将进度条设置为正确地前进到100%。 " --pulsate"选项使进度对话框显示一个移动指示器。这通知用户发生了什么事,他应该等待。
如果有人单击"取消",则--auto-kill选项将终止脚本。
" --auto-close"选项使进度对话框在其监视的过程完成时自动关闭。
# search for hardware info with the appropriate value in $Flag hwinfo $Flag | tee >(zenity --width=200 --height=100 \ --title="Collating Information" --progress \ --pulsate --text="Checking hardware..." \ --auto-kill --auto-close) >${TempFile}
当" hwinfo"扫描完成时,脚本调用" zenity"以创建带有" --text-info"选项的文本信息对话框窗口。文本信息对话框窗口显示TempFile
文件的内容:
该脚本设置对话框窗口的宽度和高度以及标题文本。
--flename选项用于读取保存在TempFle变量中的文件的内容。
# Display the hardware info in a scrolling window zenity --width=800 --height=600 \ --title "Hardware Details" \ --text-info --filename="${TempFile}"
当用户关闭文本信息对话框窗口时,脚本退出。
exit 0
让我们来看看。
./hardware-info.sh
出现列表框。默认情况下,短选项被选中。
让我们选择Long,然后单击OK。
出现进度窗口,带有一个滑动指示器。它会保留在屏幕上,直到完成硬件扫描为止。
硬件扫描完成后,将显示文本信息对话框窗口,其中包含扫描的详细信息。
单击确定。