shell下的菜单-1

        三种生成菜单的方式,C编写的菜单解析程序、dialog工具、select语法。前两种方式是基于curses库的实现,可以处理光标移动,第三种方式由ksh或bash所提供的select菜单方式实现,不支持光标移动。

        第一种方式由两部分组成,C语言编写的菜单解析程序和shell编写的菜单处理程序。

菜单解析程序getkey.c:

/********************************************************
*程序功能:根据传入的菜单文件和坐标起始位置,显示菜单并
*	   获取选中条目,返回选中位置,该程序配合shell编写
*          通用界面,菜单项开始的1. 2. 3. 表示快捷键,
*	   只支持单屏显示,暂不支持多屏显示.
*程序参数:argv[1] 全路径菜单文件名 argv[2] 起始行位置
*	   argv[3] 起始列位置       argv[4] 上次选中菜单项
*程序返回:返回的是选中的菜单编号,正确的菜单编号从1开始,
	   0表示程序错误退出。
*程序注意:该程序违反一般UNIX程序的返回惯例,主要是为了解决
	   shell下不能处理负数返回值的问题,0表示出错。
*********************************************************/
#include 
#include 
#include 
#include 
#include 

/**定义支持的菜单条数和菜单长度**/
#define MAX_ITEM_NUM	40
#define MAX_ITEM_LEN	80

/**菜单项的前缀字符个数**/
#define MENU_OPT_LEN	2

struct Menu
{
	int beg_l;/**起始行坐标**/
	int beg_c;/**起始列坐标**/
	char menu_item[MAX_ITEM_NUM][MAX_ITEM_LEN];/**菜单项**/
	int item;/**菜单项数目**/
	int lst_sel;/**上次选择菜单项**/
};

void 	endscr();
int 	getchoice(const struct Menu* menu);
int 	get_menu(struct Menu* menu, char* file);
void 	clear_all_screen();
int 	draw_menu(const struct Menu* menu, int selected);

/**屏幕最大行坐标和列坐标**/
static int max_l=0,max_c=0;
static int show_error_l=20,show_error_c=0;
static int g_ret=0;

int main(int argc, char *argv[])
{
	if(argc<5)
	{
		printf("usage:%s menu_file line col def_sel\n", argv[0]);
		return 0;
	}
	struct Menu stMenu;
	char cMenu[MAX_ITEM_NUM][MAX_ITEM_LEN];
	memset(&stMenu, 0x00, sizeof(stMenu));
	stMenu.beg_l=atoi(argv[2]);
	stMenu.beg_c=atoi(argv[3]);
	stMenu.lst_sel=atoi(argv[4]);
	initscr();
	curs_set(0);/**设置光标不可见**/
	getmaxyx(stdscr, max_l, max_c);/**返回的是最大行数和列数**/
	max_l-=1;/**行坐标从0开始**/
	max_c-=1;/**列坐标从0开始**/
	if(stMenu.beg_l<0 || stMenu.beg_l>max_l)	stMenu.beg_l=0;
	if(stMenu.beg_c<0 || stMenu.beg_c>max_c)	stMenu.beg_c=0;
	g_ret = get_menu(&stMenu, argv[1]);
	if(g_ret){
		mvprintw(show_error_l++, show_error_c, "Get menu error!");
		endscr();
		return 0;
	}
	if(stMenu.lst_sel<1 || stMenu.lst_sel>stMenu.item)	stMenu.lst_sel=1;
	int selected = getchoice(&stMenu);
	curs_set(0);/**设置光标可见**/
	endscr();
	return selected;
}

int get_menu(struct Menu* menu, char* file)
{
	if(menu==NULL||file==NULL)
	{
		clear();
		mvprintw(show_error_l++, show_error_c, "Func [%s] NULL POINTER!",__func__);
		return 1;
	}
	char cLine[256];
	memset(cLine, 0x00, sizeof(cLine));
	FILE* fp=fopen(file, "r");
	if(fp==NULL){
		clear();
		mvprintw(show_error_l++, show_error_c, "Open file [%s] error!",file);
		return 1;
	}
	while(fgets(cLine, sizeof(cLine), fp))
	{
		menu->item++;
		if(menu->item>MAX_ITEM_NUM)
		{
				break;
		}
		strncpy(menu->menu_item[menu->item-1], cLine, sizeof(menu->menu_item[0])-1);
		memset(cLine, 0x00, sizeof(cLine));
	}
	fclose(fp);
	return 0;
}

/*clear_all_screen函数*/
void clear_all_screen()
{
	clear();
}

/**0表示程序出错,>0值表示用户选择的菜单序号**/
int getchoice(const struct Menu* menu)
{
	if(menu==NULL)
	{
		clear();
		mvprintw(show_error_l++, show_error_c, "Func [%s] NULL POINTER!",__func__);
		return 0;
	}
	int selected=0;
	int key = 0;
	clear_all_screen();
	keypad(stdscr, TRUE);/**打开功能键模式**/
	cbreak();
	noecho();
	selected = menu->lst_sel-1;/**默认选中的菜单项**/
	while(1)
	{
		if(key == KEY_UP)
		{
			/**默认可循环**/
			if(selected<=0){
				selected=menu->item-1;
			}else{
				--selected;
			}
		}
		if(key == KEY_DOWN)
		{
			/**默认可循环**/
			if(selected>=menu->item-1){
				selected=0;
			}else{
				++selected;
			}
		}else if(key=='\n' || key==KEY_ENTER)/**通过光标选中了某个选项**/
		{
			break;
		}
		else
		{
			for(int i=0; iitem; ++i)
			{
				if(key==menu->menu_item[i][0])
				{
					selected=i;
					break;
				}
			}
		}
		g_ret=draw_menu(menu, selected);
		if(g_ret){
			mvprintw(show_error_l++, show_error_c, "Draw menu error!");
			selected=-1;
			break;
		}
		key = getch();
	}
	keypad(stdscr, FALSE);
	nocbreak();
	echo();
	return selected+1;
}

int draw_menu(const struct Menu* menu, int selected)
{
	if(menu==NULL)
	{
		clear();
		mvprintw(show_error_l++, show_error_c, "Func [%s] NULL POINTER!",__func__);
		return 1;
	}
	int pos_l=menu->beg_l,
	    pos_c=menu->beg_c;
	char item_opt[MENU_OPT_LEN]={0};
	for(int i=0; iitem; ++i)
	{
		memset(item_opt, 0x00, sizeof(item_opt));
		strncpy(item_opt, menu->menu_item[i], MENU_OPT_LEN);
		mvprintw(pos_l, pos_c, "%s", item_opt);/**选项a,b,c,...不高亮**/
		if(i == selected){
			attron(A_STANDOUT);/**设置高亮属性**/
		}
		mvprintw(pos_l++, pos_c+strlen(item_opt), "%s", menu->menu_item[i]+strlen(item_opt));/**不包含选项a,b,c,**/
		if(i == selected){
			attroff(A_STANDOUT);/**关闭高亮属性**/
		}
	}
	refresh();
	return 0;
}

void endscr()
{
	refresh();
	endwin();
}

       通过cc -O2 -o getkey -lcurses getkey.c编译得到getkey可执行程序,以便在菜单处理程序中使用。

shell编写的菜单处理程序:

#!/usr/bin/sh
old_stty_setting=`stty -g`
trap " stty \"$old_stty_setting\";exit 1" 1 2 15

#确认完成返回
confirm_over()
{
	echo "\033[22;0H按确认完成\c"
	read
}

#确认是否继续
confirm_ok()
{
	echo "\033[22;0H按确认执行\c"
	read
	if [ "$REPLY" = "y" ];then
		return 0
	else
		return 1
	fi
}

#选中退出选项
f0()
{
	stty "$old_stty_setting"
	exit 0
}

#选中第一个菜单
f1()
{
	clear
	if confirm_ok ;then
		#要执行的命令
		:
		clear
		confirm_over
	fi
}

#选中第二个菜单
f2()
{
	clear
	confirm_over
}

#选中第三个菜单
f3()
{
	clear
	confirm_over
}

#选中第四个菜单
f4()
{
	clear
	confirm_over
}

MENU_FILE=menu.txt

cat >$MENU_FILE <<-EOF
	1.执行批前备份
	2.执行日终程序
	3.查询日终日志
	4.查看系统状态
	q.退出菜单
EOF

#定义菜单的响应程序
set -A menu_acts f1 f2 f3 f4 f0

if [ `wc -l<$MENU_FILE` -ne $((${#menu_acts[*]})) ]
then
	echo "请检查菜单条目和响应程序是否一致!"
	exit 1
fi

while true
do
	getkey $MENU_FILE 0 0 "$ans"
	ans=$?
	#将菜单编号转换为从0开始
	m_i=$((ans-1))
	if [ $m_i -lt 0 ]
	then
		exit 1
	fi
	${menu_acts[$m_i]}
done

菜单效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值