Linux小知识---Shell下的图形界面

背景介绍

最近支持现场产品部署,由于系统并没有UI界面,开机只有一个命令行,IP地址不可用的时候,web配置管理也没办法使用,此时让用户来改一个IP地址的话,就得需要一定的专业知识了,这可不够人性啊。
在这里插入图片描述

所以特意研究了一下shell下能够用的界面,ncurses和dialog。
设计的软件流程如下
在这里插入图片描述
就是一个状态机,切换不同状态下的界面。

ncurses

这是一个开源的c语言库,用来创建用户交互的接口。整个流程的思路就是创建了一个窗口,然后开始在上半部分输出结果,最后一行为输入。
效果
在这里插入图片描述
在这里插入图片描述
库安装
CentOS下需要安装ncurses-devel这个库

yum install ncurses-devel

主函数

int main(int argc, char *argv[])
{
	system_ver = check_system();
    if (init_win() != 0) 
	{
        printf("init_win fail!\n");
        destroy_win();
        return -1;
    }
	if(has_colors() == TRUE) 
	{ 
	 	init_pair(1, COLOR_WHITE, COLOR_MAGENTA);
		attron(COLOR_PAIR(1));
	}
	
    proc_user_cmd();
	if(has_colors() == TRUE) 
	{ 
		attroff(COLOR_PAIR(1));
	}
    stop();
 
    return 0;
}

这里的has_colors() 是为了判断系统支持不支持彩色,支持的话就会设置前景色和背景色。
初始化函数

static int init_win()
{
    initscr();
	start_color();
    raw();
    keypad(stdscr, TRUE);
    refresh();
    memset(&s_win, 0, sizeof(s_win));
    s_win.resp_win = newwin(BODY_HEIGHT, COLS, 0, 0);
    if(s_win.resp_win == NULL) {
        return -1;
    }
    leaveok(s_win.resp_win, TRUE);
    scrollok(s_win.resp_win, TRUE);
    wsetscrreg(s_win.resp_win, 0, resp_win_lines());
 
    return 0;
}

创建了一个窗口,初始化并配置大小。
主状态机

static int proc_user_cmd()
{
	bool run=true;
	while(run)
	{
		if(g_sta_now == _wait_sel_ifname)
		{
			waite_sel_ifname();
		}
		else if(g_sta_now == _wait_sel_setpart)
		{
			waite_sel_setpart();
		}
		else if(g_sta_now == _wait_input_ip)
		{
			wait_input_ip();
		}
		else if(g_sta_now == _wait_input_netmask)
		{
			wait_input_netmask();
		}
		else if(g_sta_now == _wait_input_gateway)
		{
			wait_input_gateway();
		}
		else if(g_sta_now == _wait_input_dns1)
		{
			wait_input_dns1();
		}
		else if(g_sta_now == _wait_input_dns2)
		{
			wait_input_dns2();
		}
		else if(g_sta_now == _wait_save_ifname)
		{
			wait_save_ifname();
		}
		else
			
		{
			run=false;
		}
	}
	
    return 0;  
}
 

举一个选择接口的例子

static int waite_sel_ifname()
{
	bool runnow=true;
	clean_all_paras();
	
    while(runnow) 
	{
		clean_resp_win();
      	show_info_msg("Select interface");
		get_all_ifnames();		
 		wait_input_msg();
		
        if (s_win.cmd_len > FLAG_LEN) 
		{
            if ((strcasecmp(cmd_str(), "exit") != 0)&&(strcasecmp(cmd_str(), "q") != 0))
			{
                int num=atoi(cmd_str());
                if((num>0)&&(num<=all_if))
                {
					g_sta_now = _wait_sel_setpart;
					use_if=num;
					alog("select ifname:");
					alog(ifnames[use_if].ifname);
					strcpy(save_ifname,ifnames[use_if].ifname);
					strcpy(save_if_path,ifnames[use_if].cfg_file);
				}
            } 
			else 
			{
				g_sta_now = _exit_code;
            }
        }
		exit_input();
		runnow =false;
    }
    return 0;  
}

显示标题的函数如下

static void show_info_msg(char* infomsg)
{
	s_win.cmd_line = 1;
	s_win.cmd_y = 0;
	s_win.cmd_x = FLAG_LEN;
	s_win.cmd_len = FLAG_LEN;
	memset(s_win.cmd, 0, sizeof(s_win.cmd));
	strcpy(s_win.cmd, infomsg);

	move(s_win.cmd_y, 0);
	clrtoeol();
	refresh();
	mvprintw(s_win.cmd_y++, 0, "%s", s_win.cmd);
}

然后列出所有接口并记录。
等待输入的函数如下

static void wait_input_msg(void)
{
	int cmd_count = 0;
	
	s_win.cmd_line = 1;
	s_win.cmd_y = MAX_Y;
	s_win.cmd_x = FLAG_LEN;
	s_win.cmd_len = FLAG_LEN;
	memset(s_win.cmd, 0, sizeof(s_win.cmd));
	strcpy(s_win.cmd, CMD_FLAG);

	move(s_win.cmd_y, 0);
	clrtoeol();
	refresh();
	mvprintw(s_win.cmd_y, 0, "%s", s_win.cmd);
	refresh();

	int ch;
	while((ch=getch()) != KEY_Enter) 
	{
		switch (ch) 
		{
			case KEY_CTRL_C:
				g_sta_now = _exit_code;
				return ;
				
			case KEY_UP:
				if (cmd_count < RECORD_SUM) 
				{
					//show_cmd_record(++cmd_count);
				}		
			break;
				
			case KEY_DOWN:
				if (cmd_count > 0) {
					//show_cmd_record(--cmd_count);
				} else {
					mvprintw(MAX_Y, 0, CMD_FLAG);
					clrtoeol();
				}
			break;
				
			case KEY_LEFT:
				on_key_left();
			break;
			
			case KEY_RIGHT:
				on_key_right();
			break;
			
			case KEY_TAB:
				on_key_tab(cmd_str());
				move(MAX_Y, s_win.cmd_x);
			break;
			
			case KEY_BackSpace:
				on_key_backspace();
			break;
			
			case KEY_DC:
				on_key_delete();
			break;
			
			default:
				if (s_win.cmd_len < CMD_MAX) 
				{
					on_key_normal(ch);
				}
			break;
		}

		refresh();
	}

}

里面有很多操作,例如按下左右设置光标,退格键删除等。

完整代码下载路径,内部包含了代码和ncurses中文说明手册。
《基于ncurses开发配置网络图形化界面》

这个库的功能其实远比我写的这个强大,甚至可以制作游戏。
在这里插入图片描述

Dialog

俗话说有时候shell一句话,C语言可能要写100行代码 ,也不知道是谁说的。
在这里插入图片描述

所以这里找到了一个shell的模块,用来生成一系列对话框,这就是dialog命令
关于各种参数和用法,可以参考这个文章
《shell之dialog详解》

看一下效果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个看上去是不是就很银杏啊。
首先要安装dialog命令,CentOS7下

yum install dialog

整个脚本就100多行,主体依旧是一个状态机。基本每一步就是将对话的结果保存为文件,最终确认保存的时候,将文本内容依次写入配置文件,并重启网络

while(( $run == 1 ))
do
	case $Q_STATUS in
    0)  
		dialog --menu "which interface do you want to set?" 15 30 8 $ALL_INF_LIST 2> _ifname.txt
		Q_STATUS=1
		Q_IFNAME=$(cat _ifname.txt)
    ;;
    1)  
		dialog --menu "which part do you want to set?" 15 30 8 1 "ipaddr" 2 "netmask" 3 "gateway" 4 "dns1" 5 "dns2" 6 "save config" 7 "exit" 2> _setpart.txt
		Q_SETPART=$(cat _setpart.txt)
		if [ $Q_SETPART = "1" ];then
		   Q_STATUS=2
		elif [ $Q_SETPART = "2" ];	then
		   Q_STATUS=3
		elif [ $Q_SETPART = "3" ];	then
		   Q_STATUS=4
		elif [ $Q_SETPART = "4" ];	then
		   Q_STATUS=5
		elif [ $Q_SETPART = "5" ];	then
		   Q_STATUS=6
		elif [ $Q_SETPART = "6" ];	then
		   Q_STATUS=7
		elif [ $Q_SETPART = "7" ];	then
			dialog --clear  # “-clear”作用为清屏。
			exit 0			
		else
		   echo "没有符合的条件"
		fi
    ;;
    2)  
		dialog --title "IP" --inputbox "Please enter ip" 9 30 2>_ipaddr.txt
		Q_STATUS=1		
	;;
    3)  
		dialog --title "Netmask" --inputbox "Please enter netmask" 9 30 2>_netmask.txt
		Q_STATUS=1
	;;
    4)  
		dialog --title "Gateway" --inputbox "Please enter gateway" 9 30 2>_gateway.txt
		Q_STATUS=1		
	;;
    5)  
		dialog --title "DNS1" --inputbox "Please enter dns1" 9 30 2>_dns1.txt
		Q_STATUS=1		
	;; 
    6)  
		dialog --title "DNS2" --inputbox "Please enter dns2" 9 30 2>_dns2.txt
		Q_STATUS=1
	;; 
	7)  
		dialog --title "Confirm" --yesno "Are you willing to save config?\n" 9 18

		if [ $? !=0 ]; then  # yes的返回码为0,“$?”为上一个命令的退出状态。
			dialog --infobox "Thank you anyway!" 5 20
			sleep 2
			dialog --clear  # “-clear”作用为清屏。
			exit 0
		else
			if [ -f "./_ipaddr.txt" ]; then
				Q_IPADDR=$(cat _ipaddr.txt)
				sed -i '/IPADDR=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				echo  IPADDR=$Q_IPADDR >> /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				
			fi
			if [ -f "./_netmask.txt" ]; then
				Q_NETMASK=$(cat _netmask.txt)
				sed -i '/PREFIX=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				sed -i '/NETMASK=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				echo  NETMASK=$Q_NETMASK >> /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				
			fi
			if [ -f "./_gateway.txt" ]; then
				Q_GATEWAY=$(cat _gateway.txt)
				sed -i '/GATEWAY=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				echo  GATEWAY=$Q_GATEWAY >> /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				
			fi
			if [ -f "./_dns1.txt" ]; then
				Q_DNS1=$(cat _dns1.txt)
				sed -i '/DNS1=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				echo  DNS1=$Q_DNS1 >> /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				
			fi			
			if [ -f "./_dns2.txt" ]; then
				Q_DNS2=$(cat _dns2.txt)
				sed -i '/DNS2=/d' /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				echo  DNS2=$Q_DNS2 >> /etc/sysconfig/network-scripts/ifcfg-$Q_IFNAME
				
			fi

			##CentOS7
			systemctl restart network
			##CentOS8
			##ifdown $Q_IFNAME;ifup $Q_IFNAME
			
			dialog --infobox "Save config success!" 5 20
			sleep 2
			dialog --clear  # “-clear”作用为清屏。
			exit 0			
		fi
		Q_STATUS=1
	;;
	*) 
    ;;
esac
done

完整代码下载
《基于dialog命令开发的网络配置工具》

结束语

最近总是感觉睡不醒,脑子里倒是总有想法,就是时间不太够用。“内在有激情,但是还要从容不迫。”
在这里插入图片描述

今天就简单的讲一个小的现象,就是为什么动物的腿都是双数。
是因为动物从海里进化到陆地上的时候,进化为腿的是鱼类的鳍,腹部的鳍都是成对存在的,所以爬上来进化出来的腿,也是成对的。
在这里插入图片描述
简单而言,成对的腿有什么好处呢,就是为了不跑偏。

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值