欢迎光临
我们一直在努力

shell 创建文本菜单

创建文本菜单

核心是case命令,根据用户的选择来执行特定的命令。

创建菜单布局

使用echo命令打印字符,生成一个菜单,还可以包括标题等信息:

clear
echo
# -e 选项,打印特殊字符
echo -e "\t\t\tSys Admin Menu\n"
echo -e "\t1. Display disk space"
echo -e "\t2. Display logged on users"
echo -e "\t3. Display memory usage"
echo -e "\t0. Exit program\n\n"
# -en 会去掉末尾的换行符,光标会留在行尾
echo -en "\t\tEnter option: "
# 获取用户输入,只期望获取到单个字符,-n选择限制只读1个字符,并且用户不用回车
read -n 1 option

clear命令,先清空当前会话的内容。
echo -e选项,可以打印特殊字符。
echo -en选项,会去掉末尾的换行符。这让菜单看上去更专业,光标会一直行尾等待用户输入。

获取用户输入
打印出菜单后,就要等待并获取用户输入。这步使用read命令。这里期望只要单个字符,所以用 -n 选项限制只读取一个字符。这样用户只需要输入一个数字,并且不用按回车。

创建菜单函数
把上面的部分封装成一个函数,这样,在任何时候只要调用函数,就能重现菜单。

创建桩函数

桩函数(stub function),是一个空函数,或者只有一个echo语句,说明最终这里需要什么内容:

function diskspace {
    clear
    echo "Display disk space"
}

这样,就不需要事先写出所有函数。菜单能够直接投入使用,之后在来实现具体的操作。

添加菜单逻辑

菜单布局和函数都有了,下面需要创建程序逻辑将二者结合起来。这里就需要case命令。
case命令根据菜单中输入的字符来调用相应的函数。用默认的case命令字符星号来处理所有不正确的菜单项。
下面就是这个完整的菜单脚本的例子:

#!/bin/bash
# 为脚本创建文本菜单

# --------------------
# 定义函数
# --------------------

# 打印菜单
function menu {
    clear
    echo
    # -e 选项,打印特殊字符
    echo -e "\t\t\tSys Admin Menu\n"
    echo -e "\t1. Display disk space"
    echo -e "\t2. Display logged on users"
    echo -e "\t3. Display memory usage"
    echo -e "\t0. Exit program\n\n"
    # -en 会去掉末尾的换行符,光标会留在行尾
    echo -en "\t\tEnter option: "
    # 获取用户输入,只期望获取到单个字符,-n选择限制只读1个字符,并且用户不用回车
    read -n 1 option
}

function diskspace {
    clear
    df -k
}

function whoseon {
    clear
    who
}

function menusage {
    clear
    cat /proc/meminfo
}

# --------------------
# 函数主体
# --------------------
while [ 1 ]
do
    # 菜单逻辑
    menu
    case $option in
    0)
        break ;;
    1)
        diskspace ;;
    2)
        whoseon ;;
    3)
        menusage ;;
    *)
        clear
        echo "Wrong selection";;
    esac
    echo -en "\n\n\t\tHit any key to continue"
    read -n 1 line
done
clear

菜单的显示效果如下:


                        Sys Admin Menu

        1. Display disk space
        2. Display logged on users
        3. Display memory usage
        0. Exit program

                Enter option: 

使用 select 命令

创建文本菜单的过程中,花了一半的精力在建立菜单布局和获取用户输入上。bash shell 提供了一个很容易上手的小工具,可以帮助自动完成这些工作。

select命令只需要一条命令就可以创建出菜单,然后获取输入并自动处理。命令格式如下:

select 选项变量 in "选项1" "选项2" "选项3"
do
    命令
done

select命令会将每个选项自动加上编号,然后为选项显示一个由PS3环境变量定义的特殊提示符。所以还要定义PS3环境变量。

示例代码

这里是一个select命令的示例:

#!/bin/bash
# 为脚本创建文本菜单

function diskspace {
    clear
    df -k
}

function whoseon {
    clear
    who
}

function menusage {
    clear
    cat /proc/meminfo
}

PS3="Enter option: "
select option in "Display disk space" "Display logged on users" \
"Display memory usage" "Exit program"
do
    case $option in
    "Exit program")
        break ;;
    "Display disk space")
        diskspace ;;
    "Display logged on users")
        whoseon ;;
    "Display memory usage")
        menusage ;;
    *)
        clear
        echo "Wrong selection";;
    esac
done

菜单效果如下:

$ menu2.sh 
1) Display disk space       3) Display memory usage
2) Display logged on users  4) Exit program
Enter option: 

使用这个工具可以快速的创建一个简易的菜单,不过视觉效果就差很多。

制作窗口(dialog包)

dialog包能够用ANSI转义控制字符在文本环境中创建标准的窗口对话框。

窗口部件

dialog包提供了很多窗口部件(widget),使用的时候命令格式如下:

dialog --widget parameters

常用的部件如下:

  1. msgbox部件:在窗口中显示一条简单的消息,会有一个OK按钮
  2. yesno部件:允许用户对窗口中显示的问题选择yes或no,会有两个按钮
  3. inputbox部件:提供一个简单的文本框区域来输入文本
  4. textbox部件:可以在窗口中显示大量信息,会生成一个滚动窗口
  5. menu部件:创建文本菜单,需要为每个选项提供一个选择标号和显示文本
  6. fselect部件:可以用来浏览文件和文件夹

更多窗口部件,后面会详细列出。

获取部件的输出

每个dialog部件都提供了两种形式的输出:

  • 使用退出状态码
  • 使用STDERR

返回选项
如果选择了YES或OK,返回退出状态码0。如果选择了Cancel或No,返回退出状态码1。可以用标准的$?变量来判断具体选择了哪个按钮。

返回数据
如果是返回数据,则会将数据发送到STDERR。可以用标准的bash shell方法来将STDERR输出重定向到另一个文件或文件描述符中:

dialog --inputbox "Enter your age: " 10 20 2>age.txt

具体怎么用可以参考下面的示例。

示例代码

内容比较多,感觉也不一定需要制作这么好的窗口来交换。编写脚本时记住两件事:

  • 如果有按钮,检查dialog命令的退出状态码
  • 否则就重定向STDERR来获取输出的值

前面的例子使用dialog包实现的示例代码:

#!/bin/bash
# 为脚本创建文本窗口菜单

temp=$(mktemp -t test.XXXXXX)
temp2=$(mktemp -t test2.XXXXXX)

function diskspace {
    df -k > $temp
    dialog --textbox $temp 20 60
}

function whoseon {
    who > $temp
    dialog --textbox $temp 20 50
}

function menusage {
    cat /proc/meminfo > $temp
    dialog --textbox $temp 20 50
}

while [ 1 ]
do
dialog --menu "Sys Admin Menu" 20 30 10 \
1 "Display disk space" \
2 "Display logged on users" \
3 "Display memory usage" \
0 "Exit program" 2> $temp2
if [ $? -eq 1 ]
then
    break
fi

selection=$(cat $temp2)
case $selection in
0)
    break ;;
1)
    diskspace ;;
2)
    whoseon ;;
3)
    menusage ;;
*)
    dialog --msgbox "Wrong selection" 10 30
esac
done
rm -f $temp 2> /dev/null
rm -f $temp2 2> /dev/null

这里用到了临时文件,并且使用mktemp命令来创建临时文件,看着挺专业。

安装dialog包

另外系统可能默认没有安装dialog包,要运行这个脚本,需要先安装dialog包:

[root@Ansible ~]# yum info dialog
已加载插件:fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
已安装的软件包
名称    :dialog
架构    :x86_64
版本    :1.2
发布    :5.20130523.el7
大小    :505 k
源    :installed
来自源:base
简介    : A utility for creating TTY dialog boxes
网址    :http://invisible-island.net/dialog/dialog.html
协议    : LGPLv2
描述    : Dialog is a utility that allows you to show dialog boxes (containing
         : questions or messages) in TTY (text mode) interfaces.  Dialog is called
         : from within a shell script.  The following dialog boxes are implemented:
         : yes/no, menu, input, message, text, info, checklist, radiolist, and
         : gauge.
         : 
         : Install dialog if you would like to create TTY dialog boxes.

dialog部件详表

dialog部件

部件 描述
calendar 提供选择日期的日历
checklist 显示多个选项(其中每个选项都能打开或关闭)
form 构建一个带有标签及文本字段(可以填内容)的表单
fselect 提供一个文件选择窗口来浏览选择文件
gauge 显示完成的百分比进度条
infobox 显示一条消息,但不用等待回应
inputbox 提供一个输入文本用的文本表单
inputmenu 提供一个可编辑的菜单
menu 显示可选择的一系列选项
msgbox 显示一条消息,并要求用户选择OK按钮
pause 显示一个进度条来显示暂停期间的状态
passwordbox 显示一个文本框,但会隐藏输入的文本
passwordform x牧场一个带标签和隐藏文本字段的表单
radiolist 提供一组菜单选项,单只能选择其中一个。就是单选
tailbox 用tail命令在滚动窗口中显示文件的内容
tailboxbg 更tailbox一样,但是在后台模式中运行
textbox 在滚动窗口中显示文件的内容
timebox 提供一个选择小时、分钟和秒的窗口
yesno 提供一条带有Yes和No按钮的简单消息

dialog选项

除了标准部件,还可以在dialog命令中定制不同的选项。这些选项可以让你全面定制窗口外观和操作。

dialog命令选项

选项 描述
–add-widget 继续下个对话框,直到按下Esc或Cancel按钮
–aspect ratio 指定窗口宽度和高度的宽高比
–backtitle title 指定显示在屏幕顶部背景上的标题
–begin x y 指定窗口左上角的起始位置
–clear 用默认的对话背景色来清空屏幕内容
–colors 在对话文本中嵌入ANSI色彩编码
–cr-wrap 在对话文本中允许使用换行符并强制换行
–create-rc file 将示例配置文件的内容复制到指定的file文件中
–default-item string 设定复选列表、表单或菜单对话中的默认项
–help 显示dialog命令的帮助信息
–help-status 当选定Help按钮后,在帮助信息后写入多选列表、单选列表或表单信息
–ignore 忽略dialog不能识别的选项
–input-fd fd 指定STDIN之外的另一个文件描述符
–insecure 在password部件中键入内容时显示星号
–item-help 为多选列表、单选列表或菜单中的每个标号在屏幕底部添加一个帮助栏
–keep-window 不要清除屏幕上显示过的部件
–max-input size 指定输入的最大字符串长度。默认为2048
–no-collapse 不要将对话文本中的制表符转换成空格
–no-kill 将tailbox对话框放到后台,并禁止该进程的SIGHUP信号
–no-shadow 不要显示对话窗口的阴影效果
–output-fd fd 指定除STDERR之外的另一个输出文件描述符
–print-maxsize 将对话窗口的最大尺寸打印到输出中
–print-size 将对话窗口的大小尺寸打印到输出中
–print-version 将dialog版本号打印到输出中
–separate-output 一次一行地输出checklist部件的结果,不使用引号
–separator string 指定用于分隔部件输出的字符串
–separate-widget string 指定用于分隔部件输出的字符串
–shadow 在每个窗口的右下角绘制阴影
–single-quoted 需要时对多选列表的输出采用单引号
–sleep sec 在处理完对话窗口之后延迟指定的秒数
–stderr 将输出发送到STDERR(默认行为)
–stdout 将输出发送到STDOUT
–tab-correct 将制表符转换成空格
–tab-len n 指定一个制表符占用的空格数(默认为8)
–timeout sec 指定无用户输入时,sec秒后退出并返回错误代码
–titel title 指定对话窗口的标题
–trim 从对话文本中删除前导空格和换行符
–visit-items 修改对话窗口中制表符的停留位置,使其包括选项列表

dialog命令选项2
按钮的选项功能都差不多,单独列出在这里。可以重写对话窗口中的任意按钮标签:

选项 描述
–cancel-label label 指定Cancel按钮的替代标签
–defaultno 将yes/no对话框的默认答案设为No
–exit-label label 指定Exit按钮的替代标签
–extra-button 在OK按钮和Cancel按钮之间显示一个额外按钮
–extra-label label 指定额外按钮的替代标签
–help-button 在OK按钮和Cancel按钮后显示一个Help按钮
–help-label label 指定Help按钮的替代标签
–nocancel 隐藏Cancel按钮
–no-lable label 为No按钮指定替代标签
–ok-label label 指定OK按钮的替代标签
–yes-label label 为Yes按钮指定替代标签

举例说明

  • –title选项,允许你设置出现在窗口顶部的部件标题。
  • –backtitle选项,是为脚本中的菜单创建公共标题的简便办法。
  • –create-rc选项,dialog命令支持运行时配置。该命令会根据配置文件模板创建一份配置文件。

创建本地临时文件(mktemp)

在需要临时将内容保存到文件的时候,有个特殊命令可以用来创建临时文件。mktemp命令可以在/tmp目录中创建一个唯一的临时文件。shell会创建这个文件,但不用默认的umask值。它会将当前用户设置为文件的属主,并且只有属主有读写权限。

创建文件

默认情况下,mktemp会在当前目录中创建一个文件。使用命令的时候,需要指定一个文件名模板。模板可以包含任意文本文件名,在文件名末尾加上6个X(几个X都没关系,书上建议6位):

$ mktemp test1.XXXXXX
test1.Acrugq
$ ls -al test1*
-rw-------. 1 steed steed 0 12月 12 14:26 test1.Acrugq
$ 

mktemp命令会用6位字符码替换这6个X,从而保证文件名在目录中是唯一的。

在脚本中使用

在脚本中使用mktemp命令时,需要将文件名保存到变量中,这样就能在后面的脚本中引用了:

$ mktemp test2.XXXXXX
test2.leOFBZ
$ mktemp test2.XXXXXX
test2.5kDbKn
$ mktemp test2.XXXXXX
test2.domeOC
$ mktemp test2.XXXXXX
test2.CJX702
$ tempfile=$(mktemp test2.XXXXXX)
$ exec 3>>$tempfile
$ echo "test2 Line1" >&3
$ echo "TEST2 LINE2" >&3
$ exec 3>&-
$ cat $tempfile
test2 Line1
TEST2 LINE2
$ ls -al test2*
-rw-------. 1 steed steed  0 12月 12 14:41 test2.5kDbKn
-rw-------. 1 steed steed  0 12月 12 14:41 test2.CJX702
-rw-------. 1 steed steed  0 12月 12 14:41 test2.domeOC
-rw-------. 1 steed steed  0 12月 12 14:41 test2.leOFBZ
-rw-------. 1 steed steed 24 12月 12 14:41 test2.tMVTwN
$ rm -f $tempfile 2> /dev/null
$ ls -al test2*
-rw-------. 1 steed steed 0 12月 12 14:41 test2.5kDbKn
-rw-------. 1 steed steed 0 12月 12 14:41 test2.CJX702
-rw-------. 1 steed steed 0 12月 12 14:41 test2.domeOC
-rw-------. 1 steed steed 0 12月 12 14:41 test2.leOFBZ
$ 

这里先创建了几个临时文件,干扰一下。使用的时候,创建了文件描述符3来使用,使用完之后关闭了文件描述符。最后精确的把用完的临时文件给删除了。

在/tmp目录创建临时文件

-t选项会强制mktemp命令在系统的临时目录创建文件。此时返回的就是创建的文件的全路径:

$ mktemp -t test3.XXXXXX
/tmp/test3.aPIXIy
$ 

创建临时目录

-d选项则是创建一个临时目录。如果要在/tmp目录下创建临时目录,就是-dt:

$ mktemp -d dir.XXXXXX
dir.aBDmsd
$ mktemp -dt dir.XXXXXX
/tmp/dir.pqW927
$ 
赞(0)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。