Linux下的简单解释器

2018-12-11  本文已影响0人  素白的霏丶

一、程序概述

1. 基本概述

这次大作业是在centos 7系统下完成的,使用的编程语言为:c++。

打开方式

存放路径为:/home/null/workspace

2. 实现功能

完成了要求实现的基本命令及部分可选做的扩展命令

1、pwd  //显示当前所在目录的路径名

2、list  <目录名>          //列出指定目录名中的所有目录及文件

3、cd  <目录名或路径>   //改变当前工作目录

4、mkdir<目录名>     //新建目录

5、rmdir  <目录名>      //删除目录

6、exit                 //退出命令解释程序

7、rename <旧文件名> <新文件名>  //重命名一个文件或目录

8、copy <已存在的文件名及其路径> <副本文件名及其路径>  //复制一个已存在的文件

二、设计思路

本次大作业要求使用c++,而且必须在linux的环境下操作,于是我使用了很多在linux下的函数库。

1、函数说明

1、getcwd()函数

char * getcwd(char * buf,size_t size);

getcwd()会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小。

用于实现pwd的命令解释,显示当前目录所在的文件名。

2、opdir()函数&readdir()函数&closedir()函数

DIR *opendir(const char *name);

它返回一个DIR*类型,这是一个句柄,并且这个句柄要传给reddir函数。

struct dirent *readdir(DIR *dir);

该参数是opendir函数返回的句柄,而该函数的返回值是struct dirent* 类型。

该结构体:

struct dirent {

ino_t          d_ino;       /* inode number */

off_t          d_off;       /* offset to the next dirent */

unsigned short d_reclen;    /* length of this record */

unsigned char  d_type;      /* type of file */

char           d_name[256]; /* filename */

};

这个结构体的d_name存放的就是文件的名字,这里的文件包括普通文件,目录文件等等,在linux的思想中,所有的东西都是文件。

int closedir(DIR *dir);

在结束时使用,用于关闭dir。

用于实现list的命令解释,列出指定目录名中的所有目录及文件。

3、chdir()函数

int chdir (const char *pathname);

进程调用该函数可以改变当前工作目录

用于实现cd的命令解释,改变当前工作目录。

4、mkdir()函数

int mkdir(const char *pathname, mode_t mode);

用mode的方式创建以pathname命名的目录。如/home/null/helloworld 创建的文件夹名字则为helloworld。mode用于定义创建目录的权限 如 :

//00700权限,代表该文件所有者拥有读,写和执行操作的权限

//00070权限,代表该文件用户组拥有读,写和执行操作的权限

而我使用的mode_t 0777为八进制 转换成二进制为 000 111 111 111 对应为可读可写可执行,

每三个为一组。 分别为文件所有者,用户者,其他用户。即所有用户拥有可读可写可执行的权限。

用于实现mkdir的命令解释,新建目录。

5、rmdir()函数

int _rmdir(const char *dirname);

调用该函数删除dirname的目录

用于实现rmdir的命令解释,删除目录。

6、rename()函数

int rename(const char * oldpath,const char * newpath);

调用该函数将参数为oldpath的文件重命名为参数为newpath的文件,若newpath所指定的文件已存在,则会被删除。

用于实现rename的命令解释,删除目录。

7、open()函数&read()函数&write()函数

int open(constchar* pathname,int flags,mode_tmode);其中最后一项为可选项。

调用该函数可以打开参数为pathname的文件,参数flag可以决定用什么方式打开文件。eg:

O_RDONLY 以只读方式打开文件。

O_WRONLY 以只写方式打开文件。

O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。

O_CREAT 若欲打开的文件不存在则自动建立该文件。

ssize_t  read(int fd,void * buf ,size_t count);

调用该函数可以由已打开的文件读取数据。read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中。若参数count为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。简单来说就是从fd中调count个字节到缓冲字符区buf中。

ssize_t write (int fd,const void * buf,size_t count);

调用该函数参数buf所指的内存(read中的缓冲区)写入count个字节到参数fd所指的文件内。

用于实现copy的命令解释,复制一个已存在的文件。

三、详细设计

程序设计流程图

1、int main()

while(1) {

      //shell prompt

      cout<<"[null@]$";

      cin>>str;   

if(str == "pwd"){

        pwd();}

      else if(str == "list"){

        list();}

.....}

如流程图所示,在输出提示后则进入一个死循环给str赋值,当输入的str为可执行命令时则进入函数,执行完毕后等待下一个命令。

2、void pwd();

显示当前绝对工作路径。

char ptr[40];

 getcwd(ptr,sizeof(ptr)); 

 cout<<ptr<<endl; 

调用getcwd()函数,直接获取当前路径至ptr中,直接输出即可。

3、int list();   

列出指定目录名中的所有目录及文件。

    char path[20];

    cin>>path;   

    // char path[]="/home/null/workspace";

    const char *ptr=path;  //进入函数后,输入路径保存在path中,并转换为opdir支持的const char格式。

    DIR *dir; //声明一个句柄'dir'

    struct dirent *file; //readdir函数的返回值就存放在这个结构体中,所要查找的文件名也放在这里,用指针的方式就可以查找。

    int len = 0;

    int i;

    char filename[256][256];

    if(!(dir = opendir(ptr))) //如果需要打开的目录不存在

    {

      // printf("error path : %s!\n",path);

        cout<<"error path:"<<path<<endl; //输出错误的路径

        return -1;}

    while((file = readdir(dir)) != NULL)

    {

        if(strncmp(file->d_name, ".", 1) == 0) //把当前目录'.',上一级目录'..'去除

            continue;

        strcpy(filename[len++], file->d_name); //保存遍历到的文件名}

    closedir(dir); //关闭dir流

    for(i = 0; i < len; i++)

    {cout<<filename[i]<<" ";}

    cout<<endl;

    return 0;

进入函数后,需要输入查找得目录的绝对路径path,若opendir返回值为0,即打开目录错误,则输出错误路径,跳出函数。若打开成功则跳过if语句。随后执行 while((file = readdir(dir)) != NULL)语句,当读出来的file不为空则一直循环。第一个if语句是把所有'.'开头文件及文件夹去掉,因为在Linux中‘.’ ‘..’ ‘.xxx’为当前目录,上一级目录及隐藏文件,不符合我们要查找的内容。执行完循环后则输出查找到的文件夹并退出循环。

4、void cd();

改变当前工作目录

  char dirname[20];

  cin>>dirname;

  if(chdir(dirname) == -1)

  {  cout<<"the directory isn't exit!"<<endl; }

输入要进入的目录,调用linux c函数库的chdir()函数执行chadir命令。若返回值为1则cd命令输入错误(文件夹不存在)。

5、void _mkdir();

新建目录

  char filename[20]; cin >> filename;

  if(mkdir(filename, 0777) == 0)  {

    cout<<filename<<" created successful!"<<endl;}

  else {  cout<<filename<<" created unsuccessful!"<<endl;}

输入要创建的文件夹名称,调用linux c函数库的mkdir()函数执行makedir命令。若返回值为0则mkdir命令执行成功。

6、void _rmdir();

删除目录

char filename[20];

  cin >> filename;

  if(rmdir(filename) == 0)   {

    cout<<filename<<" deleted successful!"<<endl;}

  else  cout<<filename<<" deleted unsuccessful!"<<endl;

输入要删除的文件/文件夹名称,调用linux c函数库的rmdir()函数执行deldir命令。若返回值为0则deldir命令执行成功。

7、void _rename();

重命名一个文件或目录

  char filename[20], filename1[20];

  cin>>filename>>filename1;

  if(rename(filename,filename1) == 0)

  {  cout<<"changed successful!"<<endl;}

  else cout<<"changed unsuccessful!"<<endl;

输入要重命名的旧文件/文件夹名称以及新文件/文件夹名称,调用linux c函数库的rename()函数执行rename命令。若返回值为0则rename命令执行成功。

8、void copy();

复制一个已存在的文件

char src[20],des[20];

char buff[1024];

int temp; //读出了多少个字节

cin>>src>>des;

int fd,fd2;

fd = open(src,O_RDWR|O_CREAT);

fd2 = open(des,O_RDWR|O_CREAT);

while(temp = read(fd,buff,1024))

{write(fd2,buff,temp);}

 cout<<"copy successful!"<<endl;

输入需要复制的文件路径赋值至src,输入需要将复制的文件到的绝对路径至des。用open函数以O_RDWR|O_CREAT的旗标打开这两个路径 。O_RDWR|的含义是以可读写方式打开文件。O_CREAT 的含义是若欲打开的文件不存在则自动建立该文件。将fd的文件每次以1024个字节读入缓冲数组buff中,并用temp读出返回值(读了多少个字节),再将fd的文件以每次temp个字节将buff中的数组写入fd2中。

缺点:检测不到复制失败的情况。

四、使用情况

打开解释器 pwd命令 list命令 mkdir命令 rename命令 remdir命令 copy命令

五、小结

1、遇到的困难

写了一段时间的python对于这种接近底层的语言感到陌生,c++不像别的语言一样可以有很多打包好的方便的方法,也不像python一样可以不用定义数据类型的使用数据。就算有别人打包好的函数,还是有很多算法都是要自己去写的,而在linux系统下写这份大作业更是需要花时间去理解Linux c函数,不仅要理解函数的调用还要理解参数的意义和不同情况下的函数返回值。虽然一开始有一头雾水的感觉,但在查阅了资料和文档后还是能够实现要求的指令的。

2、总结和感想

一开始的时候,在装虚拟机和系统都费了不少的心思,比如虚拟机要破解、系统有各式各样的Linux系统,(如Linux Ubuntu 、Centos等等)、装系统的时候装了minimal 只有一个黑框框完全不知道该怎么办,即使查阅了网上的Linux的命令大全也不知道要怎么样才能编译c程序。后来通过看教学视频(腾讯课堂)和上机实验明白了要如何编译使用C程序和熟悉了一些基本的Linux的命令,迷上了vi编辑器。虽然很难用,但用得好只用键盘就能完成以前要鼠标点来点去的操作,是一个能实实在在的提高写代码效率的编辑器。也能理解为什么有人那么喜欢Linux系统了哈哈。虽然我为了明天能交作业用的是gedit

六、参考链接

https://blog.csdn.net/wwj_748/article/details/8309440

https://www.cnblogs.com/ace-wu/p/6640186.html (open write read )

https://blog.csdn.net/u014453898/article/details/54864666(linux下的c语言复制方法)

https://blog.csdn.net/qq_30941699/article/details/55517763(linux下c语言递归法查找文件,并打印绝对地址)

https://blog.csdn.net/silentob/article/details/76994618(const char * 、char const *、 char * const 三者的区别)

https://www.cnblogs.com/avril/archive/2010/03/22/1691477.html(int  main(int  argc,  char*  argv[])详解)

https://blog.csdn.net/jichl/article/details/7948724(ftw遍历目录树)

七、源代码

#include<iostream>

#include<cstring>

#include<sys/types.h>

#include<sys/stat.h>

#include<dirent.h>

#include<stdlib.h>

#include<fcntl.h>

#include<time.h>

#include<queue>

#include<ftw.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

using namespace std;

//declare method

void pwd();   

int list();    

void cd();     

void _mkdir();

void _rmdir();

void _rename();

void copy();

int main()

{

cout<<"可执行的命令:"<<endl;

cout<<"pwd                                         //显示当前所在目录的路径名"<<endl;

cout<<"list     <目录名>                            //列出指定目录名中的所有目录及文件"<<endl;

cout<<"cd       <目录名或路径>                       //改变当前工作目录"<<endl;

cout<<"mkdir    <目录名>                            //新建目录"<<endl;

cout<<"rmdir    <目录名>                            //删除目录"<<endl;

cout<<"rename   <旧文件名> <新文件名>                 //重命名一个文件或目录"<<endl;

cout<<"copy      <已存在的文件名及其路径> <副本文件名及其路径>    //复制一个已存在的文件"<<endl;

cout<<"rmdir    <目录名>                            //删除目录"<<endl;

// cout<<"find     <目录> -name <待查找的文件名>         //在指定的目录及其子目录中查找指定的文件,并输出查找到的文件的绝对路径。"<<endl;

cout<<"exit                                        //退出命令解释程序"<<endl;

   string str;

   while(1) {

      //shell prompt

      cout<<"[null@]$";

      cin>>str;     

/*

      switch(str){

    case "pwd":

          pwd();

          break;

    default:

    cout<<"no command not found"<<endl;

}

*/

      if(str == "pwd"){

         pwd();}

      else

      if(str == "list"){

         list();}

      else

      if(str == "cd"){

         cd();}

      else

      if(str == "mkdir"){

         _mkdir();}

      else

      if(str == "rmdir"){

         _rmdir();}

      else

      if(str == "rename"){

         _rename();}

      else

      if(str =="copy"){

         copy();}

      else

      if(str=="exit"){

         break;}

      else

      cout<<"no command not found"<<endl;

                        }

    return 0;

}

void pwd()

{

   char ptr[40];  

   getcwd(ptr,sizeof(ptr));   

   cout<<ptr<<endl;  

}

int list()

{

    char path[20];

    cin>>path;

//    char path[]="/home/null/workspace";

    const char *ptr=path;

    DIR *dir; //声明一个句柄'dir'

struct dirent *file; //readdir函数的返回值就存放在这个结构体中

    int len = 0;

    int i;

    char filename[256][256];

if(!(dir = opendir(ptr))) //如果需要打开的目录不存在

    {

       // printf("error path : %s!\n",path);

        cout<<"error path:"<<path<<endl;

        return -1;

    }

    while((file = readdir(dir)) != NULL)

    {

        if(strncmp(file->d_name, ".", 1) == 0) //把当前目录'.',上一级目录'..'去除

            continue;

strcpy(filename[len++], file->d_name); //保存遍历到的文件名

    }

    closedir(dir);

    for(i = 0; i < len; i++)

    {

        cout<<filename[i]<<" ";

    }

    cout<<endl;

    return 0;

}

void cd()

{

   char dirname[20];

   cin>>dirname;

   if(chdir(dirname) == -1)

   {

      cout<<"the directory isn't exit!"<<endl;

    }

}

void _mkdir()

{

  char filename[20];

  cin >> filename;

  if(mkdir(filename, 0777) == 0)

  {

     cout<<filename<<" created successful!"<<endl;

   }

   else

   {  cout<<filename<<" created unsuccessful!"<<endl;

   }

}

void _rmdir()

{

   char filename[20];

   cin >> filename;

   if(rmdir(filename) == 0)

   {

    cout<<filename<<" deleted successful!"<<endl;

   }

   else

    cout<<filename<<" deleted unsuccessful!"<<endl;

}

void _rename()

{

  char filename[20], filename1[20];

  cin>>filename>>filename1;

  if(rename(filename,filename1) == 0)

  {

    cout<<"changed successful!"<<endl;

   }

   else

     cout<<"changed unsuccessful!"<<endl;

}

void copy(){

char src[20],des[20];

char buff[1024];

int temp; //读出了多少个字节

cin>>src>>des;

// char const *src_path = argv[1];

// char const *des_path = argv[2];

int fd,fd2;

fd = open(src,O_RDWR|O_CREAT);

fd2 = open(des,O_RDWR|O_CREAT);

while(temp = read(fd,buff,1024))

{

write(fd2,buff,temp);

}

}

上一篇下一篇

猜你喜欢

热点阅读