Linux shell - menu
创建交互式 shell 脚本最常用的方法是使用菜单。各种菜单项有助于用户了解脚本能做什么以及不能做什么。
菜单式脚本通常会清空显示区域,然后显示可用的菜单项列表。用户可以按下与每个菜单项关联的字母或数字来选择相应的选项。
shell 脚本菜单的核心是 case 命令。case 命令会根据用户在菜单上的选择来执行相应的命令。
创建菜单布局
创建菜单的第一步显然是确定在菜单上显示的元素以及想要显示的布局方式。
clear 命令使用终端会话的终端设置信息来清除屏幕上的文本。运行 clear 命令之后,可以用 echo 命令来显示菜单。
在默认情况下,echo 命令只显示可打印文本字符。在创建菜单项时,非可打印字符(比如制表符和换行符)往往也能派上用场。要在 echo 命令中包含这些字符,必须加入-e 选项:
echo -e "1.\tDisplay disk space"
会生成如下输出行:
# 1. Display disk space
这极大地方便了菜单项布局的格式化。只用几个 echo 命令,就能创建一个看上去还不错的菜单:
clear
echo
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 menu\n\n"
echo -en "\t\tEnter option: "
最后一行的-en 选项会去掉结尾的换行符。这让菜单看上去更专业一些,因为光标会一直在行尾等待用户的输入。
创建菜单的最后一步是获取用户输入。这要用到 read 命令(参见第 14 章)。因为我们期望的是单字符输入,所以会在 read 命令中使用-n 选项来限制只读取一个字符。这样用户只需要输入一个数字,而不用按 Enter 键:
read -n 1 option
接下来,需要创建菜单函数。
创建菜单函数
shell 脚本菜单项作为一组独立的函数实现起来更为容易。这样你就能创建出简洁、准确且容易理解的 case 命令了。
为此,你要为每个菜单项创建单独的 shell 函数。创建 shell 菜单脚本的第一步是确定脚本要实现的功能,然后将这些功能以函数的形式放在代码中。
通常我们会为还没有实现的函数创建一个桩函数(stub function)。桩函数既可以是一个空函数,也可以只包含一个 echo 语句,用于说明最终这里需要什么内容:
function diskspace {
clear
echo "This is where the diskspace commands will go"
}
这个桩函数允许在实现某个函数的同时,菜单仍能正常操作。无须等到写出所有函数之后才让菜单投入使用。你会注意到,函数从 clear 命令开始。这是为了能在一个干净的屏幕上执行函数,不让它受到原先菜单的干扰。
将菜单布局本身作为一个函数来创建,有助于制作 shell 脚本菜单:
function menu {
clear
echo
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"
echo -en "\t\tEnter option: "
read -n 1 option
}
这样,任何时候你都能调用 menu 函数来重现菜单。
添加菜单逻辑
现在你已经创建好了菜单布局和 menu 函数,只需创建程序逻辑将二者结合起来即可。前面提到过,这要用到 case 命令。
case 命令应该根据用户输入的字符来调用相应的函数。使用默认的 case 命令字符(星号)来处理所有不正确的菜单项是一种不错的做法。
下面的代码展示了菜单中 case 命令的典型用法:
menu
case $option in
0)
break ;;
1)
diskspace ;;
2)
whoseon ;;
3)
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
这段代码首先用 menu 函数清除屏幕并显示菜单。menu 函数中的 read 命令会一直等待,直到用户在键盘上输入了字符。然后,case 命令就会接管余下的处理过程。case 命令会基于用户输入的字符调用相应的函数。函数运行结束后,case 命令退出。
整合 shell 脚本菜单
现在你已经看到了组成 shell 脚本菜单的各个部分,让我们将它们整合在一起,看看它们彼此之间是如何协作的。下面是一个完整的菜单脚本示例:
function diskspace {
clear
df -k
}
function whoseon {
clear
who
}
function memusage {
clear
cat /proc/meminfo
}
function menu {
clear
echo
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"
echo -en "\t\tEnter option: "
read -n 1 option
}
while [ 1 ]
do
menu
case $option in
0)
break ;;
1)
diskspace ;;
2)
whoseon ;;
3)
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
echo -en "\n\n\t\t\tHit any key to continue"
read -n 1 line
done
clear
这个菜单创建了 3 个函数,以使用常见命令提取 Linux 系统的管理信息。while 循环用于持续处理菜单,除非用户选择了选项 0,即通过 break 命令跳出 while 循环。
可以用这个模板创建任何 shell 脚本的菜单界面。它提供了一种与用户交互的简单途径。
使用 select 命令
你可能已经注意到了,创建文本菜单的一半工夫花在了建立菜单布局和获取用户输入上。bash shell 提供了一款易于上手的小工具,能够帮助我们自动完成这些工作。
select 命令只需要一个命令就可以创建出菜单,然后获取输入并自动处理。select 命令的格式如下:
select variable in list
do
commands
done
list 参数是由空格分隔的菜单项列表,该列表构成了整个菜单。select 命令会将每个列表项显示成一个带编号的菜单项,然后显示一个由 PS3 环境变量定义的特殊提示符,指示用户做出选择。
下面是一个 select 命令的简单示例:
function diskspace {
clear
df -k
}
function whoseon {
clear
who
}
function memusage {
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")
memusage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
done
clear
select 语句中的所有内容必须作为一行出现。这从续行符就可以看出。运行该脚本会自动生成如下菜单:
./smenu1
# 1) Display disk space 3) Display memory usage
# 2) Display logged on users 4) Exit program
# Enter option:
记住,在使用 select 命令时,存储在指定变量中的值是整个字符串,而不是跟菜单选项相关联的数字。字符串才是要在 case 语句中进行比较的内容。