在Linux中用C语言写一个自己的ls-l命令
在Linux中我们会经常使用ls -l 这条命令来查看文件信息,但是这个命令到底是怎么实现的呢?下面我就带大家用C语言来实现ls -l 这条命令,直接上代码吧:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
// ls-l 功能函数,参数为一个文件名
void ls_l(char name[])
{
// 定义一个stat类型的结构体
struct stat my_stat;
int ret = stat(name,&my_stat);
if (ret == -1){
perror("stat");
return ;
}
// 判断并打印文件类型 ,这里用到了很多函数调用,后面会为大家贴上这些函数的用法
if (S_ISDIR(my_stat.st_mode))
printf("d");
else if (S_ISBLK(my_stat.st_mode))
printf("b");
else if (S_ISCHR(my_stat.st_mode))
printf("c");
else if (S_ISLNK(my_stat.st_mode))
printf("l");
else if (S_ISSOCK(my_stat.st_mode))
printf("s");
else if (S_ISREG(my_stat.st_mode))
printf("-");
else if (S_ISFIFO(my_stat.st_mode))
printf("p");
// 判断文件的权限信息
printf("%c",(my_stat.st_mode) & (1<<8)?'r':'-');
printf("%c",(my_stat.st_mode) & (1<<7)?'w':'-');
printf("%c",(my_stat.st_mode) & (1<<6)?'x':'-');
printf("%c",(my_stat.st_mode) & (1<<5)?'r':'-');
printf("%c",(my_stat.st_mode) & (1<<4)?'w':'-');
printf("%c",(my_stat.st_mode) & (1<<3)?'x':'-');
printf("%c",(my_stat.st_mode) & (1<<2)?'r':'-');
printf("%c",(my_stat.st_mode) & (1<<1)?'w':'-');
printf("%c",(my_stat.st_mode) & (1<<0)?'x':'-');
// 打印链接数
printf(" %ld",my_stat.st_nlink);
// 打印所属用户
struct passwd *uid = getpwuid(my_stat.st_uid);
printf(" %s",uid->pw_name);
// 打印所属组
struct group *gid = getgrgid(my_stat.st_gid);
printf(" %s",gid->gr_name);
// 打印文件大小
printf(" %-8ld",my_stat.st_size);
// 打印时间
struct tm *t = localtime((time_t *)&my_stat.st_mtim);
printf(" %d月 %d %d:%d ",t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);
// 打印文件名
printf("%-2s\n",name);
}
// 这里是使用命令行传参
int main(int argc, const char *argv[])
{
//判断是否携带参数,如果没有携带参数,就默认为当前路径
if (argc == 1){
printf("请输入文件路径,或者文件名\n");
return -1;
}
struct stat my_stat;
int ret = stat(argv[1],&my_stat);
// 判断输入的是否为目录
if (S_ISDIR(my_stat.st_mode)){
// 如果为目录,我们将目录打开,把里面的内容(文件名)传给功能函数
DIR * dir = opendir(argv[1]);
if (NULL == dir){
perror("opendir");
return -1;
}
struct dirent *p = readdir(dir);
if (NULL == p)
{
perror("readdir");
return -1;
}
while (p!=NULL){
ls_l(p->d_name);
p = readdir(dir);
}
closedir(dir);
}else // 不是目录
ls_l(argv[1]);
return 0;
}
上述代码中用到了库函数和结构体,下面是一部分函数和结构体的具体内容:
- 【stat结构体的内容】
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; 文件的权限、文件的类型 /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; 所属用户ID /* user ID of owner */
gid_t st_gid; 所属组ID /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; 文件的大小 /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; 最后一次访问时间 /* time of last access */
time_t st_mtime; 最后一次修改时间 /* time of last modification */
time_t st_ctime; 最后一次文件文件属性修改时间 /* time of last status change */
};
2.【将uid 转换为 用户名】
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
- 【将gid 转换为 组名】
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
- 【文件类型】
{
常规文件:S_ISREG '-'
目录:S_ISDIR 'd'
字符设备:S_ISCHR 'c'
块设备:S_ISBLK 'b'
管道:S_ISFIFO 'p'
套接字:S_ISSOCK 's'
符号链接:S_ISLNK 'l'
}
- 【目录操作函数】
include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
/*****************************************
*功能: 打开一个目录文件
*参数: @name 目录文件路径
*返回值: 成功 返回 目录流指针
* 失败 返回 NULL 更新 errno
******************************************/
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
/*****************************************
*功能: 读目录流指针
*参数: @dirp 目录流指针
*返回值: 成功 返回 struct dirent 指针
* 失败 返回 NULL 表示目录中的文件读完
******************************************/
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
/*****************************************
*功能: 关闭目录流
*参数: @dirp 目录流指针
*返回值: 成功 返回 0
* 失败 返回 -1 更新 errno
******************************************/