1. 功能
- 参数-a,-l,-R自由组合
- 在任意目录下使用
- 基本字体颜色显示
- 屏蔽ctrl+c
- 输出对齐
2. 代码分析
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/limits.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include <signal.h>
#define _NONE 0 //无参数下默认
#define _A 1
#define _L 2
#define MAX 1000 //文件名大小
#define MAXROWLEN 80
int g_leave_len = MAXROWLEN;
int g_maxlen;
int _R = 0;
void my_err(const char* err_string, int line);
void display(int flag_param, char* filename);
void display_attribute(struct stat buf, char * name, char* filename);
void display_dir(int flag_param, char* path);
void display_1(char* name, char* filename);
void display_r(int flag_praram, char* filename);
int get_color(char* filename);
void quicksort(char **a, int left, int right);
int getmid(int left,int right, char **a);
void swap(char** a, int i, int j);
int main(int argc, char** argv)
{
char path[MAX];
char param[32];
int flag_param = _NONE;
int i, k, j = 0, num = 0;
struct stat buf;
//屏蔽ctrl+c信号
signal(SIGINT, SIG_IGN);
//解析参数
for(i = 1; i < argc; i++)
{
if(argv[i][0] == '-')
{
for( k = 1; k < strlen(argv[i]); k++, j++)
{
param[j] = argv[i][k];
}
num++;
}
}
for(i = 0; i < j; i++)
{
if(param[i] == 'a')
{
flag_param |= _A;
continue;
}else if(param[i] == 'l')
{
flag_param |= _L;
continue;
}else if(param[i] == 'R')
{
_R = 1;
continue;
}else
{
printf("my_ls:invaild option -%c\n", param[i]);
exit(1);
}
}
// 无指定文件或目录输入时默认当前目录
if(argc == (num+1))
{
strcpy(path,"./");
path[2] = '\0';
display_dir(flag_param, path);
return 0;
}
//有指定目录或文件时分析是目录还是文件
i = 1;
do{
if(argv[i][0] == '-')
{
i++;
continue;
}
else
{
strcpy(path, argv[i]);
if(stat(path, &buf) == -1) my_err("stat", __LINE__);
//若为目录对目录路径进行补全
if(S_ISDIR(buf.st_mode))
{
if(path[strlen(argv[i])-1] != '/')
{
path[strlen(argv[i])] = '/';
path[strlen(argv[i])+1] = '\0';
}
else path[strlen(argv[i])] = '\0';
display_dir(flag_param, path);
i++;
}
else
{
display(flag_param, path);
i++;
}
}
}while(i<argc);
return 0;
}
//有-R参数情况下判断是否继续递归
void display_r(int flag_param,char* filename)
{
struct stat buf;
lstat(filename, &buf);
if(S_ISDIR(buf.st_mode))
{
int i, j = 0;
char name[MAX];
//解析文件名是否为隐藏文件
for(i = 0; i < strlen(filename); i++)
{
if(filename[i] == '/')
{
j = 0;
continue;
}
name[j++] = filename[i];
}
name[j] = '\0';
//进行递归
switch (flag_param){
case _NONE :
if(name[0] != '.') display_dir(flag_param,filename);
break;
case _A :
display_dir(flag_param, filename);
break;
case _L+_A :
display_dir(flag_param, filename);
break;
case _L :
if(name[0] != '.') display_dir(flag_param,filename);
default :
break;
}
}
}
//准备打印文件工作
void display(int flag_param, char* filename)
{
struct stat buf;
char name[MAX];
int i, j;
//解析文件名是否为隐藏文件
for(i = 0, j = 0; i < strlen(filename); i++)
{
if(filename[i] == '/')
{
j = 0;
continue;
}
name[j++] = filename[i];
}
name[j] = '\0';
if(lstat(filename, &buf) == -1) my_err("stat", __LINE__);
//根据参数打印文件
switch (flag_param){
case _NONE :
if(name[0] != '.') display_1(name, filename);
break;
case _A :
display_1(name, filename);
break;
case _L :
if(name[0] != '.') display_attribute(buf, name, filename);
break;
case _L+_A :
display_attribute(buf, name, filename);
break;
default :
break;
}
}
//对目录进行分析
void display_dir(int flag_param, char* path)
{
DIR* dir;
char temp[MAX] ;
struct dirent* ptr;
int filesnum = 0;
int len = strlen(path);
dir = opendir(path);
if(dir == NULL) my_err("opendir",__LINE__);
//获取文件数量
while((ptr = readdir(dir)) != NULL)
{
filesnum ++;
}
closedir(dir);
char **filenames = (char**)malloc(sizeof(char*)*filesnum);
//将所有文件名存入二维数组
dir = opendir(path);
for(int i = 0; i < filesnum; i++)
{
ptr = readdir(dir);
if(ptr == NULL) my_err("readdir",__LINE__);
filenames[i] = (char*)malloc(sizeof(char)*MAX);
strncpy(filenames[i], path, len);
if(filenames[i][len-1] != '/')
{
filenames[i][len] = '/';
filenames[i][len+1] = '\0';
strcat(filenames[i],ptr->d_name);
filenames[i][len+strlen(ptr->d_name)+1] = '\0';
}
else
{
filenames[i][len] = '\0';
strcat(filenames[i], ptr->d_name);
filenames[i][len+strlen(ptr->d_name)] = '\0';
}
}
//快排
quicksort(filenames, 0, filesnum-1);
//判断参数-R
if(_R)
{
printf("\n%s :\n", path);
}
//准备打印文件
for(int i = 0; i < filesnum; i++)
display(flag_param,filenames[i]);
printf("\n");
closedir(dir);
//-R的递归准备
if(_R){
for(int i = 2; i < filesnum; i++)
{
display_r(flag_param, filenames[i]);
}
}
}
//输出单个文件名
void display_1(char* name, char* filename)
{
int i , len;
//进行对齐
if(g_leave_len < g_maxlen)
{
printf("\n");
g_leave_len = MAXROWLEN;
}
len = strlen(name);
len = g_maxlen - len;
//根据类型打印不同颜色
int color = get_color(filename);
printf("\033[%dm%s\033[0m\t", color, name);
for(i = 0; i < len; i++)
{
printf(" ");
g_leave_len -= (g_maxlen + 2);
}
}
//文件属性分析
void display_attribute(struct stat buf, char * name, char* filename)
{
char buf_time[32];
struct passwd* psd;
struct group* grp;
//文件类型分析
if(S_ISLNK(buf.st_mode)){
printf("l");
}else if(S_ISREG(buf.st_mode)){
printf("-");
}else if(S_ISDIR(buf.st_mode)){
printf("d");
}else if(S_ISCHR(buf.st_mode)){
printf("c");
}else if(S_ISBLK(buf.st_mode)){
printf("b");
}else if(S_ISFIFO(buf.st_mode)){
printf("f");
}else if(S_ISSOCK(buf.st_mode)){
printf("s");
}
//文件权限分析
if(buf.st_mode & S_IRUSR){
printf("r");
}else{
printf("-");
}
if(buf.st_mode & S_IWUSR){
printf("w");
}else{
printf("-");
}
if(buf.st_mode & S_IXUSR){
printf("x");
}else{
printf("-");
}
if(buf.st_mode & S_IRGRP){
printf("r");
}else {
printf("-");
}
if(buf.st_mode & S_IWGRP){
printf("w");
}else{
printf("-");
}
if(buf.st_mode & S_IXGRP){
printf("x");
}else{
printf("-");
}
if(buf.st_mode & S_IROTH){
printf("r");
}else{
printf("-");
}
if(buf.st_mode & S_IWOTH){
printf("w");
}else{
printf("-");
}
if(buf.st_mode & S_IXOTH){
printf("x");
}else{
printf("-");
}
printf(" ");
//链接数量
printf("%4ld ", buf.st_nlink);
//得到拥有者和用户组id
psd = getpwuid(buf.st_uid);
grp = getgrgid(buf.st_gid);
printf("%-6s", psd->pw_name);
printf("%-6s", grp->gr_name);
printf("%6ld ", buf.st_size);
//获取最后一次修改时间
strcpy(buf_time, ctime(&buf.st_mtime));
buf_time[strlen(ctime(&buf.st_mtime))-1] = '\0';
printf("%s ", buf_time);
//根据类型打印不同颜色
int color = get_color(filename);
printf("\033[%dm%s\033[0m", color, name);
printf("\n");
}
//错误原因显示
void my_err(const char* err_string, int line)
{
fprintf(stderr, "line : %d ", line);
perror(err_string);
exit(1);
}
//字体颜色显示
int get_color(char* filename)
{
struct stat buf;
int color;
if(lstat(filename, &buf) == -1) my_err("stat", __LINE__);
if((buf.st_mode & S_IXOTH) || (buf.st_mode & S_IXUSR) || (buf.st_mode & S_IXGRP))
color = 32;
else if(S_ISLNK(buf.st_mode)){
color = 36;
}else if(S_ISREG(buf.st_mode)){
color = 37;
}else if(S_ISDIR(buf.st_mode)){
color = 34;
}else if(S_ISCHR(buf.st_mode)){
color = 33;
}else if(S_ISBLK(buf.st_mode)){
color = 33;
}else if(S_ISFIFO(buf.st_mode)){
color = 35;
}else if(S_ISSOCK(buf.st_mode)){
color = 35;
}
return color;
}
//对目录内文件名进行快排
void quicksort(char **a, int left, int right)
{
if(left < right)
{
int get = getmid(left, right, a);
quicksort(a, left, get-1);
quicksort(a, get+1, right);
}
}
int getmid(int left,int right, char **a)
{
char get[MAX];
strcpy(get, a[right]);
while(left < right)
{
while(left<right && (strcmp(a[left], get) <= 0))
left++;
swap(a, right, left);
while(left<right && (strcmp(a[right], get) >= 0))
right--;
swap(a, left, right);
}
strcpy(a[left], get);
return right;
}
void swap(char** a, int i, int j)
{
char tem[MAX];
strcpy(tem, a[i]);
strcpy(a[i], a[j]);
strcpy(a[j], tem);
}
3. 环境变量的添加
export PATH=该文件所在目录完整路径:$PATH
1.当前shell中暂时使用直接命令行输入
2.当前用户shell中一直可用打开~/.bashrc,末尾输入保存重开shell即可
注:~/.bashrc : 该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取。