程序员经常使用Bash命令语言创建Shell脚本来自动化手动任务。例如,他们会为各种配置、文件操作、生成构建结果和各种与DevOps相关的活动创建Bash脚本。几乎所有类Unix或基于Unix的操作系统都为用户提供预安装的Bash解释器,因此我们可以使用Bash编写更具可移植性的自动化脚本。
正如我们已经知道的那样,Bash脚本编写是指使用Bash命令语言的语法、内置Bash命令和核心操作系统CLI程序(如GNU核心工具)编写一系列命令。标准且老式的Bash脚本通常执行一些命令并在终端上显示纯文本输出。
然而,我们可以通过几个独特的概念使我们的Bash脚本更具未来性和用户友好性。以下概念通过一些鲜为人知的现代Bash脚本编写技术,使您的自动化脚本更加现代化。
显示动画以指示长时间运行的任务
在某些情况下,我们需要从Bash脚本中执行长时间运行的命令。有几种方法可以指示长时间运行的任务。最简单和最容易的方法是使用echo命令显示带有三个尾随点(也称为省略号)的消息。但是,这种方法产生的是一个静态消息,对用户和开发人员来说不是很交互式和友好。
我们可以使用核心Unix操作系统命令和Bash内置命令轻松显示ASCII动画。看下面这个只有两个动画帧的简单动画示例:
#!/bin/bash
# Linux迷 www.linuxmi.com
while true;
do
# Frame #1
printf "\r< Loading..."
sleep 0.5
# Frame #2
printf "\r> Loading..."
sleep 0.5
done
上面的Bash脚本在终端上显示一个无尽的两帧动画。printf语句使用\r转义字符来重置当前行的终端光标。上面的脚本呈现了以下基于文本的动画:
一个简单的两帧文本动画
我们可以在动画中添加更多帧,并使用以下Bash脚本在特定耗时任务完成之前一直显示动画。
#!/bin/bash
# Linux迷 www.linuxmi.com
sleep 5 &
pid=$!
frames="/ | \\ -"
while kill -0 $pid 2&>1 > /dev/null;
do
for frame in $frames;
do
printf "\r$frame Loading..."
sleep 0.5
done
done
printf "\n"
上面的脚本显示一个基于文本的旋转器动画,直到sleep 5命令完成执行。类似地,我们可以在任何耗时任务中显示旋转器动画,而不是用echo显示静态消息。预览如下。
一个带有旋转器文本动画的Bash脚本,作者的截图 这些基于文本的动画使命令行程序更加用户友好和互动,因此大多数现代命令行程序都显示这些ASCII动画。现在,你知道如何通过改变帧字符列表来使你的Bash脚本也具有动画效果了。
从Bash显示本地GUI通知
Bash脚本和命令行程序通常为经常使用终端界面的开发人员提供工具。例如,Flutter框架为开发人员提供了flutter命令行程序,用于管理Flutter应用程序和配置Flutter应用程序开发环境。假设你正在开发一个耗时的命令行脚本。在用户不查看终端输出时,如何显示重要消息?
所有类Unix和基于Unix的操作系统都有特殊的命令来显示GUI通知。我们可以从Bash脚本中调用这些命令来显示本地通知。例如,你可以在基于GNU/Linux的操作系统上使用notify-send命令,如下所示。
#!/bin/bash
# Linux迷 www.linuxmi.com
sleep 10
notify-send "notify.sh" "Task #1 已成功完成 www.linuxmi.com"
一些GNU/Linux发行版通常会预装notify-send工具的版本。上面的Bash脚本在十秒后显示了一个本地通知。预览如下:
在Ubuntu上的本地通知截图
macOS用户可以通过在Bash中执行AppleScript解释器来显示本地通知,如下所示:
#!/bin/bash
sleep 10
osascript -e "display notification \"Task #1 www.linuxmi.com 已成功完成\" with title \"notify.sh\""
在Bash脚本中的多进程处理非常有助于通过长时间运行的脚本或永久运行的后台脚本向用户通知重要事件。
在Bash脚本中的多进程处理
通常,程序员使用Bash脚本按顺序运行命令。因此,Bash解释器会逐个执行每个语句,直到达到源文件的末尾或遇到exit语句。然而,我们可以改变这种顺序执行的方式,实现并行执行以加快自动化脚本的速度。
首先,我们可以将整个Bash脚本分解为几个独立的函数,可以异步运行每个函数。接下来,我们可以将所有Bash函数作为后台任务运行。最后,我们可以使用内置的wait命令来保持脚本执行过程处于活动状态,直到所有异步进程执行结束。
请看以下示例代码:
#!/bin/bash
# Linux迷 www.linuxmi.com
function task1() {
echo "Running task1..."
sleep 5
}
function task2() {
echo "Running task2..."
sleep 5
}
task1 &
task2 &
wait
echo "www.linuxmi.com 全部完成"
在这个例子中,我们将两个并行函数task1和task2作为后台任务运行。此外,我们使用内置的wait命令使脚本实例保持活动状态,直到后台任务完成执行。如果你检查脚本的执行时间,你会发现这两个函数在大约五秒钟内结束,而不是十秒钟。
使用Bash显示GUI组件
前面我们讨论了如何通过长时间运行的Bash脚本显示GUI通知。类似地,我们可以显示其他GUI组件,如消息框、输入框和文件选择对话框。有时我们需要为非技术人员创建基于GUI的自动化程序。如果你已经了解Bash脚本编写,你不需要使用其他GUI开发工具来创建简单的GUI应用程序——因为我们可以使用Bash显示GUI元素。
zenity程序提供了几个命令,用于在GNU/Linux命令行环境中显示各种GUI元素。例如,我们可以使用以下命令打开文件选择对话框。
zenity --file-selection
大多数基于GNOME的GNU/Linux操作系统发行版都预装了Zenity版本。此外,作为替代,你可以在基于KDE的GNU/Linux发行版中使用kdialog命令。
macOS用户可以像往常一样调用AppleScript解释器。例如,他们可以使用以下命令通过Bash脚本显示文件选择对话框。
osascript -e "POSIX path of (choose file)"
你也可以像Zenity那样构建自己的二进制文件,并从Bash脚本中显示任何GUI组件。此外,你还可以使用Neutralinojs通过Bash脚本在本地/远程窗口中显示交互式的HTML界面。
使用文本样式现代化终端输出
我们经常使用echo命令输出脚本中的消息。默认情况下,echo命令根据默认终端文本样式打印给定的文本。但是,在某些情况下,我们可以通过使用基本的用户体验原则根据当前上下文改进文本样式。例如,我们可以使用红色显示错误消息。此外,您可以使用粗体字体样式强调段落中的一些关键细节。
tput是一个Unix程序,提供控制当前终端屏幕的命令。它提供了改变终端光标位置、获取终端信息和更改文本样式的命令。我们可以将tput命令与echo命令结合使用,在所有类Unix和基于Unix的操作系统上打印各种文本样式。
请看以下示例,打印不同的文本样式:
#!/bin/bash
# Linux迷 www.linuxmi.com
bold=$(tput bold)
underline=$(tput smul)
italic=$(tput sitm)
info=$(tput setaf 2)
error=$(tput setaf 160)
warn=$(tput setaf 214)
reset=$(tput sgr0)
echo "${info}INFO${reset}: This is an ${bold}info${reset} message"
echo "${error}ERROR${reset}: This is an ${underline}error${reset} message"
echo "${warn}WARN${reset}: This is a ${italic}warning${reset} message"
在这里,我们使用tput命令为每种文本样式定义了一些变量。最后,我们使用echo命令执行临时保存的命令,以显示不同的文本样式,如下所示。
Bash中的文本样式屏幕截图
您可以使用上述方法为Bash脚本构建自己的个性化颜色方案。上面的示例脚本使用空设备文件(/dev/null)来隐藏kill命令的错误消息。