概述
在Linux系统中,ls -l
命令是我们日常使用最频繁的命令之一,它能够以长格式显示文件的详细信息。本文将深入解析ls -l
的实现原理,并逐步讲解如何用C语言实现一个简化版的ls -l
命令。
// 输出示例:-rw-rw-r-- 1 miao miao 4 9月 15 20:28 a.txt
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
int main(int argc, char* argv[]){
if (argc < 2){
printf("%s filename\n", argv[0]);
return -1;
}
// 通过stat函数获取文件信息
struct stat st;
int ret = stat(argv[1], &st);
if (ret == -1){
perror("stat");
return -1;
}
// 1. 文件类型
char perms[12] = {0};
switch (st.st_mode & __S_IFMT){
case __S_IFLNK:
perms[0] = 'l'; // 符号链接
break;
case __S_IFDIR:
perms[0] = 'd'; // 目录
break;
case __S_IFREG:
perms[0] = '-'; // 普通文件
break;
case __S_IFBLK:
perms[0] = 'b'; // 块设备
break;
case __S_IFCHR:
perms[0] = 'c'; // 字符设备
break;
case __S_IFSOCK:
perms[0] = 's'; // 套接字
break;
case __S_IFIFO:
perms[0] = 'p'; // 管道
break;
default:
perms[0] = '?'; // 未知类型
break;
}
// 2. 文件权限
// 文件所有者权限
perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
// 文件所在组权限
perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
// 其他人权限
perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
perms[10] = '\0'; // 字符串结束符
// 3. 硬链接数
int linknum = st.st_nlink;
// 4. 文件所有者名称
char* fileuser = getpwuid(st.st_uid)->pw_name;
// 5. 文件所在组
char* filegroup = getgrgid(st.st_gid)->gr_name;
// 6. 文件大小
long int filesize = st.st_size;
// 7. 修改时间
char* time = ctime(&st.st_mtime);
char mtime[512] = {0};
strncpy(mtime, time, strlen(time) - 1); // 去除末尾的换行符
// 格式化输出
char buf[1024];
sprintf(buf, "%s %d %s %s %ld %s %s",
perms, linknum, fileuser, filegroup, filesize, mtime, argv[1]);
printf("%s\n", buf);
return 0;
}
1. stat系统调用
stat()
函数是获取文件信息的核心系统调用,它填充一个stat
结构体,包含文件的所有元数据:
- 文件类型和权限(st_mode)
- 硬链接数量(st_nlink)
- 所有者和组ID(st_uid, st_gid)
- 文件大小(st_size)
- 最后修改时间(st_mtime)
2. 文件类型识别
通过st_mode & __S_IFMT
这种掩码的方式,可以提取文件类型信息,常见的文件类型包括:
- 普通文件(-)
- 目录(d)
- 符号链接(l)
- 字符设备(c)
- 块设备(b)
- 套接字(s)
- 管道(p)
3. 权限位处理
文件权限分为三组:所有者、组和其他用户,每组包含读(r)、写(w)和执行(x)权限。通过位掩码操作可以检查每位权限设置。
4. 用户和组信息转换
使用getpwuid()
和getgrgid()
函数将UID和GID转换为可读的用户名和组名。
5. 时间格式处理
ctime()
将时间戳转换为可读字符串,但包含换行符,需要去除末尾的换行符。
示例:
ll输出:

脚本输出:
