简介: 命令行不适合于每一位用户。事实上,一些用户可能仅在握着鼠标时才感到舒服。要仅使用 shell 来满足这些用户或构建桌面应用程序,可以向您的脚本添加一些 GUI。这里是一些具体做法。
如果您走进一个拥挤的机房,可能会听到有关 “shebangs”、斜线、点、根、管道、端口等等这个那个的闲聊。如果讲到 UNIX®,您无疑会理解本地术语 — 有关 UNIX 的缩略词、命令名、快捷键、选项、文件名和方言 — 且有宾至如归的感觉。与其他艺术工作者一样,UINX 用户拥有广泛的术语来描述其工作细节。
并非每个人都探讨 UNIX;事实上,有些人可能发现命令行很复杂,令人却步。此外,您可能不希望将全部命令行寄托给临时或无经验的用户。要帮助那些不习惯使用命令行的人,或构建围绕 shell 的自定义解决方案,您可以为您的脚本构建 GUI。有了这样的工具 — dialog 和 Zenity 是两个值得一提的工具(参见 参考资料) — 您就可以使用对话框、文件浏览器和其他常见的 “windowing” 控件和技术来与您的用户交互。事实上,对话框提供更多自然对话:您提出问题,请求响应,并相应地予以响应。
本期的 “对话 UNIX” 探讨 dialog 和 Zenity,并展示如何将任何脚本转化成一个令人信服的 GUI 应用程序。对于传统的、基于文本的界面使用 dialog,Zenity 提供现代风格的视窗化桌面。
向任何 shell 脚本添加对话框
一个命令行实用程序通常提供足够的选项来完全控制每个调用。一些 DOS 命令可能启用或禁用一个特性,而其他 DOS 命令可能处理参数,比如名称列表。在命令行,您将(几乎)所有信息呈现在前面,然后执行任务。图形应用程序很不同。选择是通过菜单、复选框和文件浏览器做出的。一个图形应用程序接受一点信息,处理它,然后通常要求获得更多信息。据说 GUI 应用程序是事件驱动的。
dialog 实用程序跨越两个世界。当您需要来自用户的输入时调用该实用程序,然后返回到您的脚本继续处理提供的任何数据。换言之,如果您写一个脚本来使用 dialog,就有可能忽略命令行参数,而是使用 dialog 在必要时发出提示信息。
如果您的系统缺少 dialog 实用程序,您可以轻松使用当前版本自带的包管理器来安装它,或者您可以直接通过源代码编译它。例如,如果您的系统使用 Aptitude,您可以通过如下命令安装 dialog:
- sudoapt-getinstalldialog
否则就要通过源代码编译,可以下载维护人员 Thomas Dickey 的 Web 站点上的代码(参见 参考资料)并运行典型的三个命令:./configure && make && make install:
- $wgethttp:
- $tarxzfdialog.tar.gz
- $cddialog-1.1-20100428
- $./configure
- $make
- $sudomakeinstall
安装完成之后,您的路径中应当会有一个名为 dialog 的新实用程序。输入 man dialog 来查看捆绑文档。
dialog 使用起来很简单:它仅是另一个 UNIX 命令。您使用命令选项显示您选择的对话框,然后捕获结果并基于该值执行一些逻辑。dialog 的一些变体直接将命令结果放在特殊的 shell 状态变量 $? 中,您应当在 dialog 命令退出后立即保存或询问该变量(因为随后的一个命令会立即改变其值)。另外,通常更为复杂的 dialog 命令变体同时设置 shell 状态变量并生成其他结果。为将事情简单化,dialog 提供 --stdout 选项来将其结果发出到标准输出,因而便于通过命令求值捕获数据(带左引号的命令和赋值语句的组合)。
例如,dialog --yesno 命令是最简单的变体之一。它提出一个问题,提示做出是或否的响应,并返回 $? 中的 0 或 1,具体取决于用户选择了 “Yes” 还是 “No”。您可以测试 $? 的值并执行一些条件代码。这里是您可以添加到 shell 脚本的一个工作代码段:
- dialog--yesno"Doyouwanttocontinue?"00
- rc=$?
-
if["${rc}"=="0"];then
- echoYes
-
else
- echoNo
- fi
--yesno 选项需要至少三个参数:问题文本以及对话框本身的高度和宽度,后者用行和列度量。如果您不需要特定尺寸,总是可以为高度或宽度使用 0,以自动调整对话框大小。(还有相对于窗口左下角放置窗口的选项。)图 1 展示运行中的 --yesno。
图 1. --yesno 操作
dialog 选项 --calendar 呈现一个日历来允许用户选择特定日期。如果用户选择一个日期,然后单击 OK,命令返回 0。但是,如果用户单击 Cancel,命令返回 1。此外,如果用户单击 OK,命令将选定日期发出为标准输出。这里是使用命令求值产生日期的一个例子:
- RESULT=`dialog--stdout--title"CALENDAR"
- --calendar"Pleasechooseadate..."00912010`
- retval=$?
--title 选项使用下一个参数来将一个标题添加到对话框,且可用于任何 dialog 命令。非常像 --yesno,您提供一些文本来提示用户。接下来,选项 0 0 再次指定自动高度和宽度,选项 9 1 2010 分别指示日历中显示的初始日、月和年。选项卡和箭头键改变日历并选择一个日期。对话框退出后,如果 retval 是 0,RESULT 的值就是选定的日期。图 2 显示日历对话框。
图 2. 日历对话框
dialog 命令提供通常在图形应用程序中找到的大部分控件:
--infobox 仅仅展示信息:它不要求任何输入。信息框仍然只是简单地在屏幕上。要延长其显示,在它和下一个命令之前置入一个 sleep 命令。
--input 收集单一输入响应。您可能会使用该命令来收集您的用户的姓名或邮政编码。
--textbox 显示一个文本文件的内容。如果文件超出对话框的垂直高度,一个控件支持简单的向上和向下滚动。
--menu 和 --radiolist 提供一个选择列表,供用户进行选择。两种对话框在功能上是等同的,但是略有不同的视觉风格,以更好地模拟一个 GUI 可能展示的东西。特别地,--radiolist 命令呈现 ( ) 来模拟单选按钮。
--checklist 显示用户可单独启用或禁用的一个项目列表。
每个 dialog 变体的输出不同,或是一个单一值,或是一列由空格分隔的带引号值。例如,--checklist 是用于选择一个或多个选项的一个不错的控件,它发出一列带引号值,其中每个值与一个启用的选项相关。下面演示了一个操作示例:
- RESULT=`dialog--stdout
- --checklist"Enabletheaccountoptionsyouwant:"10403/
- 1"Homedirectory"on/
- 2"Signaturefile"off/
- 3"Simplepassword"off`
行 1、2 和 3 结尾的反斜杠(/)是延续标记;从 RESULT 到 off` 的一切内容是一个命令。如果用户启用了 Home directory 和 Simple password,$RESULT 将会是 "1" "3"。--checklist 的参数是高度和宽度,任何时间内的列表元数量(如果有些项目被挡住,您可以通过滚动查看这些项目),以及清单选项(其中每个选项是一个值)、一个描述、在最初启用或禁用该选项。
您可以随时输入 dialog --help 来查看常规列表,输入 dialog 来查看特定选项。dialog 有无数用法。
有像素?使用 Zenity。
Zenity 是 UNIX 桌面,如同 dialog 是简单的终端窗口。您可以使用 Zenity 从任何 shell 脚本打开 GTK+ 对话框。事实上,Zenity 与 dialog 有着许多相同的功能;惟一的区别在于,Zenity 在一个 X Window System 环境中工作。Zenity 与 GNOME 相捆绑。如果您不运行 GNOME,可以单独安装 Zenity(但是,也要安装大量 GTK+ 库)。您还可以从 GNOME 项目页面下载 Zenity 的源代码(参见 参考资料 获取链接)。
下面是一个简单的例子。命令为:
- zenity--question--text"Doyouwanttocontinue?"
生成的结果如 图 3 所示。(用于演示的机器在运行 Ubuntu 10。)如果您单击 OK,命令返回 0。否则,它返回 1。
图 3. 一个简单问题
如同 dialog,Zenity 有很多选项 — 甚至比 dialog 还多 — 但是选项命名贴切,因而不言自明。您可能发现 Zenity 比 dialog 更有优势,特别是由于大部分计算机用户都有某种 X 桌面。
Zenity 提供与 dialog 相同的许多控件。这里是收集名称的一个代码段:
- ENTRY=`zenity--entry--text"Pleaseenteryourname"
- --entry-text"Yourname"--title"Enteryourname"
-
if[$?==0];then
- zenity--info--text"Hello$ENTRY/!"
- fi
再次说明,如果 zenity 的退出代码是 0,那么 ENTRY 有某人的姓名。这里是为使用 Zenity 而重写后的日历示例:
- DATE=`zenity--calendar--day"9"--month"1"--year"2010"--format"%Y-%m-%d"
-
if[$?==0];then
- echo$DATE
- fi
尽管 Zenity 更详细一点 — 例如,对于年、月、日有单独的选项 — 其他 DOS 命令使您免于记住精确的参数使用顺序。Zenity 的日历还允许您指定输出格式,即使用标准 strftime() 代码。该命令的结果类似于 2010-1-9,它表示 2010 年 1 月 9 日。
Zenity 还提供一个过程表来展示一个操作的状态。它从标准输入逐行读取数据。如果一个行的前缀是井号(#),文本被更新为该行文本。如果一个行仅包含一个数字,百分比被更新为该数字。清单 1 展示 Zenity 文档中的一个示例。
清单 1. Zenity 过程表
-
#!/bin/sh
- (
- echo"10";sleep1
- echo"#Updatingmaillogs";sleep1
- echo"20";sleep1
- echo"#Resettingcronjobs";sleep1
- echo"50";sleep1
- echo"Thislinewilljustbeignored";sleep1
- echo"75";sleep1
- echo"#Rebootingsystem";sleep1
- echo"100";sleep1
- )|
- zenity--progress/
- --title="UpdateSystemLogs"/
- --text="Scanningmaillogs..."/
- --percentage=0
-
-
if["$?"=-1];then
- zenity--error/
- --text="Updatecanceled."
- fi
sub-shell(包含在括号中)执行一系列任务 — 在这个人为例子中 albeit sleep 延迟 — 且通过一个管道将输出发出到一个 Zenity 过程表。在每一步之前,sub-shell 发出一个数字来推进过程表,每个 --percentage 0 起始于 0,然后发出一个以 # 开头的字符串来改变状态消息。因此,过程表沿着步骤标记脚本工作。如果 Zenity 的退出代码是 -1,单击的是 Cancel 按钮。
再次说明,要使用 dialog 或 Zenity,用对话框替换您之前引用过命令行参数的代码。用一个小创意,您可以将您的 shell 脚本转化为一等桌面公民。
其他高级工具
有些时候,您可能发现您的需求超过了 shell 脚本以及 dialog 和 Zenity 工具的功能范围之外。在那些实例中,您可能转向 C/C++ 并为桌面构建本机应用程序,但是您还可以使用高级脚本语言和许多强大的 GUI 框架的语言绑定。
一个组合是 Ruby 脚本语言和 wxWidgets 框架的 Ruby 绑定。Ruby 是面向对象的、富于表现力的且简洁的,运行于大部分操作系统之上。wxWidgets 框架还可用于每个主流平台,包括 Mac OS X、Windows®、Linux® 和 UNIX。由于两者都是可移植的,您可以用 Ruby 编写一个应用程序一次,然后随处运行它。另一个更简单的选择是 Shoes。尽管不如 wxWidgets 丰富,Shoes 学习和使用起来相当简单。清单 2 使用 70 行代码实现了一个计算器。
清单 2. 用 Shoes 实现的一个计算器
-
classCalc
- definitialize
- @number=0
- @previous=nil
- @op=nil
- end
-
- defto_s
- @number.to_s
- end
-
- (0..9).eachdo|n|
- define_method"press_#{n}"do
- @number=@number.to_i*10+n
- end
- end
-
- defpress_clear
- @number=0
- end
-
- {'add'=>'+','sub'=>'-','times'=>'*','div'=>'/'}.eachdo|meth,op|
- define_method"press_#{meth}"do
-
if@op
- press_equals
- end
- @op=op
- @previous,@number=@number,nil
- end
- end
-
- defpress_equals
- @number=@previous.send(@op,@number.to_i)
- @op=nil
- end
- end
-
- number_field=nil
- number=Calc.new
- Shoes.app:height=>250,:width=>200,:resizable=>falsedo
- background"#EEC".."#996",:curve=>5,:margin=>2
-
- stack:margin=>2do
-
- stack:margin=>8do
- number_field=parastrong(number)
- end
-
- flow:width=>218,:margin=>4do
- %w(789/456*123-0Clr=+).eachdo|btn|
- buttonbtn,:width=>46,:height=>46do
- method=casebtn
- when/[0-9]/;'press_'+btn
- when'Clr';'press_clear'
- when'=';'press_equals'
- when'+';'press_add'
- when'-';'press_sub'
- when'*';'press_times'
- when'/';'press_div'
- end
-
- number.send(method)
- number_field.replacestrong(number)
- end
- end
- end
- end
- end
对 Ruby 和 Shoes 的介绍不在本文讨论范围之内,但是这里是一些最重要的构造:
大多数 Ruby 类 Calc 使用 Ruby 的元编程功能,在运行时为所有数字键和数学操作键定义功能。
代码开头 Shoes.app... 创建计算器的 GUI,为其呈现布局和按钮。Shoes 提供两个容器来装配布局:stack 和 flow。一个 stack 是元素的一个垂直堆栈,其中每个元素直接放在前一个元素下面。一个 flow 尽量紧密地包裹元素,直至它达到其边框局限,然后包装其余的元素。(您可以将一个堆栈看作是一个 HTML <div>,将一个流看作 HTML <p>。)您可以使用 Ruby 块创建一个堆栈或一个流。
最里面的 flow 快循环创建应用程序中的所有按钮,并有效地将每个按钮绑定到其方法。(case 语句返回一个方法名称;number.send(method) 行调用实例化计算器上的那个方法。)
number_field.replace strong(number) 行通过最新计算结果更新计算器显示。发出 number 致使类调用其自己的 to_s (“to string”) 方法。
其他脚本语言拥有类似的库,且 Ruby 本身有更多选择,包括 Ruby Cocoa,可使用 Ruby 在 Mac OS X 上开发 Cocoa 应用程序。选择您喜欢的开源脚本语言,找到一个轻量级 GUI 工具包,然后开始编码。
您不需要讨厌的编译器!
如果您已经掌握了 shell 脚本编写,将您的工作与 dialog 或 Zenity 结合起来,以增加互操作性。如果您需要的编程功能比 shell 提供的更多,考虑 Ruby 或 Python 这样的语言以及任何窗口工具包。您无需一个编译器来编写良好的桌面应用程序。
关于作者
Martin Streicher 是一位 Ruby on Rails 的自由开发人员和 Linux Magazine 的前任主编。Martin 毕业于 Purdue University 并获得计算机科学学位,从 1986 年起他一直从事 UNIX 类系统的编程工作。他喜欢收集艺术品和玩具。
相关推荐
Platypus是一个开发人员工具,可以从命令行脚本(例如Shell脚本或Python,Perl,Ruby,Tcl,JavaScript和PHP程序)创建本机Mac应用程序。这是通过将脚本与运行脚本的应用二进制文件包装在macOS 应用程序捆绑包中来...
编译和运行Objective-C程序: ...Objective-C主要用于构建图形用户界面应用程序,而不是用于编写简单的命令行脚本。如果你只是想编写命令行脚本,使用Shell脚本、Python或其他脚本语言可能更为合适。
2.8.3 应用程序的说明 2.9 小结 第3章 文件操作8 3.1 Linux文件结构8 3. 1.1 目录9 3. 1.2 文件和设备9 3.2 系统调用和设备驱动程序 80 3.3 库函数 81 3.4 底层文件访问 82 ...
2.8.3 应用程序的说明 2.9 小结 第3章 文件操作8 3.1 Linux文件结构8 3. 1.1 目录9 3. 1.2 文件和设备9 3.2 系统调用和设备驱动程序 80 3.3 库函数 81 3.4 底层文件访问 82 3.4.1 ...
2.8.3 应用程序的说明 2.9 小结 第3章 文件操作8 3.1 Linux文件结构8 3. 1.1 目录9 3. 1.2 文件和设备9 3.2 系统调用和设备驱动程序 80 3.3 库函数 81 3.4 底层文件访问 82 ...
因此,我们为 iPad 和 iPhone 7 应用程序创建了我们自己的 SVG 应用程序图标模板。 它包括新的黄金比例网格。 为了便于导出,我们编写了一个小脚本来快速呈现各种应用程序图标。 您可以在此处下载 SVG 模板和脚本。...
13.6.2 高级主题:使用fifo的客户/服务器应用程序 464 13.7 cd数据库应用程序 468 13.7.1 目标 469 13.7.2 实现 469 13.7.3 客户接口函数 472 13.7.4 服务器接口server.c 478 13.7.5 管道 481 13.7.6 对cd...
13.6.2 高级主题:使用fifo的客户/服务器应用程序 464 13.7 cd数据库应用程序 468 13.7.1 目标 469 13.7.2 实现 469 13.7.3 客户接口函数 472 13.7.4 服务器接口server.c 478 13.7.5 管道 481 13.7.6 对cd...
这是因为Tcl/Tk的shell程序wish提供了对其他程序、文件系统和网络套接字的存取功能,同时还能够创建图形用户界面。不管怎样,现在发现包含几千行Tcl脚本的应用程序并不稀奇。 我编写这本书的原因就是,虽然自己...
通过《Python在Unix和Linux系统管理中的应用(影印版)》及其辅助虚拟机,你将学习如何打包并部署Python应用程序和库文件,以及如何编写在多个Unix和Linux平台下都运行良好的代码。 通过这《Python在Unix和Linux系统...
深入java虚拟机光盘资源 rdiez 的工具 这个存储库包含我多年来编写的一些工具。...在启动图形应用程序时很有用,这些应用程序不应在不方便的时候打印到您的 shell 会话随机警告,并且在关闭控制台窗口后应保持运行
实验1.3 Shell脚本编程实验10 .第2章 嵌入式Linux系统基础12 2.1 构建嵌入式Linux系统环境12 2.1.1 交叉编译12 2.1.2 交叉编译器12 2.1.3 NFS13 实验2.1 嵌入式Linux开发环境的建立14 2.2 Linux C程序设计17...
实验1.3 Shell脚本编程实验10 .第2章 嵌入式Linux系统基础12 2.1 构建嵌入式Linux系统环境12 2.1.1 交叉编译12 2.1.2 交叉编译器12 2.1.3 NFS13 实验2.1 嵌入式Linux开发环境的建立14 2.2 Linux C程序设计17...
实验1.3 Shell脚本编程实验10 .第2章 嵌入式Linux系统基础12 2.1 构建嵌入式Linux系统环境12 2.1.1 交叉编译12 2.1.2 交叉编译器12 2.1.3 NFS13 实验2.1 嵌入式Linux开发环境的建立14 2.2 Linux C...
实验1.3 Shell脚本编程实验10 .第2章 嵌入式Linux系统基础12 2.1 构建嵌入式Linux系统环境12 2.1.1 交叉编译12 2.1.2 交叉编译器12 2.1.3 NFS13 实验2.1 嵌入式Linux开发环境的建立14 2.2 Linux C程序设计17...
6.1.2 控制台应用程序与图形用户界面应用程序 151 6.1.3 动态链接库、模块 151 6.1.4 线程、纤程与作业 152 6.1.5 权限与优先级 153 6.2 进程管理 153 6.2.1 创建进程、获取进程相关信息、获取启动参数 ...
PDF套件 只需单击一下,您可能想要对PDF进行的所有操作! 合并和分割PDF 将PDF转换为图像并将图像转换为PDF 小册子拼版,裁剪和修剪PDF ... 大多数脚本设计用于Apple的Automator应用程序的“运行Shell脚本”操作中,
6.1.2 控制台应用程序与图形用户界面应用程序 151 6.1.3 动态链接库、模块 151 6.1.4 线程、纤程与作业 152 6.1.5 权限与优先级 153 6.2 进程管理 153 6.2.1 创建进程、获取进程相关信息、获取启动参数 ...