【操作系统】|Linux 命令解释程序设计与实现

实验目的

探索、理解并掌握操作系统命令解释器的设计原理和实现机制,基于 Linux 内核进行相应命令解释程序的设计和实现,并在 Linux 操作系统平台上加以测试验证。

实验内容

分析、设计与实现基于 Linux 内核的命令解释程序(Shell),主要包括系统环境变量的设置和初始化、系统命令提示符显示、命令辨别解析(区分内部命令与外部命令及不同内部命令)、典型内部命令(譬如显示指定目录下文件列表、显示文本文件内容、文件拷贝、文件删除、空文件创建、日期设置/显示)处理等功能,并在 Linux 操作系统上测试验证。

实验过程

命令的设计与实现

下面是六条命令的设计与详情:

Table4:命令的设计
COMMAND TYPE1 TYPE2 EFFECT
cp 直接调用 内部命令 把A文件复制为B文件
rename 间接调用 内部命令 把文件A重命名为B
list 间接调用 内部命令 读取目录下文件列表
rm 间接调用 内部命令 删除文件
pwd 间接调用 内部命令 打印目前路径
spath 直接调用 外部命令 显示系统变量
exit 无调用 内部命令 退出

​ 采用C语言编写,为了实现相应的功能,头文件引用如下:

Table5:头文件引用
include describe
<stdio.h> 标准输入输出
<sys/types.h> 基本系统数据类型
<wait.h> 引用wait
<stdbool.h> c语言引用bool类型
<sys/syscall.h> 系统调用头文件
<string.h> 字符串操作
<stdlib.h> 定义杂项函数及内分配函数
<stddef.h>
<malloc.h> 动态存储分配函数头文件
<errno.h> 定义错误码
<unistd.h> unix 系统标准头文件
<libgen.h> 模式匹配函数定义
<sys/stat.h> 文件状态
<fcntl.h> 文件控制
<dirent.h> 目录项

详细的过程不贴了,把代码贴到最后吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#include <stdio.h>
#include <sys/types.h>
#include <wait.h>
#include <stdbool.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <malloc.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#define PWD_size 512
#define command_size 256
#define tmp_size 1024
// getcwd(buffer, sizeof(buffer));

bool command_switch(char *command); //对命令进行分流的子函数
bool command_list(char *command2, bool isPwd);
bool command_rename();
bool command_copyFile();
bool command_rm();
int command_systempath();
bool command_pwd();

int main()
{
while (1)
{
char pwd[PWD_size], command[command_size];
getcwd(pwd, sizeof(pwd));
printf("basher^%s>", pwd);
scanf("%s", command);
if (!strcmp(command, "exit"))
{
break;
}
else //对command进行分流处理
{
if (!command_switch(command))
printf("command Error\n");
fflush(stdin);
}
}
printf("Successfully Exit!\n");
return 0;
}

bool command_switch(char *command)
{
if (!strcmp(command, "list"))
{
char command2[command_size];
// printf("当前目录查询请输0,其他目录请输入路径>");
scanf("%s", command2);
if (!strcmp(command2, "0")) //缓冲区无字符
{
char pwd[PWD_size];
getcwd(pwd, sizeof(pwd)); //通过当前目录查找
command_list(pwd, 1);
}
else
{
command_list(command2, 0);
}
return 1;
}
else if (!strcmp(command, "rename")) //修改文件名
{
if (command_rename())
return 1;
else
return 0;
}
else if (!strcmp(command, "cp"))
{
if (command_copyFile())
return 1;
else
return 0;
}
else if (!strcmp(command, "rm"))
{
if (command_rm())
return 1;
else
return 0;
}
else if (!strcmp(command, "spath"))
{
if (command_systempath())
return 1;
else
return 0;
}
else if (!strcmp(command, "pwd"))
{
if (command_pwd())
return 1;
else
return 0;
}
else
return 0;
}

bool command_list(char *command2, bool isPwd)
{
struct dirent *entry;
DIR *olist = NULL;
int i = 1;
fflush(stdin);
if ((olist = opendir(command2)) == NULL)
{
printf("opendir false!\n");
return 0;
}
while (entry = readdir(olist))
{
if ((strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))) // 忽略掉上一目录和这一目录
{
printf("%s\n", entry->d_name);
i++;
}
}
if (closedir(olist) != 0 && !isPwd)
{
printf("closedir false!\n");
return 0;
}
return 1;
}
bool command_rename()
{
// 命令格式 rename 1.txt 2.txt
char newname[30], oldname[30];
scanf("%s", oldname);
scanf("%s", newname);
fflush(stdin);
if (rename(oldname, newname) != 0)
{
printf("change the new name false! \n");
return 0;
}
else
{
printf("change the new name success! \n");
return 1;
}
}

bool command_copyFile()
{
// 输入命令如下格式
// cp 1.txt 2.txt
// 直接调用
char cp1[30], cp2[30], buf[tmp_size];
int fd1, fd2;
int n;
bool flag = 1;
scanf("%s", cp1);
scanf("%s", cp2);
fflush(stdin);
if ((fd1 = syscall(SYS_open, cp1, O_RDONLY)) == -1)
{
printf("open the file false!");
flag = 0;
}
if ((n = syscall(SYS_read, fd1, buf, tmp_size)) == -1)
{
printf("read the first file false! \n");
flag = 0;
}
if ((fd2 = syscall(SYS_creat, cp2, 066)) == -1)
{
printf("create the file false!\n");
flag = 0;
}
if (syscall(SYS_write, fd2, buf, n) == -1)
{
printf("write the second file false!\n");
flag = 0;
}
if (syscall(SYS_close, fd1) == -1)
{
printf("close the first file false! \n");
flag = 0;
}
if (syscall(SYS_close, fd2) == -1)
{
printf("close the second file false! \n");
flag = 0;
}
if (flag)
{
printf("copy the new file success! \n");
}
return !flag;
}

bool command_rm()
{
char file_name[30];
scanf("%s", file_name);
fflush(stdin);
remove(file_name);
return 1;
}

int command_systempath()
{
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0)
{
execlp("env", "", NULL);
}
else
{
return 0;
// wait();
}
return 0;
}

bool command_pwd()
{
char pwd[PWD_size];
getcwd(pwd, sizeof(pwd)); //通过当前目录查找
printf("%s", pwd);
return 1;
}