ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api:

opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列

readdir:struct dirent *readdir(DIR *dirp), 把opendir的返回值传过来,   返回值为一个结构体

        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[]; /* filename */
};

有了这两个api,就可以实现一个简易的ls功能

 /*================================================================
* Copyright (C) 2018 . All rights reserved.
*
* 文件名称:myls.c
* 创 建 者:ghostwu(吴华)
* 创建日期:2018年01月09日
* 描 述: ls命令
*
================================================================*/ #include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h> void do_ls( char [] ); int main(int argc, char *argv[])
{
if( argc == ) {
do_ls( "." );
}else {
while( --argc ) {
printf( "arg=%s\n", * ++argv );
do_ls( *argv );
}
}
return ;
} void do_ls( char dir_entry[] ) {
DIR* pDir;
struct dirent* pCurDir;
if( ( pDir = opendir( dir_entry ) ) == NULL ){
perror( "read dir" );
exit( - );
}else {
while( ( pCurDir = readdir( pDir ) ) != NULL ) {
printf( "%s\n", pCurDir->d_name );
}
}
}

这个简易的ls功能,列举出了所有的文件( 包括隐藏的 ), 但是很多的信息不全,如: 权限,用户和组,修改时间,文件大小,链接数目等,stat这个api可以获取文件的这些信息

stat:获取文件状态信息

原型:int stat(const char *pathname, struct stat *buf), 第一个参数:文件名, 第二个参数:保存文件状态信息的结构体( man 2 stat 有结构体相关说明 )

1、获取文件的大小

 /*================================================================
* Copyright (C) 2018 . All rights reserved.
*
* 文件名称:stat.c
* 创 建 者:ghostwu(吴华)
* 创建日期:2018年01月09日
* 描 述:
*
================================================================*/ #include <stdio.h>
#include <sys/stat.h> #define FILENAME "/etc/passwd" int main(int argc, char *argv[])
{
struct stat filestat; if( - == stat( FILENAME, &filestat ) ) {
perror( "file stat" );
return -;
}else {
printf( "the size of %s is %ld\n",FILENAME, filestat.st_size );
} return ;
}

2、读取文件st_mode(权限位), 用户id, 组id, 修改时间,链接数目

 /*================================================================
* Copyright (C) 2018 . All rights reserved.
*
* 文件名称:stat2.c
* 创 建 者:ghostwu(吴华)
* 创建日期:2018年01月09日
* 描 述:
*
================================================================*/ #include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h> void show_info( char *file, struct stat* statinfo );
void show_time( time_t filetime );
char* format_time( char* dsttime, const char* srctime ); int main(int argc, char *argv[])
{
struct stat fileinfo;
if( argc > ) {
/*调试信息
printf( "%s\n", argv[1] );
int res = stat( argv[1], &fileinfo );
printf( "%d\n", res );
*/
if( stat( argv[], &fileinfo ) != - ) {
show_info( argv[], &fileinfo );
}
}else {
perror( "get args from terminal" );
} return ;
} void show_info( char* file, struct stat* statinfo ){
printf( "%s文件信息如下:\n", file );
printf( "st_mode = %d\n", statinfo->st_mode );
printf( "links = %ld\n", statinfo->st_nlink );
printf( "uid = %d\n", statinfo->st_uid );
printf( "gid = %d\n", statinfo->st_gid );
printf( "file size = %ld\n", statinfo->st_size );
show_time( statinfo->st_mtime );
} void show_time( time_t filetime ) {
struct tm* ptm;
ptm = localtime( &filetime ); int month = ptm->tm_mon + ;
int day = ptm->tm_mday;
int hour = ptm->tm_hour;
int min = ptm->tm_min; char srchour[] = "";
char srcmin[] = "";
char dsthour[] = "";
char dstmin[] = "";
sprintf( srchour, "%d", hour );
sprintf( srcmin, "%d", min );
format_time( dsthour, srchour );
format_time( dstmin, srcmin ); printf( "文件最后修改时间: %d月\t%d\t%s:%s\n", month, day, dsthour, dstmin );
} char* format_time( char* dsttime, const char* srctime ) {
if( strlen( srctime ) < ) {
return strcat( dsttime, srctime );
}
return strcpy( dsttime, srctime );
}

3、权限st_mode转字符权限位( 如: -rwxrwxrwx ), 用户id和组id转用户名和组名称,判断文件类型

 /*================================================================
* Copyright (C) 2018 . All rights reserved.
*
* 文件名称:stat3.c
* 创 建 者:ghostwu(吴华)
* 创建日期:2018年01月09日
* 描 述:文件类型与权限位
*
================================================================*/ #include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h> void do_ls( char* filename );
void show_filetype( char* filename, int filemode );
void show_filetype2( char* filename, int filemode );
void mode_to_letters( int filemode, char str[] );
//用户id转名称
char* uid_to_name( uid_t uid );
//组id转名称
char* gid_to_name( gid_t gid ); int main(int argc, char *argv[])
{
if( argc < ) {
printf( "usage:%s file\n", argv[] );
return -;
}else {
do_ls( argv[] );
}
return ;
} char* uid_to_name( uid_t uid ){
return getpwuid( uid )->pw_name;
} char* gid_to_name( gid_t gid ){
return getgrgid( gid )->gr_name;
} void do_ls( char* filename ) {
struct stat fileinfo;
if( stat( filename, &fileinfo ) == - ) {
printf( "%s open failure\n", filename );
exit( - );
}
//printf( "st_mode = %d\n", fileinfo.st_mode );
show_filetype( filename, fileinfo.st_mode );
show_filetype2( filename, fileinfo.st_mode );
char file_permission[];
mode_to_letters( fileinfo.st_mode, file_permission );
printf( "%s\n", file_permission );
printf( "用户:%s\n", uid_to_name( fileinfo.st_uid ) );
printf( "组:%s\n", gid_to_name( fileinfo.st_gid ) );
} //掩码判断文件类型
void show_filetype( char* filename, int filemode ){
//用st_mode的值跟0170000这个掩码相位与的结果 判断文件类型
if ( ( filemode & ) == ){
printf( "%s是普通文件\n", filename );
}else if( ( filemode & ) == ){
printf( "%s是目录\n", filename );
}else if ( ( filemode & S_IFMT ) == S_IFLNK ){
printf( "%s是符号链接\n", filename );
}
} //用宏判断文件类型
void show_filetype2( char* filename, int filemode ){
if( S_ISREG( filemode ) ) {
printf( "%s是普通文件\n", filename );
}else if( S_ISDIR( filemode ) ) {
printf( "%s是目录\n", filename );
}else if( S_ISLNK( filemode ) ){
printf( "%s是符号链接\n", filename );
}
} //数字解码成字母权限位
void mode_to_letters( int filemode, char str[] ) {
strcpy( str, "----------" );
if( S_ISREG( filemode ) ) str[] = '-';
if( S_ISDIR( filemode ) ) str[] = 'd';
if( S_ISLNK( filemode ) ) str[] = 'l'; //用户权限位
if( filemode & S_IRUSR ) str[] = 'r';
if( filemode & S_IWUSR ) str[] = 'w';
if( filemode & S_IXUSR ) str[] = 'x'; //组权限位
if( filemode & S_IRGRP ) str[] = 'r';
if( filemode & S_IWGRP ) str[] = 'w';
if( filemode & S_IXGRP ) str[] = 'x'; //其他组权限位
if( filemode & S_IROTH ) str[] = 'r';
if( filemode & S_IWOTH ) str[] = 'w';
if( filemode & S_IXOTH ) str[] = 'x';
}

综合上面3个小实例,可以得到格式化比较好的ls命令版本:

 /*================================================================
* Copyright (C) 2018 . All rights reserved.
*
* 文件名称:myls2.c
* 创 建 者:ghostwu(吴华)
* 创建日期:2018年01月09日
* 描 述:ls命令( version 1.2 )
*
================================================================*/ #include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <time.h> void do_ls( char [] );
void do_stat( char* filename );
void show_list( char* filename, struct stat* statinfo );
void mode_to_letters( mode_t filemode, char str[] );
void show_time( time_t filetime );
char* format_time( char* dsttime, const char* srctime ); //用户id转名称
char* uid_to_name( uid_t uid );
//组id转名称
char* gid_to_name( gid_t gid ); int main(int argc, char *argv[])
{
if( argc == ) {
do_ls( "." );
}else {
while( --argc ) {
printf( "arg=%s\n", * ++argv );
do_ls( *argv );
}
}
return ;
} void do_ls( char dir_entry[] ) {
DIR* pDir;
struct dirent* pCurDir;
if( ( pDir = opendir( dir_entry ) ) == NULL ){
perror( "read dir" );
exit( - );
}else {
while( ( pCurDir = readdir( pDir ) ) != NULL ) {
do_stat( pCurDir->d_name );
}
closedir( pDir );
}
} //得到文件信息
void do_stat( char* filename ){
struct stat statinfo;
if ( stat( filename, &statinfo ) == - ) {
printf( "打开%s失败\n", filename );
exit( - );
}else {
show_list( filename, &statinfo );
}
} //显示文件列表
void show_list( char* filename, struct stat* statinfo ) {
mode_t st_mode = statinfo->st_mode; char str[];
mode_to_letters( st_mode, str );
printf( "%s\t", str ); printf( "%ld\t", statinfo->st_nlink ); //符号链接
printf( "%s\t\t", uid_to_name( statinfo->st_uid ) ); //用户名
printf( "%s\t", gid_to_name( statinfo->st_gid ) ); //组名
printf( "%10ld", statinfo->st_size ); //文件大小
show_time( statinfo->st_mtime ); //最后一次修改时间
printf( "\t%s", filename ); printf( "\n" );
} char* uid_to_name( uid_t uid ){
return getpwuid( uid )->pw_name;
} char* gid_to_name( gid_t gid ){
return getgrgid( gid )->gr_name;
} void mode_to_letters( mode_t filemode, char str[] ) { strcpy( str, "----------" );
if( S_ISREG( filemode ) ) str[] = '-';
if( S_ISDIR( filemode ) ) str[] = 'd';
if( S_ISLNK( filemode ) ) str[] = 'l'; //用户权限位
if( filemode & S_IRUSR ) str[] = 'r';
if( filemode & S_IWUSR ) str[] = 'w';
if( filemode & S_IXUSR ) str[] = 'x'; //组权限位
if( filemode & S_IRGRP ) str[] = 'r';
if( filemode & S_IWGRP ) str[] = 'w';
if( filemode & S_IXGRP ) str[] = 'x'; //其他组权限位
if( filemode & S_IROTH ) str[] = 'r';
if( filemode & S_IWOTH ) str[] = 'w';
if( filemode & S_IXOTH ) str[] = 'x';
} void show_time( time_t filetime ) {
struct tm* ptm;
ptm = localtime( &filetime ); int month = ptm->tm_mon + ;
int day = ptm->tm_mday;
int hour = ptm->tm_hour;
int min = ptm->tm_min; char srchour[] = "";
char srcmin[] = "";
char dsthour[] = "";
char dstmin[] = "";
sprintf( srchour, "%d", hour );
sprintf( srcmin, "%d", min );
format_time( dsthour, srchour );
format_time( dstmin, srcmin ); printf( "%4d月%4d%4s:%2s", month, day, dsthour, dstmin );
} char* format_time( char* dsttime, const char* srctime ) {
if( strlen( srctime ) < ) {
return strcat( dsttime, srctime );
}
return strcpy( dsttime, srctime );
}

总结:

1)opendir和readdir的用法

2)结构体struct dirent的应用

3)stat的用法

linux系统编程:自己动手写一个ls命令的更多相关文章

  1. Linux系统编程【3.2】——ls命令优化版和ls -l实现

    前情提要 在笔者的上一篇博客Linux系统编程[3.1]--编写ls命令中,实现了初级版的ls命令,但是与原版ls命令相比,还存在着显示格式和无颜色标记的不同.经过笔者近两天的学习,基本解决了这两个问 ...

  2. Linux系统编程【2】——编写who命令

    学到的知识点 通过实现who命令,学到了: 1.使用man命令寻找相关信息 2.基于文件编程 3.体会到c库函数与系统调用的不同 4.加深对缓冲技术的理解 who命令的作用 who命令的使用 在控制终 ...

  3. linux系统编程综合练习-实现一个小型的shell程序(一)

    之前已经花了不少篇幅学习了linux系统编程的很多知识点:文件与io.进程.信号.管道,而零散的知识点,怎么能够综合的串接起来是学习的一个很重要的目的,当然最好的方式就是用所学的知识点做一个项目了,所 ...

  4. linux系统编程:自己动手写一个cp命令

    cp命令的基本用法: cp 源文件 目标文件 如果目标文件不存在 就创建, 如果存在就覆盖 实现一个cp命令其实就是读写文件的操作: 对于源文件: 把内容全部读取到缓存中,用到的函数read 对于目标 ...

  5. linux系统编程综合练习-实现一个小型的shell程序(四)

    上节中已经对后台作业进行了简单处理,基本上要实现的功能已经完了,下面回过头来,对代码进行一个调整,把写得不好的地方梳理一下,给代码加入适当的注释,这种习惯其实是比较好了,由于在开发的时候时间都比较紧, ...

  6. linux系统编程综合练习-实现一个小型的shell程序(三)

    上节中已经实现了对普通命令的解析,包括输入重定向,输出重定向,管道,后台作业,这次就来执行已经解析好的命令,对应的函数为:execute_command(),首先对带有管道的命令进行执行: 比如:&q ...

  7. linux系统编程综合练习-实现一个小型的shell程序(二)

    上节minishell当中,已经初步实现了一个简单命令的解析,这节来继续对更加复杂命令进行解析,包含:输入重定向的解析.管道行的解析.输出重定向的解析以及是否有后台作业的解析,如下: 下面对其进行实现 ...

  8. Linux系统编程(14)——shell常用命令

    1. ls命令 ls命令是列出目录内容(ListDirectory Contents)的意思.运行它就是列出文件夹里的内容,可能是文件也可能是文件夹. "ls -l"命令已详情模式 ...

  9. Linux系统编程【1】——编写more命令

    背景介绍 笔者知识背景 笔者接触Linux快一年了.理论知识方面:学习了操作系统基础知识,了解进程调度.内存分配.文件管理.磁盘I/O这些基本的概念. 实操方面:会使用Linux简单命令,在嵌入式系统 ...

随机推荐

  1. Celery启动Django项目:Client sent AUTH, but no password is set 错误处理

    celery -A CeleryTest worker -l info [2017-02-22 07:26:52,666: ERROR/MainProcess] consumer: Cannot co ...

  2. Service Fabric学习-从helloworld开始(无状态服务)

    原先做服务器程序, 都是部署在xx云上, 也没理解云是个啥, 不就是个服务器(虚拟机)租赁商吗? 好吧, 其实这个是IaaS, 而接下来要学习的ServiceFabric(以下简称SF)是PaaS. ...

  3. 如何在Notepad++里正确设置java环境(图文环境)

    不多说,直接上干货! 这款软件非常好用!!! Notepad++软件的下载与安装步骤(图文详解) 欢迎大家,加入我的微信公众号:大数据躺过的坑        人工智能躺过的坑       同时,大家可 ...

  4. JavaScript -- Window-Scroll

    -----037-Window-Scroll.html----- <!DOCTYPE html> <html> <head> <meta http-equiv ...

  5. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(八):MyBatis分页功能实现

    使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真不想花双倍的时间写 count 和 select,幸 ...

  6. Redis3.2.4 Cluster集群搭建

    服务器环境:192.168.1.105192.168.1.160每台服务器搭建3个节点,组成3个主节点,3个从节点的redis集群. 注意:防火墙一定要开放监听的redis端口,否则会创建失败. 一. ...

  7. filebeat-2-通过kafka队列链接logstash

    filebeat 直接到logstash, 由于logstash的设计问题, 可能会出现阻塞问题, 因为中间使用消息队列分开 可以使用redis, 或者kafka, 这儿使用的是kafka 1, 安装 ...

  8. 非Spring环境下使用Mybatis操作数据库的流程

    准备工作 1,  导入mybatis-3.2.7.jar,mysql-connector-5.1.25-bin.jar两个jar包 2,  在数据库中创建一个db_test数据库,库中有一个表为use ...

  9. java Multimap

    实现 { "a": [ , , ], "b": [ , ] } 当然, HashMap<String, List<Integer>> 是 ...

  10. JavaScript实现二叉树算法

    二叉树的遍历方式 分别为中序遍历(左子树->当前节点->右子树).前序遍历(当前节点->左子树->右子树).后序遍历(左子树->右子树->当前节点).下面使用Jav ...