用于 Shell 脚本的终端函数

“Shell Curses”是一个脚本函数库,这些函数为 Shell 程序员提供了将基于文本的光标移动到屏幕上指定位置的能力。这种能力允许使用 Shell 脚本创建菜单和数据输入系统,而不需要已编译的库。这些函数非常类似于“C”语言的“Curses”库。

0 评论:

Dana French, 总裁, Mt Xia Inc.

2008 年 6 月 12 日

  • 内容

在 IBM Bluemix 云平台上开发并部署您的下一个应用。

开始您的试用

引言

Shell Curses 创建于 1993 年,目的是为了解决需要一组不必针对每种新平台进行重新编译的可移植光标操作函数这一特定问题。这些函数最初采用 Bourne Shell 编写,后来迁移到了 Korn Shell 93,尽管当前的函数集在 Bash 中同样工作得非常好。自从 1993 年以来,Shell Curses 已被下载了两百多万次,并且目前全世界的组织正在各种各样的应用程序中使用它。作为 Shell Curses 的创作者,我可以告诉您当前版本是免费可用的,无需许可证即可用于任何目的。

回页首

函数

在 15 年前编写这一组函数时,大多数 UNIX® 系统管理员同时也是 C 语言程序员,非常熟悉名为 Curses 的 C 语言函数库,该函数库提供了光标操作和文本窗口函数。今天,由于图形界面的普及,许多 UNIX 系统管理员不再那么熟悉光标操作和文本窗口。尽管仍然存在对这些函数的需要,但知识库却似乎正在缩小。本文的目的是提高读者对 Shell Curses 函数库的持续需要和存在性的意识。

C 语言 Curses 与 Shell Curses 函数库之间的区别在于,C 语言库是已编译的二进制,并且必须编译并链接到其他已编译的程序中。Shell Curses 函数库是许多 Curses 函数的纯粹 Shell 脚本实现,并且不需要编译。Korn Shell 93 版本的 Shell Curses 使用的唯一 UNIX 实用工具是“tput”。有关 tput 的更多信息,请参阅参考资料,本文将不对其进行讨论。Shell Curses 函数与已编译的 Curses 函数具有相同的名称和参数结构,因此熟悉 Curses 的程序员也熟悉如何使用 Shell Curses,虽然 Bourne 或 Korn Shell 脚本语法将与 C 语言有所不同。

Shell Curses 库

Shell Curses 库由以下函数组成(按逻辑使用顺序排列):

表 1:标准 Shell Curses 函数
函数 参数 描述
initscr   初始化 Shell Curses 屏幕寻址系统
endwin   取消初始化 Curses 屏幕寻址系统
refresh

[BufferName] 将屏幕中的逻辑缓冲区清空。

如果为此函数指定了参数字符串,则会将环境变量 BufferName 中存储的光标命令回显到屏幕上。

clear   清屏。
move ${RowNbr }
${ColNbr}
将逻辑光标移动到指定的行和列。需要行和列编号参数。
mvcur

${RowNbr}
> ${ColNbr}
将物理光标移动到指定的行和列。需要行和列编号参数。
addch X 在屏幕上的当前位置打印字符。需要单个字符参数。
addstr ${String} 在屏幕上的当前位置打印 String 的值。
mvaddch ${RowNbr}
> ${ColNbr} X
将逻辑光标移动到指定的行和列。在屏幕上指定的行和列打印指定的字符。需要行和列编号参数。
mvaddstr ${RowNbr}
${ColNbr}
${String}
将逻辑光标移动到指定的行和列。在屏幕上指定的行和列打印 String 的值。需要行和列编号参数,还需要一个 String 参数。
clrtoeol   清除当前行从当前列到行尾的内容。
clrtobot   清除从当前列到屏幕结尾的屏幕内容。
getch   从标准输入检索一个字符。
getstr   从标准输入检索一个字符串。
insch   在当前屏幕位置插入一个字符。
mvinsch ${RowNbr}
> ${ColNbr}
将逻辑光标移动到指定的行和列。在 RowNbr, ColNbr 插入一个字符

需要行和列编号参数。

insertln   在当前屏幕位置插入一行。
delch   删除位于当前屏幕位置的一个字符。
mvdelch ${RowNbr}
${ColNbr}
将逻辑光标移动到指定的行和列。删除位于当前位置的一个字符。需要行和列编号参数。
deleteln   删除位于当前行的行。
attroff   关闭所有屏幕属性。
attron   什么也不做。仅用于实现 Curses 兼容性。
attrset ${Attribute} 设置由 Attribute 的定义的屏幕属性。

需要一个属性字符串定义。

有效的属性如下:
rev reverse video
blink Blinking mode
bold Bold Video
dim Half Bright video
smul Start Underscore Mode
rmul End Underscore Mode
sgr0 Exit all Attributes

增强的 Shell Curses 功能

下列函数包括在 Shell Curses 函数库中,并提供了超越普通“Curses”函数以外的增强功能:

表 2:增强的 Shell Curses 函数
函数 参数 描述
savescr [BufferName] 将逻辑屏幕缓冲区保存到由 BufferName 定义的环境变量中。

需要一个屏幕名称字符串。

mvclrtoeol ${RowNbr}
${ColNbr}
将逻辑光标移动到指定的行和列。需要行和列编号参数。
clrtobol   清除行从当前列到行首的内容。
mvclrtobol ${RowNbr}
${ColNbr}
将逻辑光标移动到指定的行和列。清除行从当前列到行首的内容。需要行和列编号参数。
mvclrtobot ${RowNbr}
${ColNbr}
将逻辑光标移动到指定的行和列。清除从当前列到屏幕结尾的屏幕内容。需要行和列编号参数。
getwd   从标准输入检索一个单词。
beep   鸣叫显示铃声。
chkparm ${String} 确定“String”的值是否为 Null,如果是则返回 false,如果不是则返回 true。需要单个字母数字参数。
chkint ${Nbr} 确定“Nbr”的值是否为数字,如果是则返回 true,如果不是则返回 false。需要单个数字参数。
chklines ${Nbr} 确定“Nbr”的值是否小于或等于屏幕上的行数。如果是则返回 true,如果不是则返回 false。需要单个数字参数。
chkcols ${Nbr} 确定 Nbr 的值是否小于或等于屏幕上的行数。如果是则返回 true,如果不是则返回 false。需要单个数字参数。

回页首

示例

由于篇幅限制,本文没有提供这些函数的实际代码。有关下载信息,请参阅参考资料部分。

人们已使用 Shell Curses 创建了许多工具集,以便为安装系统、菜单程序、数据输入应用程序、数据库等等提供前端界面。下面将提供一些说明各个函数用法的示例。

在编写 Shell 脚本时,必须首先做出的决定之一为是否要使用某个函数库,或者是否要包括某个文件作为包含所有必需函数的“点”脚本。Shell Curses 可以通过任一种机制进行利用,具体使用哪一种机制将由 Shell 程序员做出决定。下面的示例将把 Shell Curses 的使用表示为函数库,因为对本讨论来说,这是最高效的机制。作为函数库,每个函数应该在某个目录中作为与函数具有相同名称的单独文件存在。在这些示例中,用于 Shell Curses 函数库的目录为 /usr/local/function/shellcurses。这些示例还使用 Korn Shell 93 作为脚本解释器,这是在每个脚本开头的 shebang 行进行定义的 (#!/usr/bin/ksh93)。

在 IBM® AIX® 下面使用 Shell Curses 函数库的一个问题在于,AIX 已经提供了名为 clear 和 refresh 的已编译库,这些库将与具有相同名称的 Shell 函数产生混淆。要解决此问题,应该将 clearrefresh 和 initscr 函数全都复制到单个文件中名为 initscr 的函数库中。这可以确保在调用 initscr 函数时,将同时初始化 clear 和 refresh 的 Shell Curses 函数,从而避免与 AIX 二进制命令 clear 和 refresh 产生混淆。

此示例使用 Shell Curses 函数来清屏;将光标移动到第 10 行,第 25 列;并在该位置打印单词 Hello World!。然后将光标移动到第 23 行,第 1 列。请注意对 refresh 函数的调用。这是实际将命令发送到屏幕以进行显示的函数。

   #!/usr/bin/ksh93FPATH="/usr/local/functions/shellcurses"initscrclearmove 10 25addstr "Example 1: Hello World!"move 23 1refreshendwinexit 0

下一个示例与前一个示例相同,只不过是使用单个 mvaddstr 函数,而不是使用两个函数,即使用 move 然后再使用 addstr

  #!/usr/bin/ksh93FPATH="/usr/local/functions/shellcurses"initscrclearmvaddstr 10 25 "Example 2: Hello World!"move 23 1refreshendwinexit 0

第三个示例提示用户输入一些数据,然后在屏幕下方的某个位置显示该数据。请注意,提示包含在一个 Shell 变量中,提示中的字符数量用于确定要在屏幕上放置光标的位置,以便用户输入数据。还要注意,refresh 函数在 getstr 函数之前调用,以便在提示用户输入数据之前,将命令刷新到屏幕:

    #!/usr/bin/ksh93FPATH="/usr/local/functions/shellcurses"initscrclearPROMPT="Example 3: Enter some data...:"LEN="${#PROMPT}"(( COL = LEN + 2 + 1 ))mvaddstr 10 2 "${PROMPT}"move 10 ${COL}refreshANS=$( getstr )mvaddstr 15 2 "Here is the data you entered.: ${ANS}"move 23 1refreshendwinexit 0

第四个示例提供一个完整的菜单系统,并具有标题和针对无效选择的错误检查。此示例还在做出选择并显示用户的选择之后重新绘制屏幕。

  #!/usr/bin/ksh93FPATH="/usr/local/functions/shellcurses"SCRWID="80"initscrclear#### Display a screen header, centered on the screenHEADER="Shell Curses Example 4"HDRWID="${#HEADER}"(( HDRBEGIN = ( SCRWID - HDRWID ) / 2 ))mvaddstr 1 ${HDRBEGIN} "${HEADER}"MENU[0]="First Menu Line"MENU[1]="Second Menu Line"MENU[2]="Third Menu Line"MENU[3]="Fourth Menu Line"MENU[4]="Fifth Menu Line"ITEMCNT="${#MENU[@]}"MENUWID="${#MENU[0]}"#### Determine the maximum length of the longest menu itemfor MENULINE in "${MENU[@]}"do(( ${#MENULINE} > MENUWID )) && (( MENUWID = ${#MENULINE} + 4 ))done#### Display the numbered menu item, centered on the screen(( COL = ( SCRWID - MENUWID ) / 2 ))NBR="0"for MENULINE in "${MENU[@]}"domvaddstr $(( ++NBR + 4 )) ${COL} "${NBR} = ${MENULINE}"done#### Prompt the user for a selectionmvaddstr 22 2 "Enter the number of your selection: "mvaddstr 23 2 "( 0 = Exit )"#### Read the users selection from the screenANSWER="99"while [[ "_${ANSWER}" != _[0-9] ]] ||(( ANSWER < 1 )) ||(( ANSWER > ITEMCNT ))do[[ "_${ANSWER}" == _0 ]] && exit 0mvclrtoeol 22 40refreshANSWER="$( getstr )"done#### Display the item number selected by the userclearmvaddstr 1 ${HDRBEGIN} "${HEADER}"mvaddstr 4 2 "You selected menu item number ${ANSWER}"move 23 1refreshendwinexit ${ANSWER}

第五个示例提供了一个带有错误检查功能的完整多行数据输入系统。此示例利用了动态确定的屏幕宽度和高度,它还使用了反转的视频屏幕属性来强调屏幕上显示的错误消息。

   #!/usr/bin/ksh93FPATH="/usr/local/functions/shellcurses"initscrSCRWID="${MAX_COLS}"SCRLEN="${MAX_LINES}"clear#### Display a two line header, centered on the screenHEADER1="Shell Curses Example 5"HEADER2="Data Entry Screen"mvaddstr 1 $(( ( SCRWID - ${#HEADER1} ) / 2 )) "${HEADER1}"mvaddstr 2 $(( ( SCRWID - ${#HEADER2} ) / 2 )) "${HEADER2}"#### Define the user entry promptsDOTS="........................................"PRMPT[1]="Enter an existing directory name"PRMPT[2]="Enter an existing regular file name"PRMPT[3]="Enter an alpha-numeric value"PRMPT[4]="Enter a numeric value"PRMPT[5]="Enter an executable file name"PCNT="${#PRMPT[@]}"#### Display the numbered data entry prompt with trailing dotsfor IDX in "${!PRMPT[@]}"do(( DOTWID = ( SCRWID / 2 ) - ( ${#PRMPT[IDX]} + 4 ) ))PRMPT[IDX]="${PRMPT[IDX]}${DOTS:0:${DOTWID}}"mvaddstr $(( IDX + 4 )) 2 "${IDX}: ${PRMPT[IDX]}...:"doneDATACOL="$(( ${#PRMPT[1]} + 10 ))"#### Prompt the user for a selectionmvaddstr $(( SCRLEN - 3 )) 2 "Select a line number to enter data:"#### Read the users data line number selection from the screenwhile :do#### Read the line number entered by the usermvclrtoeol $(( SCRLEN - 3 )) 40refreshANS="$( getstr )"#### clear the status line and re-display the default status messagemvclrtoeol $(( SCRLEN - 2 )) 2mvaddstr $(( SCRLEN - 2 )) 2 "( 0 = Exit )"#### Validate the user entered line number, if invalid go back and ask again[[ "_${ANS}" == "_0" ]] && exit 0if [[ "_${ANS}" != _+([[:digit:]]) ]] || (( ANS < 1 )) || (( ANS > PCNT ))thencontinuefi#### Read the line data from the user entrymvclrtoeol $(( ANS + 4 )) ${DATACOL}refreshDATA[${ANS}]="$( getstr )"mvclrtoeol $(( SCRLEN - 2 )) 2attrset rev#### Check the validity of the line 1 data as entered by the userif (( ANS == 1 )) && [[ ! -d "${DATA[${ANS}]}" ]]thenmvclrtoeol $(( ANS + 4 )) ${DATACOL}mvaddstr $(( SCRLEN - 2 )) 2 "ERROR: Invalid Directory Name"fi#### Check the validity of the line 2 data as entered by the userif (( ANS == 2 )) && [[ ! -f "${DATA[${ANS}]}" ]]thenmvclrtoeol $(( ANS + 4 )) ${DATACOL}mvaddstr $(( SCRLEN - 2 )) 2 "ERROR: Invalid Regular File Name"fi#### Check the validity of the line 3 data as entered by the userif (( ANS == 3 )) && [[ "_${DATA[${ANS}]}" != _+([[:alnum:]]) ]]thenmvclrtoeol $(( ANS + 4 )) ${DATACOL}mvaddstr $(( SCRLEN - 2 )) 2 "ERROR: Invalid Alpha-Numeric Value"fi#### Check the validity of the line 4 data as entered by the userif (( ANS == 4 )) && [[ "_${DATA[${ANS}]}" != _+([[:digit:]]) ]]thenmvclrtoeol $(( ANS + 4 )) ${DATACOL}mvaddstr $(( SCRLEN - 2 )) 2 "ERROR: Invalid Numeric Value"fi#### Check the validity of the line 5 data as entered by the userif (( ANS == 5 )) && [[ ! -x "${DATA[${ANS}]}" ]]thenmvclrtoeol $(( ANS + 4 )) ${DATACOL}mvaddstr $(( SCRLEN - 2 )) 2 "ERROR: File is not executable or does not exist"fiattroffrefreshdoneendwinexit ${ANS}

这些示例代表了 Shell Curses 函数库的应用和用法的一小部分。French Menus 下面存在一个基于 Shell Curses 的标准化菜单和数据输入系统。

该菜单系统为 Shell 程序员提供了创建多级菜单系统和多屏数据输入程序的能力,这些多级菜单系统和多屏数据输入程序可与广泛的程序和数据库连接。如果没有指定后端程序或数据库,则使用内置的数据库系统来存储用户指定的信息。为了演示这些功能,下面将提供一个演示程序。French Menus 也充分(如果不是全部的话)利用了 Shell Curses 库中的函数,并且是设计和实现其他应用程序时的理想参考工具。

回页首

结束语

本文的目的是强调对基于文本的应用程序的持续需要,以及提高人们对为此目的而创建的现有工具的意识。诸如 Shell Curses 和 French Menus 等函数库使得基于文本的应用程序的创建更加容易,并提供了据以衡量和评估 Shell 编程的标准。由于许多 UNIX 程序员知道 Shell Curses,或者至少知道 Curses,基于这些函数集编写自己的 Shell 程序将会使得这些程序可移植、可扩展和可维护。

Shell Curses 函数库相关推荐

  1. curses函数库_Shell Curses函数库

    Shell Curses成立于1993年,旨在解决需要一组可移植的游标操纵函数的特定问题,而不必为每个新平台都重新编译它们. 这些功能最初是用Bourne Shell编写的,此后已迁移到Korn Sh ...

  2. Linux下curses函数库的详细介绍

    Linux下curses函数库的详细介绍 curses库介绍 安装 curses库函数介绍 初始化和重置函数 管理屏幕的函数 输出到屏幕 从屏幕读取 清除屏幕 移动光标 字符属性 管理键盘的函数 键盘 ...

  3. 【C】【Linux】利用C curses函数库进行终端彩色显示

             以前,只有极少数的哑终端支持彩色显示功能,所以大多数早起的curses函数库都不支持色彩,现在,ncurses和其他大多数现代的curses实现版本都提供了对它的支持.但是遗憾的是, ...

  4. Linux中Shell脚本函数库的笔记

    Shell函数库的作用:函数库就是对一些十分常用的功能,独立出来,然后集中存放在一些独立的文件中,这些文件可以理解为函数库.函数库本质上也是函数,一般情况下函数库的函数建议使用下划线开头. 示例: c ...

  5. Shell脚本函数(函数传参、递归、创建库)

    Shell脚本函数 一.Shell函数 1.Shell函数定义 2.函数的返回值 return echo 二.函数传参 三.函数变量的作用范围 四.递归 1.阶乘 2.递归目录 五.创建库 一.She ...

  6. shell脚本(五)——函数的格式、传参、变量、递归、函数库

    shell脚本(五)--函数 一.shell函数定义 二.格式 1.格式一: 2.格式二: 三.函数返回值 四.函数传参 五.函数变量的作用范围 六.递归 1.阶乘 2.递归查目录 七.创建函数库 一 ...

  7. 高级shell脚本编程之函数库、信号与陷进、文件处理、数组、安全性

    高级shell脚本编程之函数库.信号与陷进.文件处理.数组.安全性 1.函数库 把所有需要用到的函数都放到一个文件中,然后每个脚本的开头包含这个文件.例如: #!/bin/sh scope(){ lo ...

  8. linux shell 函数库,bash shell 函数库

    bash shell 函数库ash由自由软件基金会,Inc.版权所有(C) 1989-2011. 语法 bash [options] [file] 描述 Bash是一种与sh兼容的命令语言解释器,它执 ...

  9. shell 函数 与 函数库

    目录 前言 一.shell 函数 1.1 Shell函数定义 1.2 函数返回值 1.3 函数参数传值 1.4 函数变量生命周期 1.5 函数中可以调用函数 二.函数之递归 2.1 阶乘 2.2 遍历 ...

最新文章

  1. 像DW的应用源格式那样格式化VS里面的代码
  2. MySQL事物的概念
  3. jetson nano poe_工业POE交换机工作流程及使用注意事项介绍
  4. WPF--ComboBox数据绑定
  5. .NET Core 3.1正式发布,还不赶快升级!
  6. 增量导出_[华为]一种实用的增量式深度CTR模型训练方法
  7. mysql 查看索引命中_请问下如何在Mysql中where与orderBy后在命中索引?
  8. 漫步最优化二十一——全局收敛
  9. devops什么意思_DevOps有什么意义?
  10. 浅析 路印协议--Loopring 及整体分析 Relay 源码
  11. delphi7 安装/卸载控件通用方法
  12. C++1.1 #include<iostream>
  13. [转] 关于浏览器假死的原因分析和代码优化
  14. python容易学ma_初学者学python 初学者学python好学吗
  15. 线程的同步和异步理解
  16. hdwiki 附件上传大小设置
  17. vs+cmake完美编译RTS游戏,类似魔兽争霸源码
  18. 2019互联网公司100强
  19. VIVADO+ZYNQ7000入门三,PS与PL的联合开发
  20. 创新突破,索爱S5耳机实现空间音频和动态头部跟踪

热门文章

  1. 一个具有20位地址和32位字长的存储器_详解西门子间接寻址之存储器间接寻址...
  2. tomcat 如何配置环境变量
  3. 解决librdkafka 报WARN:Protocol read buffer underflow
  4. 给项目添加spring的测试单元
  5. 慕课网 饿了么 vue2.0 项目
  6. HDU1013 POJ1519 Digital Roots
  7. Linux环境Eclipse + Tomcat + MySQL 构造J2EE方法开发环境
  8. 软件过程评估和软件能力评价的方法与步骤
  9. 动态规划与数学方程法解决楼层扔鸡蛋问题
  10. Eclipse启动时报错Java was started but returned exit code=13