shell架构,环境变量

本文介绍ARM裸机环境下Shell的开发过程,包括命令获取、解析与执行,并演示了如何添加标准命令集及环境变量管理功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文总结自《朱有鹏老师嵌入式linux核心课程》的《1.16.ARM裸机第十六部分-shell原理和问答机制引入》中的《1.16.4.shell实战3-定义标准命令集及解析》至《1.16.7.shell实战6-添加其他命令2》。


shell包括三个部分:

(1)第1步:命令获取

(2)第2步:命令解析

(3)第3步:命令执行


shell中的三部分在程序中表示如下:

int main(void)
{
     char buf[MAX_LINE_LENGTH] = {0};// 用来暂存用户输入的命令
     shell_init();                   //这里面应该包括所应用硬件的初始化,以及命令集初始化
     while(1)  //shell是个死循环,处理完一个命令的获取、解析、执行之后进入下一个命令的循环
     {
       // 第1步:命令获取
       puts("aston#");
       // buf弄干净好存储这次用户输入
       memset(buf, 0, sizeof(buf));

       // 读取用户输入放入buf中, 注:这个地方没有命令输入的时候是阻塞在                                     //这个位置的,gets函数内部实现的功能是当从键盘上输入‘\n’的时候才解除阻塞,继续执行。
       gets(buf);
       cmd_parser(buf);// 第2步:命令解析                
       cmd_exec();     // 第3步:命令执行

      }
      return 0;
}


cmd_parser(buf):解析命令的方法主要是和标准命令集中的字符串进行比较,如果找到命令,就记录此命令在命令集中所在的下标。找到下标即解析完成。


cmd_exec():利用找到的下标来调用硬件驱动,从而完成对硬件的控制。主要应用的是switch case语句,这样做可以方便扩展其他硬件操作。


void cmd_exec(void)
{
    switch (cmd_index)
    {
        case 0: // led
              do_cmd_led(); break;
        case 1: // lcd
              do_cmd_lcd(); break;
        case 2: // buzzer 
              do_cmd_buzzer();break;
        case 3: // adc 
              do_cmd_adc(); break;
        default:
              do_cmd_notfound();break;
    }
}

以do_cmd_led()为例,由于对led的操作的多样化,因此在 do_cmd_led函数中还需要利用if语句选择相应的操作,这和S5PV210的中断服务程序的写法比较类似。


// led命令的处理方法
void do_cmd_led(void)
{
	int flag = -1;
	// 真正的led命令的操作实现
	// 目前支持的命令有led on | led off 
	// cmd[0]里面是led,cmd[1]里面是on|off
	if (!strcmp(cmd[1], "on"))
	{
		// led on
		led_on();
		flag = 1;
	}
	if (!strcmp(cmd[1], "off"))
	{
		// led off
		led_off();
		flag = 1;
	}
	// ..... 还可以继续扩展

	if (-1 == flag)
	{
		// 如果一个都没匹配,则打印使用方法
		puts("command error, try: led on | led off");
		puts("\n");
	}
}

如果要扩展硬件,在命令集初始的时候要扩展命令集,命令解析不用更改,主要是更改命令执行部分,增加switch-case的相关分支,同时再编写do_cmd_xxx的时候也要正确增加if分支。


上面添加的部分也只是硬件操作功能,然而在uboot这样的shell中,管理环境变量也是shell的重要组成部分,添加方式和硬件功能加入shell的方式一样。


环境变量:

环境变量就好象程序的全局变量一样,整个程序中唯一。
可以影响程序的执行,环境变量可以支持一些命令(这个命令要在shell中实现)来查询环境变量、设置环境变量、保存环境变量(必须借助flash才能完成。等开机的时候,就会直接利用flash中存储的环境变量参数来完成环境变量的初始化)


环境变量相关函数为(在扩展shell功能的时候相当于硬件do_cmd_led中led_on()):

void env_init(void);

int env_get(const char *pEnv, char *val);

void env_set(const char *pEnv, const char *val);


环境变量通常是个结构体(例如):

typedef struct env
{
	char env_name[10];//记录环境变量的名字
	char env_val[20]; //记录环境变量的值,这个才是真正干活的数据,其他两个都是辅助标记
	int  is_used;	  // 标志位,0表示这个环境变量没用,1表示用了
}env_t;

在shell中增加环境变量的查询,设置以及保存功能时一定要记住扩展相应的命令集(即命令集初始化):

void init_cmd_set(void)
{
	memset((char *)g_cmdset, 0, sizeof(g_cmdset));		// 先全部清零
	strcpy(g_cmdset[0], led);
	strcpy(g_cmdset[1], lcd);
	strcpy(g_cmdset[2], pwm);
	strcpy(g_cmdset[3], adc);
	strcpy(g_cmdset[4], printenv);
	strcpy(g_cmdset[5], setenv);
	memset((char *)cmd, 0, sizeof(cmd));	
}










                
### 只读Shell环境变量的定义与使用 #### 定义只读环境变量Shell中,`readonly`命令用于将变量标记为只读。一旦某个变量被声明为只读,它的值就不能再被修改或删除[^1]。为了使该变量成为环境变量,还需要通过`export`命令将其导出到环境中。 以下是创建只读环境变量的具体过程: 1. **定义变量并赋初值** 首先定义一个普通的Shell变量,并为其赋予初始值。 2. **将变量设为只读** 使用`readonly`命令对该变量进行保护,防止后续对其值的任何更改尝试。 3. **导出为环境变量** 利用`export`命令将此变量提升至环境变量级别,使得子进程能够继承它。 示例代码如下: ```bash #!/bin/bash MY_VAR="This is a read-only environment variable" export MY_VAR readonly MY_VAR echo $MY_VAR ``` #### 设置方法注意事项 当试图对已经设定成只读状态下的变量重新分配新数值或者执行清除操作(`unset`)时,系统将会抛出错误提示表明这是不可变更的只读型态数据对象[^1]。 #### 使用场景分析 只读环境变量适用于那些在整个应用程序生命周期内都不应该发生变化的关键配置参数场合。例如,在部署大型分布式应用架构下,某些固定的网络端口号、数据库连接串或者是API密钥等敏感信息都可以考虑采用这种方式加以管理以增强系统的稳定性和安全性[^4]。 另外值得注意的是虽然我们讨论的重点在于“环境”层面的只读特性实现,但实际上无论是局部还是全局作用域内的任意种类别的shell变量均支持利用同样的机制施加类似的限制条件[^3]。 ### 示例演示 下面给出一段完整的脚本来展示整个流程以及验证效果: ```bash #!/bin/bash # Step 1: Define the variable with initial value. DB_HOST="localhost" # Step 2: Export it as an environmental variable so child processes can access it too. export DB_HOST # Step 3: Mark this variable as 'read only'. readonly DB_HOST # Print out current status of our newly created RO env var. echo "Database Host set to: $DB_HOST" # Attempting modification will fail now... DB_HOST="new-host.example.com" && echo "Modified successfully!" || echo "Modification failed due to being READ ONLY!" ``` 运行以上脚本后可以看到最后一步修改失败的信息输出,证明了我们的目标达成情况良好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值