设计概述
本设计要求在在Linux环境下模拟实现简单命令解释器(即定义一个命令使它具有Linux中某些命令的功能)例如:定义mylist使它具有list 的功能,即在Linux环境中 $ mylist 和 $list 作用一样。而本次设计需要实现的命令如下:
mypwd 显示当前所在目录的路径名
mymkdir 用于创建文件夹
myrmdir 用于删除目录
mycd 用于切换当前目录
mylist 列出指定目录名中的所有目录及文件
mycp 将源文件复制至目标文件,或将多个源文件复制至目标目录
mydate 显示或设定系统的日期与时间
mycreate 创建一个文本文件,该文本文件的内容为键盘上输入的一行或多行文字。
mydelete 删除一个文本文件
exit 退出命令解释程序
mymv 移动文件或修改文件名
myrm 删除一个目录中的一个或多个文件或目录,如果没有使用 -r 选项,则 rm 不会删除目录
myrename 重命名一个文件或目录
myfind 在指定的目录及其子目录中查找指定的文件(输入文件名),并输出查找到的文件的绝对路径
本人实现了所有的基本命令并实现了一部分扩展命令(myrename,myfind)但是mycp命令仅实现了将源文件复制至目标文件而没有实现将多个源文件复制至目标目录的作用,mydate命令没有实现设置系统的日期与时间仅实现了显示系统的时间。
二、操作系统相关原理
本次命令解释系统基本实现使用菜单方式实现将相关功能整合在一起并对其进行模块的划分;利用Linux系统下cmd.cpp 为本次课程设计的源文件,采用语言为C++执行命令g++ -o cmd cmd.cpp产生可执行文件:cmd在命令行键入:./cmd就可以直接运行
包含的头文件大多是Linux下c的函数库。通过调用相关的函数库来实现模拟shell命令操作。下面是对一些概念原理的说明:
- 源程序包含的头文件
#include <stdio.h>//主要方便使用一些c的函数
#include<iostream>//主要用于一些标准输入输出:cin,cout操作
#include<cstring>//标准C++函数库,主要用于字符串处理
#include<sys/types.h>//基本系统数据类型
#include<sys/stat.h>//文件状态
#include<dirent.h>//文件操作函数
#include<fcntl.h>//文件控制
#include<time.h>//定义关于时间的函数
#include<queue>队列相关
#include<stdlib.h>主要方便使用一些c的函数
#include<unistd.h>对 POSIX 操作系统 API 的访问功能的 头文件
#include<ftw.h>//对文件树进行漫游
以上是整个源程序涉及到的一些函数头文件
2.函数概念说明
以下是对程序调用Linux c函数库的方法说明:
调用getcwd()函数
函数原型:char * getcwd(char * buf,size_t size);
函数说明:getcwd()会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小。在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数size大小,则返回值NULL,errno的值则为ERANGE。倘若参数buf为NULL,getcwd()会依参数size的大小自动配置内存(使用malloc()),如果参数size也为0,则getcwd()会依工作目录绝对路径的字符串程度来决定所配置的内存大小,进程可以在使用完此字符串后利用free()来释放此空间。
返回值:执行成功则将结果复制到参数buf所指的内存空间,或是返回自动配置的字符串指针。失败返回NULL,错误代码存于errno。
调用opendir()函数
函数原型:DIR * opendir(const char * name);
函数说明:opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和open()类似,接下来对目录的读取和搜索都要使用此返回值。
返回值:成功则返回DIR* 型态的目录流,打开失败则返回NULL。
调用readdir()函数
函数原型:struct dirent * readdir(DIR * dir);
函数说明:readdir()返回参数dir目录流的下个目录进入点。
结构dirent定义如下
struct dirent
{
ino_t d_ino;
ff_t d_off;
signed short int d_reclen;
unsigned char d_type;
har d_name[256;
};
d_ino 此目录进入点的inode
d_off 目录文件开头至此目录进入点的位移
d_reclen _name的长度,不包含NULL字符
d_type d_name 所指的文件类型
d_name 文件名
返回值:成功则返回下个目录进入点。有错误发生或读取到目录文件尾则返回NULL。
附加说明:EBADF参数dir为无效的目录流。
调用closedir()函数
函数原型:int closedir(DIR *dir);
函数说明:closedir()关闭参数dir所指的目录流。
返回值:关闭成功则返回0,失败返回-1,错误原因存于errno 中。
调用chdir()函数
函数原型:int chdir(const char * path);
函数说明:chdir()用来将当前的工作目录改变成 以参数path所指的目录。
返回值:执行成功返回0,失败返回-1;
调用mkdir()函数
函数原型:int mkdir(const char *pathname, mode_t mode);
函数说明:mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
返回值:若目录创建成功,则返回0,否则返回-1;
调用rmdir()函数
函数原型:int _rmdir(const char *dirname);
函数说明:rmdir()函数删除以参数dirname为命名的目录。
返回值:若目录删除成功,则返回0,否则返回-1;
调用rename()函数
函数原型:int rename(const char * oldpath,const char * newpath);
函数说明:rename()会将参数oldpath 所指定的文件名称改为参数newpath所指的文件名称。若newpath所指定的文件已存在,则会被删除。
返回值:执行成功则返回0,失败返回-1。
调用ftw()函数
表头文件:#include <ftw.h>
函数原型:int ftw(const char *dir, int (*fn) (const *file, const struct stat *sb, int flag), int depth)
函数说明:ftw() 会从参数dir指定的 目录 开始,往下一层层地递归式遍历子 目录 。ftw()会传三个参数给fn(), 第一个参数*file指向当时所在的 目录 路径,第二个参数是*sb, 为stat结构指针,第三个参数为旗标,有下面几种可能值:
FTW_F 一般文件
FTW_D 目录
FTW_DNR 不可读取的 目录 ,此 目录 以下将不被遍历
FTW_SL 符号连接
FTW_NS 无法取得stat结构数据,有可能是 权限 问题
最后一个参数depth代表ftw()在进行遍历 目录 时同时打开的文件数。ftw()在遍历时每一层 目录 至少需要一个文件描述词,如果遍历时用完了depth所给予的限制数目,整个遍历将因不断地关文件和开文件操作而显得缓慢.
如果要结束ftw()的遍历,fn()只需返回一非零值即可,此值同时也会是ftw()的返回值。否则ftw()会试着走完所有的 目录 ,然后返回0.
返回值:遍历中断则返回fn()函数的返回值,全部遍历则返回0,若有错误发生则返回-1
三、概要设计
命令解释系统整体设计流程
Mypwd函数:
显示当前所在目录的路径名。
Mymkdir函数:
用于创建文件夹。
Myrmdir函数:
用于删除目录。
Mycd函数:
用于切换当前目录。
Mylist函数:
列出指定目录名中的所有目录及文件。
Mycp函数:
将源文件复制至目标文件,或至目标目录。
Mydate函数:
显示系统的日期与时间。
Mycreate函数:
创建一个文本文件,该文本文件的内容为键盘上输入的一行或多行文字。
Mydelete函数:
删除一个文本文件。
Exit命令:
退出命令解释程序。
Myrename函数:
重命名一个文件或目录。
Myfind函数:
在指定的目录及其子目录中查找指定的文件(输入文件名),并输入文件名。
四、详细设计和编码
Mypwd函数:
通过getcwd()函数返回显示当前所在目录的路径名
getcwd(ptr,sizeof(ptr)); //调用getcwd函数
cout<<ptr<<endl; //打印绝对路径
Mymkdir函数:
用于创建文件夹。
//如果mkdir函数执行成功返回0
if(mkdir(filename, 0777) == 0)
{
cout<<filename<<" indecates successful!!!"<<endl;
}
else
{ cout<<filename<<" indecates failure!!!"<<endl;
}
}
Myrmdir函数:
用于删除目录。
//如果删除成功返回0
if(rmdir(filename) == 0)
{
cout<<filename<<" delete successful!!!"<<endl;
}
else
cout<<filename<<" delete failure!!!"<<endl;
}
Mycd函数:
用于切换当前目录。
如果chdir函数转换失败的话返回-1
if(chdir(dirname) == -1)
主要借助操作系统本身的chdir函数
Mylist函数:
列出指定目录名中的所有目录及文件。
cin>>dirname;
dir = opendir(dirname);
if(dir == NULL)
{
cout<<"cannot open directory"<<endl;
}
//opendir 函数打开并返回一个目录流,用于读取文件名为 dirname 的字符串
//readdir 函数从目录中读取下一个条目。
while((ptr = readdir(dir)) != NULL)
{ // if the d_name is equal with "." or ".." ,do nothing
if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0){}
// if not , print the ptr->d_name
else
cout<<ptr->d_name<<" ";
// count the d_name
count++;
// if count % 8 == 0, line feed
if(count % 8 == 0)
cout<<endl;
}
// 关闭该目录
closedir(dir);
Mycp函数:
将源文件复制至目标文件,或至目标目录。
FILE *fp = NULL; //源文件
FILE *fp1 = NULL; //复制文件
char temp[200]; //复制生成文件的目录路径
fp = fopen(b, "r");
//如果第二个字段是路径
if ((dir = opendir(temp)) != NULL)
{
chdir(temp); //存在该目录,改变为此目录
fp1 = fopen(b, "a"); //路径
}
else
{
/* code */
//copy <已存在的文件名> <副本文件名>
fp1 = fopen(a, "a"); //副本文件名
}
char buff[255];
while (!feof(fp)) //判断文件内容是否为空
{
/* code */
fgets(buff, 255, fp); //读取文件
fputs(buff, fp1); //写入文件
}
fclose(fp); //关闭文件
fclose(fp1);
主要借助opendir和文件指针(fget,fputs)实现。
Mydate函数:
显示系统的日期与时间。
time_t timeval;
(void)time(&timeval);
string timestr;
// 借助ctime函数然后返回字符串
timestr = ctime(&timeval);
cout<<"The date is: "<<timestr<<endl;
Mycreate函数:
创建一个文本文件,该文本文件的内容为键盘上输入的一行或多行文字。
fileP=fopen(a1,"w");
cout<<"输入内容 先输入需要多少行"<<endl;
cin>>N;
cin.ignore(); //取消换行键的读入
string strCinLine[100];
for(int i =0;i<N;i++)
{
getline(cin,strCinLine[i]);
fputs(strCinLine[i].c_str(),fileP);
fputs("\n",fileP);
}
fclose(fileP);
借助文件指针和getline函数。
Mydelete函数:
删除一个文本文件。
gets(filename);//输入文件名
if (remove(filename) == 0)
{
printf("Removed %s.", filename);
}
else
{
perror("remove");
}
Exit命令:
输入exit退出命令解释系统。
Myrename函数:
重命名一个文件或目录。
// 如果重命名成功返回 0
if(rename(filename1, filename2) == 0)
Myfind函数:
在指定的目录及其子目录中查找指定的文件(输入文件名),并输入文件名。
int fn(const char *file, const struct stat *sb, int flag)
{
if(flag == FTW_D)
cout << file <<"-- directory"<<endl;
else if(flag == FTW_F)
cout << file <<"-- file"<<endl;
return 0;
}//遍历每个图层目录并打印文件
五、系统测试
菜单界面:
- Linux系统下的菜单界面
Mypwd:
- 显示cmd文件当前路径
Mylist
3.显示该目录的内容
Mycd
4.切换目录
Mymkdir
5.创建文件夹
Myrmdir
6.删除文件夹
Myrename
7.重命名文件夹
Myfind
8.找到文件所在位置
Mydate
9.显示时间
mycp
10.复制文本文件
Mycreate
11.创建文本文件
Mydelete
12.删除文本文件
Exit
13退出命令