写一个自己的bash2.0版本
文章目录
在上一次我们写了一个mybash程序,生成了一个自己的简单的bash。通过执行mybash可执行程序,调用命令,如ps,ls等。原理是mybash调用fork()产生一个子进程然后再替换该子进程,详细请见上一篇博客 写一个自己的bash1.0版本但是仍有一些缺陷,比如, 1、我们的命令提示符是写死的,是通过printf()函数直接打印出来的 printf(“wys@DESKTOP-2OU3HRV:~$”);那么现在来回顾一下Linux终端的命令提示符各部分的含义
明白了各部分含义后,在*今天的2.0版本中首先得任务是改进命令提示符***,不要写死,让程序自己获取用户名,主机名,还有当前目录并识别当前是普通用户还是管理员用户。 2、像ps,ls,cp等等命令是在/usr/bin/目录下的,我们可以通过fork()一个子进程进而替换子进程来执行,但是还有一些命令是内置命令,比如cd ,jobs,exit等是在bin目录下找不到的,所以只能通过我们自己来实现, 今天2.0版本第二个任务就是自己简单实现cd命令
1、改进命令提示符
1.1获取用户名
参考Linux程序设计中文第四版 4.5用户信息
每一个用户都有一个唯一的用户标识符UID(管理员用户UID为0)。既然UID是用户身份的关键,那么我们就从UID开始吧!!!
UID有自己的类型–uid_t;
获取UID方法 uid_t getuid(void);
得到了用户UID后就可以通过UID来获取用户信息,方法:*struct passwd getpwuid(uid_t uid);
代码如下:
30 int id = getuid();//获取用户id
31 char* s = "$";
32 if( id == 0 )
33 {
34 s = "#";
35 }
36
37 struct passwd* ptr = getpwuid(id);//通过uid获取用户详细信息
38 if( ptr == NULL )
39 {
40 printf("$");
41 fflush(stdout);
42 return;
43 }
1.2获取主机名
参考Linux程序设计中文第四版 4.6主机信息
通过gethostname函数获取
*int gethostname(char name,size_t namelean);
gethostname函数把机器的网络名写入name字符串。该字符串至少有namelen个字长,成功时,gethostbyname返回0,否则返回-1。
代码如下:
45 char hostname[64] = { 0 };
46 if (gethostname(hostname,64) == -1 )
47 {
48 printf("$");
49 fflush(stdout);
50 return;
51 }
1.3获取当前位置
参考Linux程序设计中文第四版 3.7.5chdir系统调用和getcwd函数
程序可以通过调用getcwd函数来确定自己的当前工作目录
**#include <unistd.h>
char getcwd(char buff,size_t size);
getcwd函数把当前目录的名字写到给定的缓冲区buff里。如果目录名的长度超出了参数size的缓冲区长度(一个ERANGE错误),比如你所在的目录特别深,它就返回NULL,如果成功,它返回指针buf。
代码如下:
54 char pwd_buff[128] = {0};
55 if(getcwd(pwd_buff,128) == NULL)
56 {
57 printf("$");
58 fflush(stdout);
59 return;
60 }
1.4整个void print_info()函数完整代码
27 void print_info()
28 {
29
30 int id = getuid();//获取用户id
31 char* s = "$";
32 if( id == 0 )
33 {
34 s = "#";
35 }
36
37 struct passwd* ptr = getpwuid(id);//通过uid获取用户详细信息
38 if( ptr == NULL )
39 {
40 printf("$");
41 fflush(stdout);
42 return;
43 }
44
45 char hostname[64] = { 0 };
46 if (gethostname(hostname,64) == -1 )
47 {
48 printf("$");
49 fflush(stdout);
50 return;
51 }
52
53 //获取当前位置
54 char pwd_buff[128] = {0};
55 if(getcwd(pwd_buff,128) == NULL)
56 {
57 printf("$");
58 fflush(stdout);
59 return;
60 }
61
62 //打印命令提示行信息
63 printf("\033[1;32;40m %s@%s:\033[0m \033[1;34;40m%s%s\033[0m",ptr->pw_name,hostname,pwd_buff,s);
64 fflush(stdout);
65 }
2、实现简单的cd命令操作
参考Linux程序设计中文第四版 3.7.5chdir系统调用和getcwd函数
程序可以像用户在文件系统里那样来浏览目录。就像你在shell里使用cd命令来切换目录一样,程序使用的是chdir系统调用。
#include<unistd.h>
int chdir(const char *path);
如果是cd命令,传入的第二个参数,即要切换的目录为空,则结束本次循环,再次打印出命令提示符(Linux bash中当cd后没有目录时,则切换到家目录,自己的mybash没有必要和bash相同,也可以自己设计),不为空时,使用chdir系统调用,操作成功则continue结束本次循环,重新打印当前路径。
代码如下:
86 if (strcmp(cmd,"cd") == 0)
87 {
88 if( myargv[1] == NULL )
89 {
90 continue;
91 }
92 if ( chdir(myargv[1]) == -1)
93 {
94 perror("cd err");
95 }
96 continue;
97 }
3、mybash完整代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 #include<sys/wait.h>
6 #include<pwd.h>
7 #include<errno.h>
8
9 char* get_cmd (char buff[],char* myargv[])
10 {
11
12 if( buff == 0 || myargv == 0)
13 {
14 return NULL;
15
16 }
17 char*s = strtok(buff," ");
18 int i = 0;
19 while( s != NULL )
20 {
21 myargv[i++] = s;
22 s = strtok(NULL," ");
23 }
24 return myargv[0];
25 }
26
27 void print_info()
28 {
29
30 int id = getuid();//获取用户id
31 char* s = "$";
32 if( id == 0 )
33 {
34 s = "#";
35 }
36
37 struct passwd* ptr = getpwuid(id);//通过uid获取用户详细信息
38 if( ptr == NULL )
39 {
40 printf("$");
41 fflush(stdout);
42 return;
43 }
44
45 char hostname[64] = { 0 };
46 if (gethostname(hostname,64) == -1 )
47 {
48 printf("$");
49 fflush(stdout);
50 return;
51 }
52
53 //获取当前位置
54 char pwd_buff[128] = {0};
55 if(getcwd(pwd_buff,128) == NULL)
56 {
57 printf("$");
58 fflush(stdout);
59 return;
60 }
61
62 //打印命令提示行信息
63 printf("\033[1;32;40m %s@%s:\033[0m \033[1;34;40m%s%s\033[0m",ptr->pw_name,hostname,pwd_buff,s);
64 fflush(stdout);
65 }
66 int main()
67
68 {
69 while(1)
70 {
71 char buff[128] = { 0 };
72 print_info();
73 fgets(buff,128,stdin);
74 buff[strlen(buff) - 1] = 0;
75 char* myargv[10] = { 0 };
76 char* cmd = get_cmd(buff,myargv);
77 if(cmd == NULL)
78 {
79 continue;
80 }
81
82 else if (strcmp(cmd,"exit") == 0 )
83 {
84 exit(0);
85 }
86 else if (strcmp(cmd,"cd") == 0)
87 {
88 if( myargv[1] == NULL )
89 {
90 continue;
91 }
92 if ( chdir(myargv[1]) == -1)
93 {
94 perror("cd err");
95 }
96 continue;
97 }
98 else
99 {
100 pid_t pid = fork();
101 if(pid == -1 )
102 {
103 printf("fork error\n");
104 }
105
106 if(pid == 0 )
107 {
108 execvp(cmd,myargv);
109 printf("exec error\n");
110 exit(0);
111 }
112 wait(NULL);
113 }
114
115
116 }
117 exit(0);
118 }
4、编译运行程序
通过运行,我们发现mybash已经自动获取用户名,主机名,当前目录,以及是普通用户还是管理员用户,也实现了cd命令。就此mybash2.0版本结束了!!!