[Linux环境编程] Linux系统命令“ls -R”的实现

摘要:
Linux系统命令“ls-R”的实现I.基本概念1.递归处理“ls-R“的含义,它显示指定目录下的所有文件和子目录。1#include<sys/types.h>2#include<dirent。h˃ 34DIR*opendir;5DIR*fdopendir;678#包含 910结构目录*读取目录;1112指令{13ino_td_ino;/*inodenumber*/14off_td_off;/*offsettothnextirent*/15unsignedshortd_reclen;/*记录长度*/16unsignedhard_type;/*typeoffile;不支持所有文件系统类型*/17chard_name[256];/*文件名*/18};1#include<sys/types.h>2#include<dirent。h˃ 34真空复卷机;2.必须在此处使用intlstat获取文件信息;函数,否则在处理链接文件时,链接的原始文件将被视为处理对象而不是其本身。1#包含2#包含3#包含 45intstat;6intfstat;7英寸;89结构统计{10dev_tst_dev;/*包含文件的设备ID*/11ino_tst_ino;/*inodenumber*/12mode_tst_mode;/*保护*/13nlink_tst_nink;/*硬件链接数*/14uid_tst_uid;/*所有者的用户ID*/15gid_st_gid;/*groupIDofowner*/16dev_tst_rdev;/*设备ID*/17off_tst_size;/*总大小,以字节为单位*/18blksize_tst_blksize;/*文件系统I/O的块大小*/19blkcnt_tst_block锁;/*已定位的512B块数量*/20time_tst_atime;/*timeflastaaccess*/21time_tst_mtime;/*timeflastmodification*/22time_tst_cime;/*timeflaststatuschange*/23};3.以下POSIX宏定义为使用_ mode字段检查文件类型:23S_ISREGisiaregularfile?

Linux系统命令“ls -R”的实现

 

一、基本概念

1、“ls -R”的意义

  递归处理,将指定目录下的所有文件及子目录一并显示。

  例: ls   -R   ./testdir1/

    ./testdir1/:
    test1.c   test1.txt   test2.txt   testdir2

    ./testdir1/testdir2:
    test2.c   test3.c      test3.txt   到 test1.c 的链接

  其中蓝色为目录文件,红色为软连接文件(具体颜色和vimrc配置有关)。

二、重要函数与结构体

1、目录操作函数

  里的 void rewinddir(DIR *dirp); 函数非常重要,在读取一遍目录后,如果遗漏rewinddir函数会导致指向文件的指针停留在该目录文件流的末尾,从而影响之后二次读取。

 1        #include <sys/types.h>
 2        #include <dirent.h>
 3 
 4        DIR *opendir(const char *name);
 5        DIR *fdopendir(int fd);
 6 
 7 
 8        #include <dirent.h>
 9 
10        struct dirent *readdir(DIR *dirp);
11 
12            struct dirent {
13                ino_t          d_ino;       /* inode number */
14                off_t          d_off;       /* offset to the next dirent */
15                unsigned short d_reclen;    /* length of this record */
16                unsigned char  d_type;      /* type of file; not supported by all file system types */
17                char           d_name[256]; /* filename */
18            };
 1        #include <sys/types.h>
 2        #include <dirent.h>
 3 
 4        void rewinddir(DIR *dirp);

2、获取文件信息

  这里必须使用 int lstat(const char *path, struct stat *buf); 函数,否则在处理链接文件时会将其链接的原文件作为处理对象,而不是其本身。

 1        #include <sys/types.h>
 2        #include <sys/stat.h>
 3        #include <unistd.h>
 4 
 5        int stat(const char *path, struct stat *buf);
 6        int fstat(int fd, struct stat *buf);
 7        int lstat(const char *path, struct stat *buf);
 8 
 9            struct stat {
10                dev_t     st_dev;     /* ID of device containing file */
11                ino_t     st_ino;     /* inode number */
12                mode_t    st_mode;    /* protection */
13                nlink_t   st_nlink;   /* number of hard links */
14                uid_t     st_uid;     /* user ID of owner */
15                gid_t     st_gid;     /* group ID of owner */
16                dev_t     st_rdev;    /* device ID (if special file) */
17                off_t     st_size;    /* total size, in bytes */
18                blksize_t st_blksize; /* blocksize for file system I/O */
19                blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
20                time_t    st_atime;   /* time of last access */
21                time_t    st_mtime;   /* time of last modification */
22                time_t    st_ctime;   /* time of last status change */
23            };

3、 文件类型及权限的判断

 1        The following POSIX macros are defined to check the file type using the st_mode field:
 2 
 3            S_ISREG(m)  is it a regular file?
 4            S_ISDIR(m)  directory?
 5            S_ISCHR(m)  character device?
 6            S_ISBLK(m)  block device?
 7            S_ISFIFO(m) FIFO (named pipe)?
 8            S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
 9            S_ISSOCK(m) socket? (Not in POSIX.1-1996.)

 

三、执行结果及对比

 [Linux环境编程] Linux系统命令“ls -R”的实现第1张

 

 

四、总结

  总的来说,实现“ls -R”功能所涉及的特殊结构体很少,涉及知识面较窄,代码量少,但细节部分较多,需要一定的经验,经验不足的话调试起来会比较麻烦,总体难度一般。在实现功能的过程中有几点需要注意下:

  1. 利用 lstat 函数读取文件信息,否则无法有效处理软连接文件;

  2. 利用 rewinddir 函数重置指向文件流的指针,以便之后二次遍历目录;

  3. 在读取文件流时,注意屏蔽当前目录(.)、上一级目录(..)和隐藏文件(.*)。

  目前暂未实现制表功能,有兴趣的朋友可以尝试着通过读取终端显示宽度与最长文件名长度来加以设计。

 

五、实现代码

1、 myls2.h 

 1 #ifndef _MYLS2_H_
 2 #define _MYLS2_H_
 3 
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<limits.h>
 8 #include<unistd.h>
 9 #include<dirent.h>
10 #include<sys/stat.h>
11 #include<sys/types.h>
12 #include<fcntl.h>
13 #include<time.h>
14 #include<pwd.h>
15 #include<grp.h>
16 
17 // 处理错误
18 void error_printf(const char* );
19 
20 // 处理路径下的文件
21 void list_dir(const char* );
22 
23 // 所显示的文件信息
24 void display_dir(DIR* );
25 
26 #endif//_MYLS2_H_

2、myls2.c

 1 #include "myls2.h"
 2 
 3 // 处理错误
 4 void error_printf(const char* funname)
 5 {
 6     perror(funname);
 7     exit(EXIT_FAILURE);
 8 }
 9 
10 // 读取路径下的文件
11 void list_dir(const char* pathname)
12 {
13     char nextpath[PATH_MAX+1];
14 
15     DIR* ret_opendir = opendir(pathname); // 打开目录"pathname"
16     if(ret_opendir == NULL)
17         error_printf("opendir");
18     
19     printf("%s:
",pathname); // 显示pathname目录路径
20     display_dir(ret_opendir); // 显示pathname目录下所有非隐藏文件名称
21 
22     struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量
23     while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到目录尾
24     {
25         char* filename = ret_readdir->d_name; // 获取文件名
26 
27         int end = 0; // 优化显示路径(处理"./test/"与"./test")
28         while(pathname[end])
29             end++;
30         strcpy(nextpath,pathname);
31         if(pathname[end-1] != '/')
32             strcat(nextpath,"/");
33         strcat(nextpath,filename);
34 
35         struct stat file_message = {}; // 定义stat函数返回的结构体变量
36         int ret_stat = lstat(nextpath, &file_message); // 获取文件信息
37         if(ret_stat == -1) // stat读取文件错误则输出提示信息
38             printf("%s error!", filename);
39         else if(S_ISDIR(file_message.st_mode)  && filename[0]!='.') // 筛选"."、".."与隐藏文件
40         {
41             list_dir(nextpath);
42         }
43     }
44     closedir(ret_opendir);
45 }
46 
47 // 打印所读取文件的信息
48 void display_dir(DIR* ret_opendir)
49 {
50     struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量
51     while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到目录尾
52     {
53         char* filename = ret_readdir->d_name; // 获取文件名
54         if(filename[0]!='.') // 不输出当前目录、上一级目录与隐藏文件 
55             printf("%s	",ret_readdir->d_name); // 打印文件名
56     }
57     rewinddir(ret_opendir); // 非常重要,将文件流的指针拨回起始位置
58     puts("");
59     puts("");
60 }

3、main_myls2.c

 1 #include "myls2.h"
 2 
 3 
 4 int main(const char argc, const char** argv)
 5 {
 6     char path[PATH_MAX+1] = {};
 7 
 8     if(argc == 2 && !(strcmp(argv[1],"-R"))) // 判断命令格式
 9         strcpy(path,".");
10     else if(argc != 3)
11     {
12         printf("格式有误! 
");
13         exit(EXIT_FAILURE);
14     }
15     else
16         strcpy(path,argv[2]);
17 
18     if(!(strcmp(argv[1],"-R")))
19     {
20         struct stat file_message = {};
21         int ret_stat = lstat(path, &file_message);
22 
23         if(ret_stat == -1)
24                error_printf("stat");
25 
26         if(S_ISDIR(file_message.st_mode)) // 判断是否为目录
27             list_dir(path);
28         else
29         printf("It is not dir!");
30     }
31     else
32     {
33         printf("error in main!
");
34         exit(EXIT_FAILURE);
35     }                    
36     return 0;
37 }

免责声明:文章转载自《[Linux环境编程] Linux系统命令“ls -R”的实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇在VMware虚拟机中配置DOS汇编开发环境!!C# 序列化与反序列化Serialization之Json Xml Binary Soap JavaScript序列化下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux监控分析

一、linux硬件 CPU(计算、逻辑判断、逻辑处理)、内存(cpu在内存中处理数据(记忆片段))、IO(对磁盘在一段时间内的读写操作) cpu和内存间有块区域缓存(二级缓存) cpu高:检查cpu,查看系统的瓶颈点是否在cpu上,看cpu把时间花费在哪个地方了,如果说,在这过程中,cup没有浪费时间,只能加cpu;如果cpu确实有浪费时间的地方,解决这个...

windows的磁盘操作之八——格式化分区的思考

格式化分区平常在我们看来是再普通不过的操作了,点两下鼠标就可以搞定的事情,但是在程序中实现的的确确不太容易。可能有人说直接调个format命令不就好了,没错,但系统命令存在我们第一节http://cutebunny.blog.51cto.com/301216/624027中阐述的种种问题。 算上format命令,目前我发现有三种方法, 1.Windows...

Linux——用户和组管理,文件权限管理,文件查找(find)

一、用户和组相关的管理命令 1)创建用户:useradd 命令格式:useradd [options] LOGIN 选项: -u UID: [UID_MIN, UID_MAX], 定义在/etc/login.defs -g GID:指明用户所属基本组,可为组名,也可以GID; -c "COMMENT":用户的注释信息; -d /PATH/TO/HOME_...

【苏勇老师Linux 入门笔记】网络基础

IP 地址   IP 编制时一个双层编制方案,一个 IP 地址标示一个主机 (或一个网卡接口)。 一个 IP 地址分为两个部分:网络部分(所属区域)和主机部分(标示区域中的哪个主机)。IPv4 共32位,通常用点分十进制表示。 子网掩码用于将网络部分和主机部分区分开来,子网掩码为1(二进制)的部分为网络部分。   MAC地址主要用于同网络间主机的通信...

linux安装unzip及使用

安装完linux ,发现没有UNZIP,没办法,重新安装。 1、获取unzip源码 sudo wget http://downloads.sourceforge.net/infozip/unzip552.tar.gz 2、解压 tar zxvf unzip552.tar.gz 3、进入目录 cd unzip-5.52/ 4、将Makefile从unix子...

在ASP.NET 2.0中使用样式、主题和皮肤

ASP.NET 2.0的主题和皮肤特性使你能够把样式和布局信息存放到一组独立的文件中,总称为主题(Theme)。接下来我们可以把这个主题应用到任何站点,用于改变该站点内的页面和控件的外观和感觉。通过改变主题的内容,而不用改变站点的单个页面,就可以轻易地改变站点的样式。主题也可以在开发者之间共享。 ASP.NET包含了大量的用于定制应用程序的页面和控件的外观...