Linux C 实现终端命令 ls -l 操作

目录

1、ls命令

2、思维分析

3、目录操作相关函数

(1)打开目录

(2)关闭目录

(3)读取目录

(4)获取文件属性

4、时间、文件类型、文件权限的获取

5、代码实现


1、ls命令

        在Linux中,ls 是我们经常使用的一个命令,通过加上 ls 特定的参数,我们可以获取文件的多种信息。

        以下为常见的 ls 命令查询指令:

ls -a :          可以查询以 '.' 开头的隐藏文件
ls  -R :         递归查询 ( 可以把目录里的所有内容全部 罗列出来 )
ls -l :            显示的内容更加全
ls -i :            查询文件的 inode
ls -i filename:        查询某个文件的inode

2、思维分析

        以下为“ls -l”在Linux下的具体信息:

Linux C 实现终端命令 ls -l 操作_第1张图片

         ls -l 将显示当前目录下的所有文件信息,如下图所示:

Linux C 实现终端命令 ls -l 操作_第2张图片

         要实现以上程序结果,我们首先要考虑如何对一个目录进行操作,因此,我们需引入目录操作的相关函数

3、目录操作相关函数

(1)打开目录

头文件:

        #include

        #include

函数原型:

        DIR *opendir(const char *name);


参数:
        name:要打开的目录名


返回值:
        成功返回目录流指针,返回NULL;

(2)关闭目录

头文件:

        #include

        #include

函数原型:

        int closedir(DIR *dirp);
   

参数:
        dirp:目录流指针
   

返回值:
       成功返回0,失败返回-1

(3)读取目录

头文件:

        #include

        

函数原型:

        struct dirent *readdir(DIR *dirp);

 函数内部元素(char类型存放文件名):

       struct dirent {
               char  d_name[256]; /*文件名*/
           };

(4)获取文件属性

头文件:

        #include
        #include
        #include

   

函数原型:

        int stat(const char *pathname, struct stat *statbuf);
        int fstat(int fd, struct stat *statbuf);
        int lstat(const char *pathname, struct stat *statbuf);

参数:
       pathname:文件名
       statbuf:存放文件信息的结构体地址

返回值:
       成功返回0,失败返回-1;
    
    struct stat
    {
               mode_t    st_mode;        //文件类型和权限
               nlink_t   st_nlink;       //文件硬链接数
               uid_t     st_uid;         //用户ID
               gid_t     st_gid;         //用户组ID
               off_t     st_size;        //文件大小
               struct timespec st_mtim;  //最后修改文件时间

                  #define st_mtime st_mtim.tv_sec
    }
    
    getgrgid -- 得到用户组名的函数
    getpwuid -- 得到用户名的函数

        通过以上信息,我们可以实现除了时间、文件类型、文件权限之外的信息,要实现这三者的实现,我们还需要借助以下几种方式。

4、时间、文件类型、文件权限的获取

localtime()获取时间,将st_mtime进行参数传递之后可以获得最后一次的更新时间戳

获取文件类型: S_IFMT 0170000 bit mask for the file type bit field

                 S_IFSOCK   0140000   socket
                 S_IFLNK    0120000   symbolic link
                 S_IFREG    0100000   regular file
                 S_IFBLK    0060000   block device
                 S_IFDIR    0040000   directory
                 S_IFCHR    0020000   character device
                 S_IFIFO    0010000   FIFO
                    
如果 st_mode & S_IFMT等于对应文件类型宏,则文件类型宏对应类型就为文件类型

获取文件权限:

                st_mode & 对应权限宏 == 宏本身 表示具有该权限

用户权限:

                S_IRUSR     00400   owner has read permission
                S_IWUSR     00200   owner has write permission
                S_IXUSR     00100   owner has execute permission

组权限:

                S_IRGRP     00040   group has read permission
                S_IWGRP     00020   group has write permission
                S_IXGRP     00010   group has execute permission

其它权限:    
                S_IROTH     00004   others have read permission
                S_IWOTH     00002   others have write permission
                S_IXOTH     00001   others have execute permission

        通过观察上述三组读写执行权限可知,我们可以通过对S_IRUSR进行移位操作来进行所有用户信息的判断写入。

5、代码实现

/*===============================================================
 *   Copyright (C) 2022 All rights reserved.
 *   
 *   文件名称:func.c
 *   创 建 者:QiuCC
 *   创建日期:2022年08月06日
 *   描    述:
 *
 *   更新日志:
 *
 ================================================================*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define N 100

int main(int argc, char *argv[])
{
	struct dirent *read_dir = NULL;//读取目录
	struct stat statbuf;//获取文件属性信息
	struct passwd *username = NULL;//获取用户名
	struct group *groupname = NULL;//获取组名
	struct tm *last_time = NULL;//获取最后一次更新时间戳

	DIR *dir = opendir(".");
	if(NULL == dir){
		perror("opendir");
		return -1;
	}

	while((read_dir = readdir(dir)) != NULL){
		if(read_dir->d_name[0] != '.'){//'.'开头为隐藏文件,ls -l无法查看
			if(lstat(read_dir->d_name, &statbuf) == -1){
				perror("lstat");
				return -1;
			}

			username = getpwuid(statbuf.st_uid);
			groupname = getgrgid(statbuf.st_gid);
			last_time = localtime(&statbuf.st_mtime);

			switch(statbuf.st_mode & S_IFMT){//通过st_mode 和 S_TFMT进行位与操作,实现文件类型判断
					case S_IFSOCK:
						printf("s");
						break;
					case S_IFLNK: 
						printf("l");
						break;
					case S_IFREG:
						printf("-");
						break;
					case S_IFBLK:
						printf("b");
						break;
					case S_IFDIR:
						printf("d");
						break;
					case S_IFCHR:  
						printf("c");
						break;
					case S_IFIFO:    
						printf("p");
						break;
			}
			
			int i = 0;
			while(i < 9){//共9个权限,st_mode和对应文件宏进行位与操作,判断文件权限,通过异位信息i来进行指定用户权限的写入
				if((statbuf.st_mode & S_IRUSR >> i) == (S_IRUSR >> i)){
					if(i%3 == 0){
						printf("r");
					}else if(i%3 == 1){
						printf("w");
					}else if(i%3 == 2){
						printf("x");
					}
				}else{
					printf("-");
				}
				i++;

			}



			printf("%4ld  %s  %s  ", statbuf.st_nlink, username->pw_name, groupname->gr_name);
			printf("%ld\t", statbuf.st_size);
			printf("%d月 %d  %02d:%02d  ", last_time->tm_mon+1, last_time->tm_mday, last_time->tm_hour, last_time->tm_min);
			printf("%s\n", read_dir->d_name);
		}
	}


	closedir(dir);


	return 0;
}

6、运行结果

Linux C 实现终端命令 ls -l 操作_第3张图片

        通过实验结果显示,我们的各项信息均正确,从运行结果还可以看出,我们的目录读取是随机的,没有顺序和规律的。

好的,以上就是本期内容,欢迎大家参考指正!!!

你可能感兴趣的:(C++,IO进线程,linux,服务器,运维,ubuntu,开发语言)