Fork me on GitHub

Linux--实现简单的ls功能

利用Linux C实现简单的ls功能,其中包括:

  1. -a 显示所有文件及目录 (ls内定将文件名或目录名称开头为”.”的视为隐藏档,不会列出)。
  2. -l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出。
  3. -R 若目录下有文件,则以下之文件亦皆递归依序列出。
  4. -d 显示目录名称而非其内容。
  5. -i 显示文件和目录的inode编号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//ls_command.cpp

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdbool.h>

#define PARAM_TYPE_NUM 6//参数种类
#define DESTINATION_PARAM 0
#define a_PARAM 1
#define d_PARAM 2
#define i_PARAM 3
#define l_PARAM 4
#define R_PARAM 5

void handle_params(int argc, char* argv[], bool params[], char* optstring);
void handle_ls_command(bool params[], char* argv[]);
void printDir(char *dir, int depth, bool params[]);

void handle_params(int argc, char* argv[], bool params[], char* optstring){
int opt;

while((opt = getopt(argc, argv, optstring)) != -1){
switch(opt){
case 'a':
params[a_PARAM] = true;
break;
case 'd':
params[d_PARAM] = true;
break;
case 'i':
params[i_PARAM] = true;
break;
case 'l':
params[l_PARAM] = true;
break;
case 'R':
params[R_PARAM] = true;
break;
case '?':
printf("ls: unknown option: %c\n", optopt);
optind--;
break;
default:
break;
}
}

if(optind < argc){
params[DESTINATION_PARAM] = true;
}
}

void handle_ls_command(bool params[], char* argv[]){
if(params[DESTINATION_PARAM] != true){
printDir(".", 0, params);
}else{
printDir(argv[optind], 0, params);
}
}

void printDir(char *dir, int depth, bool params[]){
DIR *destination_directory = opendir(dir);

if(destination_directory == NULL){//如果打开失败,给出提示,并退出。
printf("ls: 打开文件夹 %s 失败。\n", dir);
// exit(-1);
return;
}

struct dirent *entry;
struct stat statbuf;
chdir(dir);//更换工作路径

while((entry = readdir(destination_directory)) != NULL){
lstat(entry->d_name, &statbuf);

//-d 显示目录名称而非其内容
if(params[d_PARAM] == true){
printf("%*s%s/ \n", depth, " ", dir);
//-i 显示文件和目录的索引节点号
if(params[i_PARAM] == true){
printf("%*s%ld\n", depth, " inode:", statbuf.st_ino);
}
//-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
if(params[l_PARAM] == true){
printf("%*s%d\t", depth, " 权限:", statbuf.st_mode);//权限
printf("%*s%d\t", depth, " 拥有者:", statbuf.st_uid);//拥有者
printf("%*s%d\t", depth, " 组ID:", statbuf.st_gid);//组名
printf("%*s%ld 字节\n", depth, " 文件大小:", statbuf.st_size);//文件大小
}
exit(0);
}

if(S_ISDIR(statbuf.st_mode)){//如果是目录
if(params[a_PARAM] == false &&
(strcmp(entry->d_name, ".")==0 || strcmp(entry->d_name, "..")==0) ){
//不显示 . 和 .. 文件夹
continue;
}
printf("%*s%s/ \n", depth, " ", entry->d_name);

//-i 显示文件和目录的索引节点号
if(params[i_PARAM] == true){
printf("%*s%ld\n", depth, " inode:", statbuf.st_ino);
}

//-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
if(params[l_PARAM] == true){
printf("%*s%d\t", depth, " 权限:", statbuf.st_mode);//权限
printf("%*s%d\t", depth, " 拥有者:", statbuf.st_uid);//拥有者
printf("%*s%d\t", depth, " 组ID:", statbuf.st_gid);//组名
printf("%*s%ld 字节\n", depth, " 文件大小:", statbuf.st_size);//文件大小
}

//-R 若目录下有文件,则以下之文件亦皆递归依序列出
//若没有,直接跳出第一次循环即可
if(params[R_PARAM] == true){
printDir(entry->d_name, depth + 4, params);
}

}else{//一般文件
//如果没有 -a 则忽略以.开头的文件
if(params[a_PARAM] == false && (entry->d_name[0] == '.')){
continue;
}

printf("%*s%s \n", depth, " ", entry->d_name);//只列出名字

//-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
if(params[l_PARAM] == true){
printf("%*s%d\t", depth, " 权限:", statbuf.st_mode);//权限
printf("%*s%d\t", depth, " 拥有者:", statbuf.st_uid);//拥有者
printf("%*s%d\t", depth, " 组ID:", statbuf.st_gid);//组名
printf("%*s%ld 字节\n", depth, " 文件大小:", statbuf.st_size);//文件大小
}

//-i 显示文件和目录的索引节点号
if(params[i_PARAM] == true){
printf("%*s%ld\n", depth, " inode:", statbuf.st_ino);
}
}
}
chdir("..");
closedir(destination_directory);
}

int main(int argc, char* argv[]){

bool params[PARAM_TYPE_NUM] = {false};//首先全部设为false
handle_params(argc, argv, params, "alRdi::");
handle_ls_command(params, argv);
exit(0);
}
扫描二维码,拯救贫困山区大学生!
-------------本文结束感谢您的阅读-------------