【Linux】自主shell编写

如果学习了常见的Linux命令,exec*函数,环境变量,那你就可以尝试一下写一个简单的shell;

下面跟着我的步骤来吧!!🤩🤩

输入命令行

既然要写一个shell,我们第一步先把这个输入命令行打印出来:

观察一下:命令行中有三个环境变量,我们如何查找它们呢?

这就需要使用env查找:发现USER、HOSTNAME、PWD;

 怎么用代码来获取这三个环境变量对应的值呢?

用:getenv函数

有关函数更详细的内容可以区man手册上区查看

接下来,我们就可以写代码了:(主要代码,完整代码在文章最后)

  void Makecommandline()
  {
      char cmd[SIZE];
      const char *name=Getname();
      const char *hostname = Gethostname();
      const char *cwd =Getcwd();
      snprintf(cmd,sizeof(cmd),"[%s@%s %s]> ",name,hostname,cwd);
      printf("%s",cmd);
      fflush(stdout);
  }

获取用户命令

想一下,我们输入一个命令时,有时候是ls,有时候是ls -l -a ,输入的有空格怎么办呢?🤖

这时就可以用fgets函数来输入命令;

 void Getusercommand(char Usercmd[])
 {
     char *s = fgets(Usercmd,sizeof(Usercmd),stdin);
     if(s==NULL)
     {
         perror("fgets");
         exit(1);
     }
     Usercmd[strlen(Usercmd)-1]='\0';
 }

命令行字符串分割

获取到用户命令后,接下来我们要对这个命令进行分割:

分割用的是strtok函数;

代码:

void Splitcommand(char Usercmd[])
 {
     argv[0]=strtok(Usercmd,SEP);
     int index=1;
     while(argv[index++]=strtok(NULL,SEP));
 }

执行命令

完成上述的准备工作后,我们要执行我们输入的命令,那要怎么执行呢?

🤡当然是用的我们的exec*函数喽,这里根据实际情况,我们选择的应该是execvp()函数;

💥💥注意:我们使用exec*函数时,要创建一个子进程来进行,这样才不会使父进程中后续代码被覆盖!!

代码:

void Executecommand()
 {
     pid_t id =fork();
     if(id<0)
     {
         exit(1);
     }
     else if(id==0)
     {
         execvp(argv[0],argv);
         exit(errno);
     }
     else
     {
         int status=0;
         pid_t rid =waitpid(id,&status,0);
         if(rid>0)
         {
             //wait sucess
             lastcode = WEXITSTATUS(status);
             if(lastcode!=0)
             {
                 printf("%s:%s:%d\n",argv[0],strerror(lastcode),lastcode);
             }
         }
     }
 }

检测命令是否是内建命令

😺😺完成上述的四部后,你就已经完成了一个简单的shell,但是并不完整;哪里不完整呢?我们可以输入一个内建命令,比如cd命令,这时我们就找到了要完善的地方;

怎么完善呢?

我们要判断一下这个命令是不是内建命令,怎么判断呢,非常简单,直接if语句:

如果有其他的内建命令,直接添加即可;

Cd():如果是内建cd命令,看一下argv[1]是不是空,

(1)如果是空,我们输入的命令就是cd,那不就是直接回到家目录了嘛,如果不为空,就不要变了;

(2)接下来,直接改变cwd即可,用chdir函数;

(3)修改环境变量PWD的值,用putenv函数;

💥💥注意:putenv 用于将一个字符串添加到环境变量中,或者修改已经存在的环境变量。这个字符串的格式通常是 "NAME=VALUE",其中 NAME 是环境变量的名称,VALUE 是其对应的值。

你已经完成了一个基础的shell,更完善的shell还会继续更新!!

完整代码:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 #include<errno.h>
  8 
  9 # define SkipPath(p) do{p+=(strlen(p)-1);while(*p!='/')p--;}while(0)
 10 
 11 
 12 #define SIZE 512
 13 #define SEP " "
 14 
 15 
 16 char cwd[SIZE*2];
 17 int lastcode =0;
 18 char *argv[SIZE*2];
 19 
 20 const char *Getname()
 21 {
 22     const char *name=getenv("USER");
 23     if(name==NULL)return "None";
 24     return name;
 25 }
 26 
 27 
 28 const char *Gethostname()
 29 {
 30     const char *hostname=getenv("HOSTNAME");
 31     if(hostname==NULL)return "None";
 32     return hostname;
 33 }
 34 
 35 
 36 const char *Getcwd()
 37 {
 38     const char *pwd=getenv("PWD");
 39     if(pwd==NULL)return "None";
 40     return pwd;
 41 }
 42 
 43 void Makecommandline()
 44 {
 45     char cmd[SIZE];
 46     const char *name=Getname();
 47     const char *hostname = Gethostname();
 48     const char *cwd =Getcwd();
 49     SkipPath(cwd);
 50     snprintf(cmd,sizeof(cmd),"[%s@%s %s]> ",name,hostname,strlen(cwd)==1 ? "/":cwd+1);
 51     printf("%s",cmd);
 52     fflush(stdout);
 53 }
 54 
 55 void Getusercommand(char Usercmd[])
 56 {
 57     char *s = fgets(Usercmd,sizeof(Usercmd),stdin);
 58     if(s==NULL)
 59     {
 60         perror("fgets");
 61         exit(1);
 62     }
 63     Usercmd[strlen(Usercmd)-1]='\0';
 64 }
 65 
 66 void Splitcommand(char Usercmd[])
 67 {
 68     argv[0]=strtok(Usercmd,SEP);
 69     int index=1;
 70     while(argv[index++]=strtok(NULL,SEP));
 71 }
 72 const char *Gethome()
 73 {
 74     const char *home =getenv("HOME");
 75     if(home==NULL)return "/root";
 76     return home;
 77 }
 78 void Cd()
 79 {
 80     const char *path =argv[1];
 81     if(path==NULL)
 82     {
 83         //返回家目录
 84         path = Gethome();
 85     }
 86     chdir(path);
 87     char tmp[SIZE*2];
 88     getcwd(tmp,sizeof(tmp));
 89     snprintf(cwd,sizeof(cwd),"PWD=%s",tmp);
 90     putenv(cwd);
 91     //printf("%s\n",cwd);
 92 }
 93 int Checkbuildin()
 94 {
 95     int yes=0;
 96     if(strcmp(argv[0],"cd")==0)
 97     {
 98         yes=1;
 99         Cd();
100     }
101     return yes;
102 }
103 void Executecommand()
104 {
105     pid_t id =fork();
106     if(id<0)
107     {
108         exit(1);
109     }
110     else if(id==0)
111     {
112         execvp(argv[0],argv);
113         exit(errno);
114     }
115     else
116     {
117         int status=0;
118         pid_t rid =waitpid(id,&status,0);
119         if(rid>0)
120         {
121             //wait sucess
122             lastcode = WEXITSTATUS(status);
123             if(lastcode!=0)
124             {
125                 printf("%s:%s:%d\n",argv[0],strerror(lastcode),lastcode);
126             }
127         }
128     }
129 }
130 int main()
131 {
132     while(1)
133     {
134         //1、我们自己输入一个命令行
135         Makecommandline();
136 
137         //2、获取用户命令字符串分割
138         char Usercmd[SIZE];
139         Getusercommand(Usercmd);
140         //printf("%s\n",Usercmd);
141         //3、命令行字符串分割
142         Splitcommand(Usercmd);
143         //4、检测命令是否是内建命令
144         int n = Checkbuildin();
145         if(n)continue;
146         //5、执行命令
147         Executecommand();
148     }
149     return 0;
150 }
### 关于ArcGIS License Server无法启动的解决方案 当遇到ArcGIS License Server无法启动的情况,可以从以下几个方面排查并解决问题: #### 1. **检查网络配置** 确保License Server所在的计算机能够被其他客户端正常访问。如果是在局域网环境中部署了ArcGIS Server Local,则需要确认该环境下的网络设置是否允许远程连接AO组件[^1]。 #### 2. **验证服务状态** 检查ArcGIS Server Object Manager (SOM) 的运行情况。通常情况下,在Host SOM机器上需将此服务更改为由本地系统账户登录,并重启相关服务来恢复其正常工作流程[^2]。 #### 3. **审查日志文件** 查看ArcGIS License Manager的日志记录,寻找任何可能指示错误原因的信息。这些日志可以帮助识别具体是什么阻止了许可服务器的成功初始化。 #### 4. **权限问题** 确认用于启动ArcGIS License Server的服务账号具有足够的权限执行所需操作。这包括但不限于读取/写入特定目录的权利以及与其他必要进程通信的能力。 #### 5. **软件版本兼容性** 保证所使用的ArcGIS产品及其依赖项之间存在良好的版本匹配度。不一致可能会导致意外行为完全失败激活license server的功能。 #### 示例代码片段:修改服务登录身份 以下是更改Windows服务登录凭据的一个简单PowerShell脚本例子: ```powershell $serviceName = "ArcGISServerObjectManager" $newUsername = ".\LocalSystemUser" # 替换为实际用户名 $newPassword = ConvertTo-SecureString "" -AsPlainText -Force Set-Service -Name $serviceName -StartupType Automatic New-ServiceCredential -ServiceName $serviceName -Account $newUsername -Password $newPassword Restart-Service -Name $serviceName ``` 上述脚本仅作为示范用途,请依据实际情况调整参数值后再实施。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值