[Linux环境编程]Linux系统命令“ls-l”的实现
Linux系统命令“ls -l”的实现
⼀、基本概念
1、“ls -l”的意义
以长格式显⽰⽬录下的内容列表。输出的信息从左到右依次包括⽂件名,⽂件类型、权限模式、硬连接数、所有者、组、⽂件⼤⼩和⽂件的最后修改时间等。
例:-rw-rw-r-- 1 using using 3102 7⽉ 22 17:06 test.c
drwxrwxr-x 2 using using 4096 7⽉ 22 18:39 testdir
lrwxrwxrwx 1 using using 17 7⽉ 22 18:43 shared -> /media/sf_shared/
其中深蓝⾊为⽬录⽂件,天蓝⾊为软连接⽂件(具体颜⾊和vimrc配置有关)。
第⼀字段:⾸字母代表的是⽂件类型,其中"-"为普通⽂件、"d"为⽬录⽂件、"c"为字符设备⽂件、"b"为块设备⽂件、"p"为管道⽂件、"l"为链接⽂件、"s"为socket⽂件。“rwx”分别代表拥有读、写和执⾏权限,“-”
代表⽆对应权限。三个“rwx”依次代表⽂件所有者、⽂件所有者所在⽤户组、其它⽤户对⽂件拥有的权限。
第⼆字段:⽂件硬连接数量
第三字段:⽂件拥有者
第四字段:⽂件拥有者所在组
第五字段:⽂件⼤⼩(以字节为单位)
第六字段:⽂件最后更改时间
第七字段:⽂件名(若为链接⽂件则追加显⽰其链接的原⽂件的路径)
⼆、重要函数与结构体
1、⽬录操作函数
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
12struct 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 };
2、获取⽂件信息
这⾥必须使⽤int lstat(const char *path, struct stat *buf);函数,否则在处理链接⽂件时会将其链接的原⽂件作为处理对象,⽽不是它本⾝。
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4
5int stat(const char *path, struct stat *buf);
6int fstat(int fd, struct stat *buf);
7 int lstat(const char *path, struct stat *buf);
8
9struct 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.)
10
11
12 The following flags are defined for the st_mode field:
13
14 S_IFMT 0170000 bit mask for the file type bit fields
15 S_IFSOCK 0140000 socket
16 S_IFLNK 0120000 symbolic link
17 S_IFREG 0100000 regular file
18 S_IFBLK 0060000 block device
19 S_IFDIR 0040000 directory
20 S_IFCHR 0020000 character device
21 S_IFIFO 0010000 FIFO
22 S_ISUID 0004000set UID bit
23 S_ISGID 0002000set-group-ID bit (see below)
24 S_ISVTX 0001000 sticky bit (see below)
25 S_IRWXU 00700 mask for file owner permissions
26 S_IRUSR 00400 owner has read permission
27 S_IWUSR 00200 owner has write permission
28 S_IXUSR 00100 owner has execute permission
29 S_IRWXG 00070 mask for group permissions
30 S_IRGRP 00040 group has read permission
31 S_IWGRP 00020 group has write permission
32 S_IXGRP 00010 group has execute permission
33 S_IRWXO 00007 mask for permissions for others (not in group)
34 S_IROTH 00004 others have read permission
35 S_IWOTH 00002 others have write permission
36 S_IXOTH 00001 others have execute permission
4、⽂件⽤户ID与⽤户所在组ID的转换
1 #include <sys/types.h>
2 #include <pwd.h>
3
4struct passwd *getpwnam(const char *name);
5 struct passwd *getpwuid(uid_t uid);
6int getpwnam_r(const char *name, struct passwd *pwd,char *buf, size_t buflen, struct passwd **result); 7int getpwuid_r(uid_t uid, struct passwd *pwd,char *buf, size_t buflen, struct passwd **result);
8
9
10 The passwd structure is defined in <pwd.h> as follows:
11
12struct passwd {
13 char *pw_name; /* username */
14char *pw_passwd; /* user password */
15 uid_t pw_uid; /* user ID */
16 gid_t pw_gid; /* group ID */
17char *pw_gecos; /* user information */
18char *pw_dir; /* home directory */
19char *pw_shell; /* shell program */
20 };
1 #include <sys/types.h>
2 #include <grp.h>
3
4struct group *getgrnam(const char *name);
5 struct group *getgrgid(gid_t gid);printf输出格式linux
6int getgrnam_r(const char *name, struct group *grp,char *buf, size_t buflen, struct group **result); 7int getgrgid_r(gid_t gid, struct group *grp,char *buf, size_t buflen, struct group **result);
8
9
10 The group structure is defined in <grp.h> as follows:
11
12struct group {
13 char *gr_name; /* group name */
14char *gr_passwd; /* group password */
15 gid_t gr_gid; /* group ID */
16char **gr_mem; /* group members */
17 };
5、⽂件最后修改时间
⽂件最后修改时间可以通过tm结构体接收localtime函数返回值来获取。
1 #include <time.h>
2
3 struct tm *localtime(const time_t *timep);
4struct tm *localtime_r(const time_t *timep, struct tm *result);
5
6
7 Broken-down time is stored in the structure tm which is defined in <time.h> as follows:
8
9 struct tm {
10 int tm_sec; /* seconds */
11 int tm_min; /* minutes */
12 int tm_hour; /* hours */
13 int tm_mday; /* day of the month */
14 int tm_mon; /* month */
15 int tm_year; /* year */
16 int tm_wday; /* day of the week */
17 int tm_yday; /* day in the year */
18 int tm_isdst; /* daylight saving time */
19 };
三、执⾏结果及对⽐
四、总结
总的来说,实现“ls -l”功能所涉及的特殊结构体较多,基础知识考察较多,需要构建很多⼩函数,较为繁杂,但逻辑结构简单,没有什么需要特别留意的地⽅,总体难度较低。
本博是在博友“”的⼀篇博客“”的基础上改进完成。总体沿⽤了原有思路和框架,做了以下改良:
1. 可以处理软连接⽂件(原处理链接⽂件所链接的原⽂件);
2. 当输⼊“myls -l”指令时默认显⽰当前⽬录下⽂件的详细信息(原报错);
3. 指令、代码优化。
但⽬前暂未实现总⽤量/total、模糊匹配和彩字显⽰功能,有兴趣的朋友可以尝试⼀下。
五、实现代码
1、myls.h
1 #ifndef _MYLS_H_
2#define _MYLS_H_
3
4 #include<stdio.h>
5 #include<stdlib.h>
6 #include<string.h>
7 #include<unistd.h>
8 #include<dirent.h>
9 #include<sys/stat.h>
10 #include<sys/types.h>
11 #include<fcntl.h>
12 #include<time.h>
13 #include<pwd.h>
14 #include<grp.h>
15
16// 处理错误
17void error_printf(const char* );
18
19// 处理路径下的⽂件
20void list_dir(const char* );
21void list_message(const char* , const struct stat*);
22
23// 所显⽰的⽂件信息
24void file_type(const struct stat* );
25void file_power(const struct stat* );
26// printf st_nlink
27void file_id(const struct stat* );
28// printf st_size
29void file_mtime(const struct stat* );
30// printf filename
31void link_printf(const char* );
32
33#endif//_MYLS_H_
2、 myls.c
1 #include "myls.h"
2
3// 处理错误
4void error_printf(const char* funname)
5 {
6 perror(funname);
7 exit(EXIT_FAILURE);
8/*
9 * EXIT_SUCCESS和EXIT_FAILURE是两个常量。
10 * EXIT_SUCCESS=0,EXIT_FAILURE=1。
11 * 0表⽰程序寿终正寝,1表⽰死于⾮命。
12*/
13 }
14
15// 读取路径下的⽂件
16void list_dir(const char* pathname)
17 {
18 DIR* ret_opendir = opendir(pathname); // 打开⽬录"pathname"
19if(ret_opendir == NULL)
20 error_printf("opendir");
21
22int ret_chdir = chdir(pathname); // 改变⼯作⽬录⾄"pathname",便于stat函数的使⽤
23if(ret_chdir == -1)
24 error_printf("chdir");
25
26struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量
27while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到⽬录尾
28 {
29char* filename = ret_readdir->d_name; // 获取⽂件名
30struct stat file_message = {}; // 定义stat函数返回的结构体变量
31int ret_stat = lstat(filename, &file_message); // 获取⽂件信息
32if(ret_stat == -1) // stat读取⽂件错误则输出提⽰信息
33 printf("%s error!", filename);
34else if(strcmp(filename,".") && strcmp(filename,"..")) // 不输出当前⽬录与上⼀级⽬录
35 list_message(filename, &file_message);
36 }
37 }
38
39// 打印所读取⽂件的信息
40void list_message(const char* filename, const struct stat* file_message)
41 {
42 file_type(file_message); // 判断打印⽂件类型
43 file_power(file_message); // 判断并打印⽂件权限
44 printf("%d ", file_message->st_nlink); // 打印硬链接数
45 file_id(file_message); // 转换并打印⽤户id与组id
46 printf("%5ld ", file_message->st_size); // 打印⽂件⼤⼩
47 file_mtime(file_message); // 打印⽂件最后修改时间
48 printf("%s ", filename); // 打印⽂件名
49if(S_ISLNK(file_message->st_mode)) // 如果是软链接⽂件,打印其指向的位置
50 link_printf(filename);
51 puts("");
52 }
53
54
55// 所显⽰的⽂件信息
56void file_type(const struct stat* file_message)
57 {
58//mode_t mode = (*get_message).st_mode;
59 mode_t mode = file_message->st_mode;
60
61if (S_ISREG(mode)) printf("-"); // 普通⽂件
62else if(S_ISDIR(mode)) printf("d"); // ⽬录⽂件
63else if(S_ISCHR(mode)) printf("c"); // 字符设备⽂件
64else if(S_ISBLK(mode)) printf("b"); // 块设备⽂件
65else if(S_ISFIFO(mode)) printf("p"); // 管道⽂件
66else if(S_ISLNK(mode)) printf("l"); // 链接⽂件
67else printf("s"); // socket⽂件
68 }
69
70void file_power(const struct stat* file_message)
71 {
72 mode_t mode = file_message->st_mode;
73
74// 判断USR权限
75 printf("%c", mode&S_IRUSR?'r':'-');
76 printf("%c", mode&S_IWUSR?'w':'-');
77 printf("%c", mode&S_IXUSR?'x':'-');
78
79// 判断GRP权限
80 printf("%c", mode&S_IRGRP?'r':'-');
81 printf("%c", mode&S_IWGRP?'w':'-');
82 printf("%c", mode&S_IXGRP?'x':'-');
83
84// 判断OTH权限
85 printf("%c", mode&S_IROTH?'r':'-');
86 printf("%c", mode&S_IWOTH?'w':'-');
87 printf("%c ", mode&S_IXOTH?'x':'-');
88 }
89
90void file_id(const struct stat* file_message)
91 {
92// 根据⽤户id获取⽤户名
93struct passwd* pwd;
94 pwd = getpwuid(file_message->st_uid);
95 printf("%s ",pwd->pw_name);
96
97// 根据组id获取组名
98struct group* grp;
99 grp = getgrgid(file_message->st_gid);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论