Project2:用C语言实现自己的ls命令/my_ls

本文详细介绍了如何使用C语言在GNU/Linux系统中模拟ls命令,涵盖-a、-l、-R、-t、-r、-i、-s参数的功能,并探讨了关键实现技巧和参考书籍。通过递归、stat函数和目录遍历,实现文件信息的详细展示和排序。

目录

一、任务说明

二、命令解析

三、命令终端效果展示

四、大致实现思路

五、棘手点

六、一些小点

七、参考书籍

八、代码展示part

九、总结


一、任务说明

lsGNU/Linux 操作系统中常见的命令。请使用 C 语言,基于 GNU/Linux 操作系统,编程实现 ls 命令的 部分 功能,包括实现 ls 的 -a、-l、-R、-t、-r、-i、-s 参数。


二、命令解析

-a列出目录下的所有文件,包括以.开头的隐含文件
-l列出文件的详细信息(包括文件属性和权限等)
-R使用递归连同目录中的子目录中的文件显示出来,如果要显示隐藏文件就要添加-a参数(列出所有子目录下的文件)
-t按修改时间进行排序,先显示最后编辑的文件
-r对目录反向排序(以目录的每个首字符所对应的ASCII值进行大到小排序)
-i输出文件的i节点的索引信息
-s在每个文件名后输出该文件的大小

三、命令终端效果展示

-a--->列出目录下的所有文件

-l+文件名--->列出文件的详细信息

-R--->列出目录中子目录下的所有文件

(目录子目录文件过多,在此不进行全部展示)

-t--->按修改时间,由近到远进行排序

  -r--->以目录的每个首字符所对应的ASCII值进行大到小排序

 -i--->输出文件的i节点的索引信息

-s--->在每个文件名后输出该文件的大小


 四、大致实现思路

  1. 先通过终端调用命令后,观察其输出内容的格式;
  2. 然后逐个分析实现参数,分块完成;
  3. 每个参数在整体实现中用自定义函数的形式独立完成,结合作用函数。

五、棘手点

  • 整套ls实现的构造框架和设计
  • -R需要对根目录进行查询,且需要用到递归
  • 细节点很多,需要处处注意
  • 参数与参数之间的优先级需要好好考虑,写嵌套时顺序不要出错

六、一些小点

1、文件名的获取

可以使用函数opendir和readdir打开文件,使用完后需要用closedir关闭:

(1)opendir函数

头文件#include <sys/types.h>  #include <dirent.h>
函数DIR *opendir(const char *name)
含义用来打开参数name 指定的目录, 并返回DIR*形态的目录流, 和open()类似, 接下来对目录的读取和搜索都要使用此返回值.

其中DIR这一结构体的定义:

struct __dirstream   
   {   
    void *__fd;    
    char *__data;    
    int __entry_data;    
    char *__ptr;    
    int __entry_ptr;    
    size_t __allocation;    
    size_t __size;    
    __libc_lock_define (, __lock)    
   };   
  
typedef struct __dirstream DIR;  

函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:

struct dirent *readdir(DIR *dp);   
void rewinddir(DIR *dp);   
int closedir(DIR *dp);   
long telldir(DIR *dp);   
void seekdir(DIR *dp,long loc);  

(2)readdir函数

头文件#include<sys/types.h> #include <dirent.h>
函数struct dirent *readdir(DIR *dir);
含义返回参数dir 目录流的下个目录进入点

dirent这一结构体的定义:

struct dirent
{
    ino_t d_ino;                 //d_ino 此目录进入点的inode
    ff_t d_off;                  //d_off 目录文件开头至此目录进入点的位移
    signed short int d_reclen;   //d_reclen _name 的长度, 不包含NULL 字符
    unsigned char d_type;        //d_type 所指的文件类型 
    har d_name[256];             //d_name 文件名
};

(3)closedir函数 

头文件#include<sys/types.h> #include <dirent.h>
函数closedir(DIR *dir);
含义关闭dir流

2、stat函数

函数原型:int stat(const char *path, struct stat *buf);

其中path为文件名,struct stat * buf是一个保存文件状态信息的结构体,其类型如下:

struct stat{
	dev_t       st_dev;       //文件的设备编号
	ino_t       st_ino;       //文件的i-node(i节点编号)
	mode_t      st_mode;      //文件的类型和存取权限,它的含义与chmod,open函数的mode参数相同
	nlink_t     st_nlink;     //连到该文件的硬件链接数目,刚建立的文件值为1.
	uid_t       st_uid;       //文件所有者的用户ID
	gid_t       st_gid;       //文件所有组的组ID
	dev_t       st_rdev;      //若此文件为设备文件,则为其设备编号
	off_t       st_size;      //文件大小,以字节计算,对符号链接,该大小是其所指向文件名的长度
	blksize_t   st_blksize;   //文件系统的I/O缓存区大小
	blkcnt_t    st_blocks;    //占用文件区块的个数,每一区块大小通常为512个字节
	time_t      st_atime;     //文件最后一次被访问的时间
	time_t      st_mtime;     //文件最后一次被修改的时间,一般只能调用utime和write函数时才会变化
	time_t      st_ctime;     //文件最近一次被修改的时间,此参数在文件所有者、所属组、文件权限被更改时更新
}

结构体的成员较多,但有的很少使用

常用的有:st_mode、st_uid、st_gid、st_size、st_atime、st_mtime

对于st_mode包含的文件类型信息,POSIX标准定义了一系列的宏:

    S_ISLNK(st_mode): 判断是否为符号链接
    S_ISREG(st_mode):判断是否为一般文件
    S_ISDIR(st_mode):判断是否为目录文件
    S_ISCHR(st_mode):判断是否为字符设备文件
    S_ISBLK(st_mode):判断是否为快设备文件
    S_ISFIFO(st_mode):判断是否为先进先出FIFO
    S_ISSOCK(st_mode):判断是否为socketP


七、参考书籍

Linux-UNIX系统编程手册(上、下册) by Michael Kerrisk


八、代码展示part

/*
***-a 列出目录下的所有文件,包括以.开头的隐含文件
***-l 列出文件的详细信息(包括文件属性和权限等)
***-R 使用递归连同目录中的子目录中的文件显示出来,如果要显示隐藏文件就要添加-a参数
   (列出所有子目录下的文件)
-t 按修改时间进行排序,先显示最后编辑的文件
-r 对目录反向排序(以目录的每个首字符所对应的ASCII值进行大到小排序)
***-i 输出文件的i节点的索引信息
-s 在每个文件名后输出该文件的大小
*/
/*
struct stat name
{
    dev_t     st_dev;    //文件的设备编号
    int_t     st_ino;     //节点
    mode_t    st_mode;   //文件的类型和存取的权限
    nlink_t   st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t     st_uid;        //用户ID
    gid_t     st_gid;        //组ID
    dev_t     st_rdev;     //(设备类型)若此文件为设备文件,则为其设备编号
    offf_t    st_size;      //文件字节数(文件大小)
    unsigned  long st_bilsize;   //块大小(文件系统的I/O缓存区大小)
    unsigend  long st_blocks;   //块数
    time_t    st_atime;  //最后一次访问时间
    time_t    st_mtime; //最后一次修改时间
    time_t    st_ctime;   //最后一次改变时间(指属性)
}
*/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<dirent.h>
#include<glob.h>
#include<stdlib.h>
#include<stdbool.h>

#define A 0
#define L 1
#define R 2
#define I 3
#define S 4
#define T 5
#define BULE 34
#define GREEN 32

struct file
{
    char filename[256];
    struct stat STA;
};
void LS_I(struct stat *STA);
void LS_S(struct stat *STA);
void LS_T(struct file *STA,int len);
void MODE(int mode, char str[]);
char* UID(uid_t uid);
char* GID(gid_t gid);
void show_file(struct stat* STA);

//获取当前路径打印文件名
void list(bool* name,int size)
{
    DIR *dir =NULL;
    struct dirent *ptr;
    char ch = '0';
    char buf[32] = {0};
    char pathname_buf[256];

    getcwd(pathname_buf,sizeof(pathname_buf));  //获取当前路径
    dir=opendir(pathname_buf);  //返回目录流

    if(dir == NULL) //如果路径为空,返回错误
    {
        printf("error!cannot open the file\n");
        exit(-1);
    }
    struct stat s_buf;
    int stat_buf;
    int i=0,j=0;
    
    //buf->st_mtime 最后一次修改时间

    struct file* buff = malloc(sizeof(struct file)*100);
    struct file* temp = buff;  //还原
    while((ptr = readdir(dir))!= NULL)
    {
        if(name[A] == false)
        {
            if(ptr->d_name[0] == '.')
            {
                continue;
            }
        }
        stat_buf=stat(ptr->d_name, &(buff->STA));
        strcpy(buff->filename,ptr->d_name);
        //printf("%s ", buff->filename);
        buff++; //指针后移
        j++; //记录文件数
    }
    buff = temp;  //指向开始
    if(name[T] == true)
    {
        LS_T(buff, j);
    }
    for(i=0;i<j;i++)
    {
        if(name[S] == true)
        {
            LS_S(&(buff+i)->STA);
        }
        if(name[I] == true)
        {
            LS_I(&(buff+i)->STA);
        }
        if(name[L] == true)
        {
            printf("\n");
            show_file(&(buff+i)->STA);
        }

        //输出
        if(S_ISDIR(buff->STA.st_mode))
        {
            //目录
            COLOR(BULE);
            printf("%5s",(buff+i)->filename);
        }else if(buff->STA.st_mode & S_IXGRP)
        {
            //可执行文件(位运算?)
            printf("....");
            COLOR(GREEN);
            printf("%5s",(buff+i)->filename);
        }else if(S_ISREG(buff->STA.st_mode))
        {
            //普通文件
            printf("......................");
            printf("   %5s",(buff+i)->filename);
        }
        //printf("  %5s",(buff+i)->filename);  //输出文件名

        if(i % 5 ==0 && name[L] != true)
        {
            printf("\n");
        }
    }
    if(name[R] == true)  //-R递归
    {
        int i=0;
        printf("\n");
        for(;i<j;i++)
        {
            printf("%s:\n",(buff+i)->filename);
            list(&(name[I]),3);
        }
    }
    printf("\n");
    closedir(dir);
}

/*
字颜色:
普通文件白色
32:绿色(可执行文件)
34:蓝色(目录文件):函数S_ISDIR()判断
*/
void COLOR(int color)
{
    printf("\033[%dm",color);
}

// 展示单个文件的详细信息 -l 
void show_file(struct stat* STA)  
{
    char modestr[11];  //存放权限
    //权限
    MODE((int)STA->st_mode, modestr);
    //连到该文件的硬连接数目,刚建立的文件值为1
    printf(" %5d", (int) STA->st_nlink);
    //用户
    printf(" %5s", UID(STA->st_uid));
    //用户组
    printf(" %5s", GID(STA->st_gid));
    //文件大小
    printf(" %5ld", (long) STA->st_size);
    //ctime:最后一次改变文件内容或目录内容的时间
    char buf_time[32];
    strcpy(buf_time, ctime(&(STA->st_mtime)));
    buf_time[strlen(buf_time) - 1] = '\0';
    printf(" %5s",buf_time);
    //文件名字
    //printf(" %20s\n", filename);
}

//文件权限
void MODE(int mode, char str[])
{  
    strcpy(str, "----------");  //初始化全为---------- 
      
    if(S_ISDIR(mode))   //是否为目录
    {  
        str[0] = 'd';  
    }  
      
    if(S_ISCHR(mode))  //是否为字符设置
    {  
        str[0] = 'c';  
    }  
      
    if(S_ISBLK(mode))  //是否为块设备
    {  
        str[0] = 'b';  
    }

    //逻辑与
    /*
        S_IRUSR:用户读权限
        S_IWUSR:用户写权限
        S_IRGRP:用户组读权限
        S_IWGRP:用户组写权限
        S_IROTH:其他组都权限
        S_IWOTH:其他组写权限
    */
    if((mode & S_IRUSR))  
    {  
        str[1] = 'r';  
    }  
    if((mode & S_IWUSR))  
    {  
        str[2] = 'w';  
    }
    if((mode & S_IXUSR))  
    {  
        str[3] = 'x';  
    }  
    if((mode & S_IRGRP))  
    {  
        str[4] = 'r';  
    }  
    if((mode & S_IWGRP))  
    {  
        str[5] = 'w';  
    }
    if((mode & S_IXGRP))  
    {  
        str[6] = 'x';  
    }  
    if((mode & S_IROTH))  
    {  
        str[7] = 'r';  
    }  
    if((mode & S_IWOTH))  
    {  
        str[8] = 'w';  
    }  
    if((mode & S_IXOTH))  
    {  
        str[9] = 'x';  
    }

    printf("%s ",str);
} 

//通过uid和gid找到用户名字和用户组名字    
char* UID(uid_t uid)
{  
    struct passwd* getpwuid(),* pw_ptr;  
    static char numstr[10];  
      
    if((pw_ptr = getpwuid(uid)) == NULL)  
    {  
        sprintf(numstr,"%d",uid);
        return numstr;
    }  
    else  
    {  
        return pw_ptr->pw_name;
    }  
}       
char* GID(gid_t gid)
{  
    struct group* getgrgid(),* grp_ptr;  
    static char numstr[10];  
      
    if(( grp_ptr = getgrgid(gid)) == NULL)  
    {  
        sprintf(numstr,"%d",gid);  
        return numstr;  
    }  
    else  
    {  
        return grp_ptr->gr_name;  
    }  
}  

//打印i节点 -i
void LS_I(struct stat *STA)
{
    printf("%ld ", STA->st_ino);
}

//文件大小 -s
void LS_S(struct stat *STA)
{
    printf("%ld ",( long )STA->st_size);
}

//-t 进行排序
void LS_T(struct file *FILE,int len)
{
    for(int i=1;i<=len-1;i++)
    {

        for(int j=1;j<len-i;j++)
        {

            if(FILE[i].STA.st_mtime<FILE[j].STA.st_mtime)//char* a; a-> = (*a)
            {
				struct file n = FILE[i];
				FILE[i] = FILE[j];
				FILE[j] = n;
            }
        }
    }
}

int main(int argc,char** argv)
{
    // ./ls5 -xxxxx
    int i;
    int command[10]={0};
    int num=strlen(argv[1]);
    printf("%s %s",argv[0],argv[1]);
    for(i=0;i<num;i++)
    {
        if(argv[1][i]=='a')
        {
            command[A]++;
        }else if(argv[1][i]=='l')
        {
             command[L]++;
        }else if(argv[1][i]=='R')
        {
            command[R]++;
        }else if(argv[1][i]=='i')
        {
            command[I]++;
        }else if(argv[1][i]=='s')
        {
            command[S]++;
        }else if(argv[1][i]=='t')
        {
            command[T]++;
        }else{
            printf("错误!\n");
            return -1;
        }
    }

    /*for(i=0;i<6;i++)
    {
        printf("\n%d ",command[i]);
    }*/

    bool sum[6]={false};  //布尔数组判断其真值
    for(i=0;i<6;i++)
    {
        if(command[i]!=0)
        {
            sum[i]=true;
        }
        //printf("\n%d ",sum[i]);
    }
    list(sum,6);
    return 0;
}

九、总结

面向项目学东西,活学活用是个很快速且有效的学习方法。

确定了方向接下来就要全力以赴了,高产博主恢复上线!!

ERROR: device-tree-xilinx-v2020.2+gitAUTOINC+f725aaecff-r0 do_compile: Error executing a python function in exec_python_func() autogenerated: The stack trace of python calls that resulted in this exception/failure was: File: 'exec_python_func() autogenerated', lineno: 2, function: <module> 0001: *** 0002:devicetree_do_compile(d) 0003: File: '/home/ljj/petalinux/csl_zynqsys_1/components/yocto/layers/core/meta/classes/devicetree.bbclass', lineno: 131, function: devicetree_do_compile 0127: if not(os.path.isfile(dtspath)) or not(dts.endswith(".dts") or devicetree_source_is_overlay(dtspath)): 0128: continue # skip non-.dts files and non-overlay files 0129: except: 0130: continue # skip if can't determine if overlay *** 0131: devicetree_compile(dtspath, includes, d) 0132:} 0133: 0134:devicetree_do_install() { 0135: for DTB_FILE in `ls *.dtb *.dtbo`; do File: '/home/ljj/petalinux/csl_zynqsys_1/components/yocto/layers/core/meta/classes/devicetree.bbclass', lineno: 119, function: devicetree_compile 0115: dtcargs += ["-i", i] 0116: dtcargs += ["-o", "{0}.{1}".format(dtname, "dtbo" if isoverlay else "dtb")] 0117: dtcargs += ["-I", "dts", "-O", "dtb", "{0}.pp".format(dts)] 0118: bb.note("Running {0}".format(" ".join(dtcargs))) *** 0119: subprocess.run(dtcargs, check = True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 0120: 0121:python devicetree_do_compile() { 0122: includes = expand_includes("DT_INCLUDE", d) 0123: listpath = d.getVar("DT_FILES_PATH") File: '/opt/pkg/petalinux/2020.2/components/yocto/buildtools/sysroots/x86_64-petalinux-linux/usr/lib/python3.7/subprocess.py', lineno: 512, function: run 0508: raise 0509: retcode = process.poll() 0510: if check and retcode: 0511: raise CalledProcessError(retcode, process.args, *** 0512: output=stdout, stderr=stderr) 0513: return CompletedProcess(process.args, retcode, stdout, stderr) 0514: 0515: 0516:def list2cmdline(seq): Exception: subprocess.CalledProcessError: Command '['dtc', '-@', '-p', '0x1000', '-i', '/home/ljj/petalinux/csl_zynqsys_1/project-spec/configs/../../components/plnx_workspace/device-tree/device-tree', '-i', '/home/ljj/petalinux/csl_zynqsys_1/build/tmp/work-shared/zynq-generic/kernel-source/scripts/dtc/include-prefixes', '-i', '/home/ljj/petalinux/csl_zynqsys_1/build/tmp/work/zynq_generic-xilinx-linux-gnueabi/device-tree/xilinx-v2020.2+gitAUTOINC+f725aaecff-r0', '-i', '/home/ljj/petalinux/csl_zynqsys_1/build/tmp/work-shared/zynq-generic/kernel-source/arch/arm/boot/dts', '-o', 'system-top.dtb', '-I', 'dts', '-O', 'dtb', 'system-top.dts.pp']' returned non-zero exit status 1. Subprocess output: Error: /home/ljj/petalinux/csl_zynqsys_1/build/tmp/work/zynq_generic-xilinx-linux-gnueabi/device-tree/xilinx-v2020.2+gitAUTOINC+f725aaecff-r0/system-user.dtsi:15.1-6 syntax error FATAL ERROR: Unable to parse input tree ERROR: Logfile of failure stored in: /home/ljj/petalinux/csl_zynqsys_1/build/tmp/work/zynq_generic-xilinx-linux-gnueabi/device-tree/xilinx-v2020.2+gitAUTOINC+f725aaecff-r0/temp/log.do_compile.22923 ERROR: Task (/home/ljj/petalinux/csl_zynqsys_1/components/yocto/layers/meta-xilinx/meta-xilinx-bsp/recipes-bsp/device-tree/device-tree.bb:do_compile) failed with exit code '1' NOTE: Tasks Summary: Attempted 4295 tasks of which 359 didn't need to be rerun and 1 failed. Summary: 1 task failed: /home/ljj/petalinux/csl_zynqsys_1/components/yocto/layers/meta-xilinx/meta-xilinx-bsp/recipes-bsp/device-tree/device-tree.bb:do_compile Summary: There was 1 ERROR message shown, returning a non-zero exit code. ERROR: Failed to build project 结合上面设备树文件的代码,分析一下为什么会报错
03-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜 然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值