简易shell
自主实现shell
done,故意写成=,表示先赋值,再判断,分割之后,strtok会返回NULL,刚好让gArgv最后一个元素是NULL,并且while判断结束
Makefile
1 myshell:myshell.c
2 gcc -o $@ $^
3 .PHONY:clean
4 clean:
5 rm -f myshell
myshell.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<sys/wait.h>
5 #include<stdlib.h>
6 #include<string.h>
7 #include<errno.h>
8
9 #define SIZE 512
10 #define ZERO '\0'
11 #define SEP " "
12 #define NUM 32
13 #define SkipPath(p) do{p += (strlen(p) - 1);while(*p != '/') p--;}while(0)
14
15 char cwd[SIZE*2];
16 char *gArgv[NUM];
17 int lastcode = 0;
18 void Die()
19 {
20 exit(1);
21 }
22
23 const char *GetHome()
24 {
25 const char *home = getenv("HOME");
26 if(home == NULL) return "/";
27 return home;
28 }
29 const char *Getusername()
30 {
31 const char *name = getenv("USER");
32 if(name == NULL) return "None";
33 return name;
34 }
35 const char *Gethostname()
36 {
37 const char *hostname = getenv("HOSTNAME");
38 if(hostname == NULL) return "None";
39 return hostname;
40 }
41 const char *Getcwd()
42 {
43 const char *cwd = getenv("PWD");
44 if(cwd == NULL) return "None";
45 return cwd;
46 }
47
48 void makecommandline()
49 {
50 char line[SIZE];
51 const char *username = Getusername();
52 const char *hostname = Gethostname();
53 const char *cwd = Getcwd();
54
55 SkipPath(cwd);
56 snprintf(line, sizeof(line), "[%s@%s %s] love:", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1);
57 printf("%s", line);
58 fflush(stdout);
59 }
60
61 int Getusercommand(char command[], size_t n)
62 {
63 char *s = fgets(command, n, stdin);
64 if(s == NULL) return -1;
65
66 command[strlen(command) - 1] = ZERO;
67 return strlen(command);
68 }
69
70 void SplitCommand(char command[], size_t n)
71 {
72 (void)n;
73 gArgv[0] = strtok(command, SEP);
74 int index = 1;
75 while((gArgv[index++] = strtok(NULL, SEP)));
76 }
77 void ExecuteCommand()
78 {
79 pid_t id = fork();
80 if(id < 0) Die();
81 else if(id == 0)
82 {
83 //child
84 execvp(gArgv[0], gArgv);
85 exit(errno);
86 }
87 else
88 {
89 //father
90 int status = 0;
91 pid_t rid = waitpid(id, &status, 0);
92 if(rid > 0)
93 {
94 lastcode = WEXITSTATUS(status);
95 if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);
96 }
97 }
98 }
99
100 void Cd()
101 {
102 const char *path = gArgv[1];
103 if(path == NULL) path =GetHome();
104
105 chdir(path);
106 //刷新环境变量
107 char temp[SIZE*2];
108 getcwd(temp, sizeof(temp));
109 snprintf(cwd, sizeof(cwd), "PWD=%s", temp);
110 putenv(cwd);
111 }
112 int CheckBuildin()
113 {
114 int yes = 0;
115 const char *enter_cmd = gArgv[0];
116 if(strcmp(enter_cmd, "cd") == 0)
117 {
118 yes = 1;
119 Cd();
120 }
121 else if(strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0)
122 {
123 yes = 1;
124 printf("%d\n", lastcode);
125 lastcode = 0;
126 }
127
128 return yes;
129 }
130 int main()
131 {
132 int quit = 0;
133 while(!quit)
134 {
135 makecommandline();
136
137 char usercommand[SIZE];
138 int n = Getusercommand(usercommand, sizeof(usercommand));
139 if(n <= 0) return 1;
140
141 SplitCommand(usercommand, sizeof(usercommand));
142
143 n = CheckBuildin();
144 if(n) continue;
145 ExecuteCommand();
146 }
147
148 return 0;
149 }