在linux下编写一个LS命令的小程序
- 格式:doc
- 大小:29.50 KB
- 文档页数:1
LinuxUNIX编程:使⽤C语⾔实现ls命令刚好把 Linux/UNIX 编程中的⽂件和IO部分学完了,就想编写个 ls 命令练习⼀下,本以为很简单,调⽤个 stat 就完事了,没想到前前后后弄了七⼋个⼩时,90%的时间都⽤在格式化(像 ls -l 中的对齐)输出了,反反复复改了好⼏遍。
⼀共实现了常⽤的四个选项:-a -h -l -d。
可以从命令⾏参数中同时接受多个⽬录和⽂件,然后分开输出。
演⽰:-a 命令:-l 和 -h 命令:-d 命令:参数同时接受多个⽂件和⽬录名:思路:先使⽤ getopt 解析选项然后判断参数有没有⽬录或⽂件(通过 operand 标志变量),没有的话仅输出进程当前⽬录有的话将参数中的⽂件和⽬录分开(files 和 dirs数组),然后输出信息因为要格式化输出,所以得将⽬录中所有项⽬读取完成后并转换成字符串形式(get_stat_str)才能获得长度最长的某个信息(如,⽂件名,尺⼨),⽽⽬录中的⽂件数⽬⼜事先不可知,所以⽤链表结构(stat_str)将所有⽬录中所有⽂件的信息存储下来。
代码:#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#include <errno.h>#include <string.h>#include <limits.h>#include <pwd.h>#include <grp.h>#define err_exit(func) {perror(func); exit(EXIT_FAILURE);} //打印出错函数,并结束程序#define max(a, b) ((a) > (b) ? (a) : (b))typedef struct stat_str{ //字符串形式的stat信息char fname[NAME_MAX]; //⼤概长度,不严谨char user[20];char group[20];char size[16];char time[13];char mode[11];char nlink[5];struct stat_str *next; //链表结构,因为需要预先获得⽬录⾥的所有项(为了控制格式化),但数⽬不确定,所以⽤链表保存} st_str;int nlink_maxlen = 0, user_maxlen = 0, group_maxlen = 0, size_maxlen = 0; //字符串形式的最⼤长度,为了格式化构造字符串int ARG_L = 0, ARG_A = 0, ARG_H = 0, ARG_D = 0; //参数是否定义//解析选项void analyse_opt(int argc, char* argv[]);//将⽂件⼤⼩(字节数)转换成易读(human readable)的形式void human_readable(off_t bytes, char *szbuf);//构造⽂件的详细信息void build_line(const st_str *stat_strbuf, char* fmtstrbuf);//打印⽬录信息void print_dir_info(const char *dir);//获得⽂件信息的str形式void get_stat_str(const struct stat* stbuf, const char* fname, st_str *strbuf);int main(int argc, char* argv[]) {struct stat stbuf;st_str st_strbuf;int no_operand = 1; //是否没有操作数analyse_opt(argc, argv); //解析选项//分别获得⽬录和其他⽂件,为了格式化输出char *files[argc-1], *dirs[argc-1];int nf = 0, nd = 0;for(int i = 1; i < argc; i++){if(argv[i][0] == '-') //跳过选项continue;elseno_operand = 0;if(-1 == lstat(argv[i], &stbuf))err_exit("lstat");if(S_ISDIR(stbuf.st_mode))dirs[nd++] = argv[i];elsefiles[nf++] = argv[i];}if(no_operand){//命令⾏没有输⼊路径print_dir_info(".");} else {//先列出⽂件的信息for(int i = 0; i < nf; i++){char fmtstrbuf[256];if(-1 == lstat(files[i], &stbuf))err_exit("lstat");get_stat_str(&stbuf, files[i], &st_strbuf);if(ARG_L){build_line(&st_strbuf, fmtstrbuf);puts(fmtstrbuf);} else {puts(files[i]);}}//再列出⽬录的信息for(int i = 0; i < nd; i++){if(nf > 0)printf("\n%s:\n", dirs[i]);print_dir_info(dirs[i]);}}return 0;}void analyse_opt(int argc, char* argv[]){int opt;while((opt = getopt(argc, argv, "lahd")) != -1){switch (opt) {case 'l':ARG_L = 1;break;case 'a':ARG_A = 1;break;case 'h':ARG_H = 1;break;case 'd':ARG_D = 1;break;}}}void human_readable(off_t nbytes, char *szbuf){if(nbytes < 1024)sprintf(szbuf, "%ld\0", nbytes);else if(nbytes < 1024 * 1024)sprintf(szbuf, "%.1lfK\0", (double)nbytes / 1024);else if(nbytes < 1024 * 1024 * 1024)sprintf(szbuf, "%.1lfM\0", (double)nbytes / 1024 / 1024);elsesprintf(szbuf, "%.1lfG\0", (double)nbytes / 1024 / 1024 / 1024);}void get_stat_str(const struct stat* stbuf, const char* fname, st_str *strbuf){//modesprintf(strbuf->mode, "%c%c%c%c%c%c%c%c%c%c",S_ISREG(stbuf->st_mode) ? '-' : (S_ISDIR(stbuf->st_mode) ? 'd' : (S_ISBLK(stbuf->st_mode) ? 'b' : (S_ISCHR(stbuf->st_mode) ? 'c' : 'l'))),(S_IRUSR & stbuf->st_mode ) ? 'r' : '-',(S_IWUSR & stbuf->st_mode ) ? 'w' : '-',(S_IXUSR & stbuf->st_mode ) ? 'x' : '-',(S_IRGRP & stbuf->st_mode ) ? 'r' : '-',(S_IWGRP & stbuf->st_mode ) ? 'w' : '-',(S_IXGRP & stbuf->st_mode ) ? 'x' : '-',(S_IROTH & stbuf->st_mode ) ? 'r' : '-',(S_IWOTH & stbuf->st_mode ) ? 'w' : '-',(S_IXOTH & stbuf->st_mode ) ? 'x' : '-');//nlinksprintf(strbuf->nlink, "%ld\0", stbuf->st_nlink);nlink_maxlen = max(nlink_maxlen, strlen(strbuf->nlink));//user, groupsprintf(strbuf->user, "%s\0", getpwuid(stbuf->st_uid)->pw_name);sprintf(strbuf->group, "%s\0", getgrgid(stbuf->st_gid)->gr_name);user_maxlen = max(user_maxlen, strlen(strbuf->user));group_maxlen = max(group_maxlen, strlen(strbuf->group));//sizeif(ARG_H){char szbuf[16];human_readable(stbuf->st_size, szbuf);sprintf(strbuf->size, "%s\0", szbuf);} else {sprintf(strbuf->size, "%ld\0", stbuf->st_size);}size_maxlen = max(size_maxlen, strlen(strbuf->size));//timestrftime(strbuf->time, 13, "%b %d %H:%M\0", localtime(&(stbuf->st_mtime)));//fnamesprintf(strbuf->fname, "%s\0", fname);}void build_line(const st_str *stat_strbuf, char* fmtstrbuf){char fmt[32];sprintf(fmt, "%%s %%%ds %%-%ds %%-%ds %%%ds %%s %%s\0", nlink_maxlen, user_maxlen, group_maxlen, size_maxlen); // puts(fmt);if((stat_strbuf->mode)[0] == 'd')strcat(stat_strbuf->fname, "/");sprintf(fmtstrbuf, fmt, stat_strbuf->mode, stat_strbuf->nlink, stat_strbuf->user,stat_strbuf->group, stat_strbuf->size, stat_strbuf->time, stat_strbuf->fname);}void print_dir_info(const char *dir){if(ARG_D){//显式⽬录本⾝的信息st_str stat_strbuf;struct stat stbuf;char fmtstrbuf[256];if(-1 == lstat(dir, &stbuf))err_exit("lstat");get_stat_str(&stbuf, dir, &stat_strbuf);if(ARG_L){build_line(&stat_strbuf, fmtstrbuf);puts(fmtstrbuf);} else {puts(stat_strbuf.fname);}} else {group_maxlen = nlink_maxlen = user_maxlen = size_maxlen = 0;//列出⽬录所有项struct DIR *pdir = opendir(dir);if(pdir == NULL)err_exit("opendir");struct dirent *pdirent;struct stat stbuf;st_str * head_st_str = (st_str*)(malloc(sizeof(st_str))), *p = head_st_str; //链表头(字符串形式的stat) //循环都⽬录errno = 0;while((pdirent = readdir(pdir)) != NULL){if((pdirent->d_name)[0] != '.' || ARG_A) {//是否显⽰隐藏⽂件if(ARG_L) {char path[256];strcpy(path, dir); // 找了⼀个多⼩时才找出来这个错误strcat(path, "/"); // d_name仅是个⽂件名⽽已strcat(path, pdirent->d_name); // 需要加上完整路径if(-1 == lstat(path, &stbuf)){err_exit("lstat");}p->next = (st_str*)(malloc(sizeof(st_str)));p = p->next;p->next = NULL;get_stat_str(&stbuf, pdirent->d_name, p);} else {puts(pdirent->d_name);}}}if(errno != 0)err_exit("readdir");//输出信息链表的格式化内容p = head_st_str->next;while(ARG_L && p){char fmtstrbuf[256];build_line(p, fmtstrbuf);puts(fmtstrbuf);p = p->next;}if(-1 == closedir(pdir))err_exit("closedir");st_str *q = head_st_str->next; //释放链表while(q){free(head_st_str);head_st_str = q;q = q->next;}free(head_st_str);}}。
linuxlsll命令参数及使⽤⽅法的详解⼀.ls命令列出制定⽂件下或当前⽬录⽤法:ls [选项]... [⽂件]...列出 FILE 的信息(默认为当前⽬录)。
如果不指定-cftuvSUX 或--sort 选项,则根据字母⼤⼩排序。
长选项必须使⽤的参数对于短选项时也是必需使⽤的。
-a, --all 不隐藏任何以. 开始的项⽬-A, --almost-all 列出除. 及.. 以外的任何项⽬--author 与-l 同时使⽤时列出每个⽂件的作者-b, --escape 以⼋进制溢出序列表⽰不可打印的字符--block-size=⼤⼩块以指定⼤⼩的字节为单位-B, --ignore-backups 不列出任何以"~"字符结束的项⽬-c 配合-lt:根据ctime 排序并显⽰ctime(⽂件状态最后更改的时间)配合-l:显⽰ctime 但根据名称排序其他情况:按ctime 排序-C 每栏由上⾄下列出项⽬--color[=WHEN] 控制是否使⽤⾊彩分辨⽂件。
WHEN 可以是"never"(默认)、"always"或"auto"其中之⼀-d, --directory 当遇到⽬录时列出⽬录本⾝⽽⾮⽬录内的⽂件-D, --dired 产⽣适合Emacs 的dired 模式使⽤的结果-f 不进⾏排序,-aU 选项⽣效,-lst 选项失效-F, --classify 加上⽂件类型的指⽰符号(*/=@| 其中⼀个)--format=关键字交错-x,逗号分隔-m,⽔平-x,长-l,单栏-1,详细-l,垂直-C--full-time 即-l --time-style=full-iso-g 类似-l,但不列出所有者--group-directories-first在⽂件前分组⽬录。
此选项可与--sort ⼀起使⽤,但是⼀旦使⽤--sort=none (-U)将禁⽤分组-G, --no-group 以⼀个长列表的形式,不输出组名-h, --human-readable 与-l ⼀起,以易于阅读的格式输出⽂件⼤⼩(例如 1K 234M 2G)--si 同上⾯类似,但是使⽤1000 为基底⽽⾮1024-H, --dereference-command-line跟随命令⾏列出的符号链接--dereference-command-line-symlink-to-dir跟随命令⾏列出的⽬录的符号链接--hide=PATTERN 隐藏符合PATTERN 模式的项⽬(-a 或 -A 将覆盖此选项)--indicator-style=⽅式指定在每个项⽬名称后加上指⽰符号⽅式:none (默认),classify (-F),file-type (-p)-i, --inode 显⽰每个⽂件的inode 号-I, --ignore=PATTERN 不显⽰任何符合指定shell PATTERN 的项⽬-k 即--block-size=1K-l 使⽤较长格式列出信息-L, --dereference 当显⽰符号链接的⽂件信息时,显⽰符号链接所指⽰的对象⽽并⾮符号链接本⾝的信息-m 所有项⽬以逗号分隔,并填满整⾏⾏宽-n, --numeric-uid-gid 类似 -l,但列出UID 及GID 号-N, --literal 输出未经处理的项⽬名称 (如不特别处理控制字符)-o 类似 -l,但不列出有关组的信息-p, --indicator-style=slash 对⽬录加上表⽰符号"/"-q, --hide-control-chars 以"?"字符代替⽆法打印的字符--show-control-chars 直接显⽰⽆法打印的字符 (这是默认⽅式,除⾮调⽤的程序名称是"ls"⽽且是在终端输出结果)-Q, --quote-name 将条⽬名称括上双引号--quoting-style=⽅式使⽤指定的quoting ⽅式显⽰条⽬的名称:literal、locale、shell、shell-always、c、escape-r, --reverse 排序时保留顺序-R, --recursive 递归显⽰⼦⽬录-s, --size 以块数形式显⽰每个⽂件分配的尺⼨-S 根据⽂件⼤⼩排序--sort=WORD 以下是可选⽤的WORD 和它们代表的相应选项:extension -X status -cnone -U time -tsize -S atime -utime -t access -uversion -v use -u--time=WORD 和-l 同时使⽤时显⽰WORD 所代表的时间⽽⾮修改时间:atime、access、use、ctime 或status;加上--sort=time 选项时会以指定时间作为排序关键字--time-style=STYLE 和-l 同时使⽤时根据STYLE 代表的格式显⽰时间:full-iso、iso、locale、posix-iso、+FORMAT。
使用ls命令在Linux终端中列出文件和目录在Linux操作系统中,使用终端是一种常见的管理文件和目录的方式。
而其中一个最基本也最常用的命令就是ls命令。
ls命令用于列出当前目录下的文件和目录,并且可以通过一些参数来展示更详细的信息。
在本文中,我们将深入介绍ls命令的使用方法和相关的参数。
1. 基本的ls命令使用ls命令的基本语法如下:```bashls [选项] [文件或目录]```没有指定选项和文件或目录时,ls命令会默认列出当前目录下的文件和目录。
例如,输入以下命令:```bashls```它将输出当前目录下的所有文件和目录的名称。
如果想更详细地列出文件和目录的信息,可以使用-l选项,如下所示:```bashls -l```上述命令将以长格式(详细信息)列出当前目录下的文件和目录。
长格式包括文件的权限、所有者、大小、修改日期等信息。
2. 列出指定目录的文件和目录除了默认列出当前目录的文件和目录,ls命令还可以列出指定目录下的文件和目录。
只需在ls命令后面跟上目录路径即可,例如:```bashls /path/to/directory```上述命令将列出指定目录下的所有文件和目录的名称。
3. 列出隐藏文件在Linux系统中,以点开头的文件被认为是隐藏文件,它们默认不会在普通的ls命令输出中显示。
如果想列出所有文件,包括隐藏文件,可以使用-a选项,如下所示:```bashls -a```上述命令将列出当前目录下的所有文件和目录,包括隐藏文件。
4. 列出文件大小和权限默认情况下,ls命令只显示文件和目录的名称。
如果想查看文件的大小和权限等详细信息,可以使用-l选项,如下所示:```bashls -l```上述命令将以长格式列出当前目录下的文件和目录,并显示文件的大小、权限、所有者等信息。
5. 显示更多详细信息除了上述的文件大小和权限等信息,ls命令还可以通过其他选项来显示更多的信息。
例如,使用-h选项可以以人类可读的方式显示文件大小,如下所示:```bashls -lh```上述命令将以长格式列出当前目录下的文件和目录,并以易读的方式显示文件的大小。
Linux-ls命令模拟////ls.c//wxd////create by jneeyou on15/11/13//Copyright(c)2015wxd.All rights reserved.//#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include"ls_fileHandle.h"/**主函数**/int main(int argc,char*argv[]){int mask=0;bool ret=false;freopen(".err.dat","wb",stderr);if(!init()){return-1;}mask=getCmdLineArgs(argc,argv);if(mask==-2)//--help命令{getHelpMenu();//显示帮助}else if(mask==ERROR){printf("参数有误,输入\"./ls--help\"查看帮助\n");}else//其他命令{setMaskArray(mask);ret=getDirInfo(".",0);if(!ret){printf("参数有误,输入\"./ls--help\"查看帮助\n");}freeMem();}system("rm-f.err.dat");return0;}////ls_fileHandle.h//wxd////create by jneeyou on15/11/13//Copyright(c)2015wxd.All rights reserved.//#ifndef__LS_FILE_HANDLE_H__#define__LS_FILE_HANDLE_H__//定义bool型#if!defined(bool)#define bool char#define true1#define false0#endif#ifndef ERROR#define ERROR-1#endif#if defined(__STDC__VERSION__)&&(__STDC__VERSION__>=199901L) //@desc宏函数,输出文件信息#define printf_c(fontBgColor,fontColor,format,args...) printf("\033[fontBgColor;fontColorm format\033[0m",args)#else//@desc输出文件信息//带颜色输出,可设置字体颜色和字体背景颜色extern int printf_c(char fontBgColor,char fontColor,const char*format,...);#endif//@desc获取命令行参数,返回掩码值extern int getCmdLineArgs(int argc,char*argv[]);//@desc设置掩码数组//@ret成功返回true,否则返回falseextern bool setMaskArray(int maskValue);//@desc获得文件信息//@ret成功返回true,否则返回falseextern bool getFileInfo(const char*dirName,const char*fileName,unsigned int index);//@desc获得目录信息//@ret成功返回true,否则返回falseextern bool getDirInfo(const char*dirName,int dirLevel);//@desc获得帮助菜单extern void getHelpMenu();//@desc释放内存void freeMem();//@desc初始化bool init();#endif//__LS_FILE_HANDLE_H__////ls_fileHandle.c//wxd////create by jneeyou on15/11/13//Copyright(c)2015wxd.All rights reserved. //#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/stat.h>#include<stdarg.h>#include<unistd.h>#include<dirent.h>#include<time.h>#include<math.h>#include<pwd.h>#include<grp.h>#include<sys/types.h>#ifndef ERROR#define ERROR-1#endif#define OK0#define NUL_POINTER NULL//定义bool,true,false#ifndef bool#define bool char#define true1#define false0#endif//帮助文件名#define HELP_FILE"helpInfo.dat"#define TMP_FILE".tmp~"//定义errno_t型#define errno_t int//定义文件类型#define block_file'b'#define direct_file'd'#define spec_char_file'c'#define fifo_device'p'#define regular_file'-'#define link_file'l'#define socket_file's'#define BF block_file//块文件#define DF direct_file//目录文件#define CF spec_char_file//特殊字符文件#define FD fifo_device//FIFO设备#define RF regular_file//普通文件#define LF link_file//符号链接文件#define SF socket_file//scoket文件//文件名最大长度#define MAX_FILE_NAME512//最多子目录个数#define MAX_SUB_DIR100//背景色typedef struct BG_COLOR{const char BLACK;//黑const char DARKRED;//深红const char GREEN;//绿const char YELLOW;//黄const char BLUE;//蓝const char PURPLE;//紫const char DARKGREEN;//深绿const char WHITE;//白const char DEFAULT;//默认}bgColor;//文字背景色static const bgColor font_bgColor={40,41,42,43,44,45,46,47,0};//前景色typedef struct FG_COLOR{const char BLACK;//黑const char RED;//红const char GREEN;//绿const char YELLOW;//黄const char BLUE;//蓝const char PURPLE;//紫const char DARKGREEN;//深绿const char WHITE;//白const char DEFAULT;//默认}fgColor;//文字颜色static const fgColor font_fgColor={30,31,32,33,34,35,36,37,0};//文件信息结构体typedef struct File_Info{ino_t ino;//节点号char type;//类型char perm[10];//权限nlink_t nlink;//硬链接数char uname[32];//用户名char gname[32];//所属组名off_t size;//大小time_t mtime;//最后修改时间char name[32];//文件名char lname[32];//链接的文件名char nameColor;//名字颜色char lnameColor;//链接文件颜色}fileInfo;#define MAX_FILE_NUM100//文件信息结构体数组static fileInfo*m_fileInfo=NULL;//已分配空间static unsigned int ALLOC_MEM_LEN=0;/////////////////////////////////////全局变量/////////////////////////////////////////////////掩码数组,根据每位元素值是否为1选择获取文件哪些//信息,每位元素对应一个ls命令参数,对应关系如下://maskArray[0]-->-l//maskArray[1]-->-a//maskArray[2]-->-R//maskArray[3]-->-r//maskArray[4]-->-d//maskArray[5]-->-i//maskArray[6]-->-S(大写S)//maskArray[7]-->-t//maskArray[8]-->-m//maskArray[9]-->-1(数字1)//maskArray[10]-->--help//maskArray[11]-->无参数//maskArray[12...15]-->保留static unsigned char maskArray[16]={0};//掩码数组有效长度#define VALID_LEN_ARRAY10//保存外部输入的文件名static char fileName[128][20]={""};//外部文件数目static int extFileNums=0;/////////////////////////////////////////////////////////////////////////////////////// ////////////////------------------------------------函数实现---------------------------------/////////////////////////////////////////////////////////////////////////////////////////////// ////////检查参数errno_t checkArgement(char arg){static const char allArgs[]={'l','a','R','r','d','i','S','t','m','1'};int len=strlen(allArgs);int i=0;for(i=0;i<len;i++){if(arg==allArgs[i])return i;}return ERROR;}//安全拷贝errno_t strcpy_s(char*_Dst,size_t_SizeInBytes,const char*_Src){char*ret=NULL;if(strlen(_Src)>_SizeInBytes){return ERROR;}ret=strcpy(_Dst,_Src);if(ret==NULL)return ERROR;return OK;}//安全打开errno_t fopen_s(FILE**_File,const char*_Filename,const char*_Mode){*_File=fopen(_Filename,_Mode);if(*_File==NULL)return ERROR;return OK;}//安全输出errno_t vsprintf_s(char*_DstBuf,size_t_SizeInBytes,const char*_Format,va_list _ArgList){errno_t ret=vsnprintf(_DstBuf,_SizeInBytes,_Format,_ArgList);return ret;}//获取命令行参数,返回掩码值int getCmdLineArgs(int argc,char*argv[]){int maskValue=0x0000;int fileCount=0;int i=0;for(i=1;i<argc;i++){if(!strcmp(argv[i],"--help")){return-2;}else if(argv[i][0]=='-'){int len=strlen(argv[i]);int ret=ERROR;while(--len){ret=checkArgement(argv[i][len]);if(ret==ERROR)return ERROR;maskValue|=(0x0001<<ret);}}else{strcpy_s(fileName[fileCount++],sizeof(fileName[0]),argv[i]);}}extFileNums=fileCount;return maskValue;}//设置掩码数组bool setMaskArray(int maskValue){long tmp=0x10000;int i=15;memset(maskArray,0,sizeof(maskArray));if(maskValue==0){maskArray[11]=1;return true;}while(!((tmp>>=1)&maskValue)&&tmp>0)i--;while(tmp>0){if(tmp&maskValue){maskArray[i--]=1;}else{maskArray[i--]=0;}tmp>>=1;}return true;}#if!(defined(__STDC__VERSION__)&&__STDC__VERSION__>=199901L)//@desc宏函数,带颜色输出,#format,将format对应的参数字符串化(为变量名时,不是变量中的值,而是变量名)#define PRINT_BY_COLOR(fontBgColor,Bold,fontColor,format,argsValue)printf("\033[%d;%02d;%dm"#format"\033[0m",fontBgColor,Bold,fontColor,argsValue)//输出文件信息int printf_c(char fontBgColor,char fontColor,const char*format,...){static char printf_buf[1024];va_list args;int n=0;int bold=0;va_start(args,format);n=vsprintf_s(printf_buf,sizeof(printf_buf),format,args);va_end(args);if(fontBgColor<40||fontBgColor>47){fontBgColor=font_bgColor.DEFAULT;}if(fontColor<30||fontColor>37){fontBgColor=font_fgColor.DEFAULT;}if(fontColor==font_fgColor.BLACK){bold=0;}PRINT_BY_COLOR(fontBgColor,bold,fontColor,"%s",printf_buf);return n;}#endif//通过uid获得用户名char*getUnameByUid(uid_t uid){struct passwd*m_pw;static char name[20]="";m_pw=getpwuid(uid);if(m_pw==NULL){return NUL_POINTER;}strcpy_s(name,sizeof(name),m_pw->pw_name);return name;}//通过gid获得组名char*getGnameByGid(gid_t gid){struct group*m_gr;static char name[20]="";m_gr=getgrgid(gid);if(m_gr==NULL){return NUL_POINTER;}strcpy_s(name,sizeof(name),m_gr->gr_name);return name;}//获取符号链接链接的文件名bool getFileNameBySLink(char*sLinkName,char*buf,size_t bufSize) {int len=0;len=readlink(sLinkName,buf,bufSize);buf[len]='\0';if(len>bufSize){perror("文件名过长,已被截取.");}return true;}//获取文件访问权限char*getFileAccePermis(mode_t st_mode){static char perm[9]="";char permValue[4]="xwr-";int i=0,len=9;for(i=0;i<len;i++){if(st_mode&(0x1<<i)){perm[len-i-1]=permValue[i%3];}else{perm[len-i-1]=permValue[3];}}return perm;}//获取文件类型char getFileType(mode_t st_mode){switch(st_mode&S_IFMT){case S_IFBLK:return BF;case S_IFDIR:return DF;case S_IFCHR:return CF;case S_IFIFO:return FD;case S_IFREG:return RF;case S_IFLNK:return LF;case S_IFSOCK:return SF;default:return ERROR;}}//通过文件类型获得文件名颜色char getFileColorByType(const char*fileName,char type){char cmd[3][512];char ret=font_fgColor.BLACK;if(type==DF)return font_fgColor.BLUE;if(type==LF)return font_fgColor.DARKGREEN;if(access(fileName,X_OK)==0)return font_fgColor.GREEN;//测试是否为压缩文件if(!system("mkdir tmp~")){sprintf(cmd[0],"tar-xf%s-C tmp~",fileName);sprintf(cmd[1],"tar-xzf%s-C tmp~",fileName);sprintf(cmd[2],"tar-xjf%s-C tmp~",fileName);if(!system(cmd[0])||!system(cmd[1])||!system(cmd[2])){ret=font_fgColor.RED;}}system("rm-Rf tmp~");return ret;}//获得文件信息bool getFileInfo(const char*dirName,const char*fileName,unsigned int index) {struct stat fileStat;char name[50];sprintf(name,"%s/%s",dirName,fileName);//数组已装满if(index>=ALLOC_MEM_LEN){m_fileInfo=(fileInfo*)realloc(m_fileInfo,sizeof(fileInfo)*ALLOC_MEM_LEN*2);ALLOC_MEM_LEN*=2;}//获取文件信息int ret=lstat(name,&fileStat);if(ret==-1){return false;}//节点号m_fileInfo[index].ino=fileStat.st_ino;//文件类型m_fileInfo[index].type=getFileType(fileStat.st_mode);//文件权限strcpy_s(m_fileInfo[index].perm,sizeof(m_fileInfo[index].perm), getFileAccePermis(fileStat.st_mode));//硬链接数m_fileInfo[index].nlink=fileStat.st_nlink;//用户名strcpy_s(m_fileInfo[index].uname,sizeof(m_fileInfo[index].uname), getUnameByUid(fileStat.st_uid));//组名strcpy_s(m_fileInfo[index].gname,sizeof(m_fileInfo[index].gname), getGnameByGid(fileStat.st_gid));//文件大小m_fileInfo[index].size=fileStat.st_size;//上次修改时间m_fileInfo[index].mtime=fileStat.st_mtime;return true;}//自定义排序函数int cmp(const void*a,const void*b){char tmpA,tmpB;fileInfo*fileInfoA=(fileInfo*)a;fileInfo*fileInfoB=(fileInfo*)b;if(maskArray[7]==1){return fileInfoA->mtime-fileInfoB->mtime;}else if(maskArray[6]==1){return fileInfoA->size-fileInfoB->size;}tmpA=fileInfoA->name[0];if(tmpA>='A'&&tmpA<='Z'){tmpA+='a'-'A';}tmpB=fileInfoB->name[0];if(tmpB>='A'&&tmpB<='Z'){tmpB+='a'-'A';}if(maskArray[3]==1){return tmpB-tmpA;}else{return tmpA-tmpB;}}//文件排序void sortFiles(fileInfo*pFileInfoArray,int elemNum){qsort(pFileInfoArray,elemNum,sizeof(pFileInfoArray[0]),cmp);}//移动输出位置void moveOutPos(int row,int col){char hori='A';//向上char vert='C';//向右if(row<0)//向下{hori='B';row=-row;}if(col<0)//向左{vert='D';col=-col;}printf("\033[%d%c\033[%d%c",row,hori,col,vert);}//通过掩码数组输出文件//返回输出内容长度int outFileByMaskArray(fileInfo cur_fileInfo,unsigned char maskArray[]) {int outputFlag=0;//是否输出标志char outStr[1024]="";//输出字符串int i=0;int len=0;//不带参数情况if(maskArray[11]==1){printf_c(font_bgColor.DEFAULT,cur_Color,"%s",cur_);return strlen(cur_);}//-l命令,长格式输出if(maskArray[0]){struct tm*mTime=localtime(&cur_fileInfo.mtime);char str[20]="";sprintf(str,"%4d.%02d.%02d%02d:%02d:%02d",mTime->tm_year+1900,mTime->tm_mon+1,mTime->tm_mday,mTime->tm_hour,mTime->tm_min,mTime->tm_sec);sprintf(outStr,"%c%s.%d%s%s%-8d%s",cur_fileInfo.type,cur_fileInfo.perm,cur_fileInfo.nlink,cur_fileInfo.uname,cur_fileInfo.gname,cur_fileInfo.size,str);}//-i命令,输出节点号inoif(maskArray[5]){char tmp[512]="";strcpy_s(tmp,sizeof(tmp),outStr);sprintf(outStr,"%d%s",cur_fileInfo.ino,tmp);}len=strlen(outStr);printf("%s",outStr);//输出文件信息if(maskArray[0]){printf("");len+=2;}len+=strlen(cur_);printf_c(font_bgColor.DEFAULT,cur_Color,"%s",cur_);//-l格式下的输出链接文件指向的文件if(maskArray[0]&&cur_fileInfo.type==LF){printf("->");printf_c(font_bgColor.DEFAULT,cur_fileInfo.lnameColor,"%s",cur_fileInfo.lname);len+=strlen(cur_fileInfo.lname)+4;}return len;}//获得目录信息bool getDirInfo(const char*dirName,int dirLevel){DIR*curDir=opendir(dirName);char linkedFile[MAX_FILE_NAME]="";char subDirFile[MAX_SUB_DIR][MAX_FILE_NAME];//保存目录文件int cnt_subDir=0;//子目录数int cnt_dirFiles=0;//目录下文件数int i=0,ret=0;static firCallFlag=1;//第一次调用标记int total_size=0;char tmp[MAX_FILE_NAME]="";struct stat m_stat;if(curDir==NULL){return false;}//-R命令时首先输出目录名if(maskArray[2]){for(i=0;i<dirLevel;i++){printf("\t");}printf("%s:\n",dirName);}struct dirent*m_dirent=NULL;while((m_dirent=readdir(curDir))!=NULL){if(!strcmp(".err.dat",m_dirent->d_name)){continue;}if(!strcmp(dirName,".")&&extFileNums>0){for(i=0;i<extFileNums;i++){if(!strcmp(fileName[i],m_dirent->d_name)){break;}}firCallFlag=0;if(i==extFileNums)continue;}//非-a命令时跳过隐藏文件if(m_dirent->d_name[0]=='.'&&maskArray[1]!=1){continue;}ret=getFileInfo(dirName,m_dirent->d_name,cnt_dirFiles);if(!ret||!strcmp(m_dirent->d_name,""))break;//-d命令跳过非目录文件if(maskArray[4]==1&&m_fileInfo[cnt_dirFiles].type!=DF) {continue;}sprintf(tmp,"%s/%s",dirName,m_dirent->d_name);strcpy_s(m_fileInfo[cnt_dirFiles].name,sizeof(m_fileInfo[cnt_dirFiles].name),m_dirent->d_name); m_fileInfo[cnt_dirFiles].nameColor=getFileColorByType( tmp,m_fileInfo[cnt_dirFiles].type);//获得链接的目标文件名if(m_fileInfo[cnt_dirFiles].type==LF){getFileNameBySLink(tmp,linkedFile,sizeof(linkedFile));strcpy_s(m_fileInfo[cnt_dirFiles].lname,sizeof(m_fileInfo[cnt_dirFiles].lname),linkedFile);lstat(linkedFile,&m_stat);sprintf(tmp,"%s/%s",dirName,linkedFile);m_fileInfo[cnt_dirFiles].lnameColor=getFileColorByType(tmp,getFileType(m_stat.st_mode));}//-R命令时保存子目录if(maskArray[2]&&m_fileInfo[cnt_dirFiles].type==DF){strcpy_s(subDirFile[cnt_subDir],sizeof(subDirFile[cnt_subDir]),m_fileInfo[cnt_dirFiles].name);cnt_subDir++;}total_size+=m_fileInfo[cnt_dirFiles].size;cnt_dirFiles++;firCallFlag=1;}if(firCallFlag==0){return false;}//排序输出文件sortFiles(m_fileInfo,cnt_dirFiles);//输出文件int col=4,row;int max_lenRowOfCol=0;//当前列最长行长度int total_lenRow=0;//当前行总长度int len=0,firColFlag=0;int j=0;row=cnt_dirFiles/col;row=(cnt_dirFiles*1.0/col>row)?row+1:row;if(maskArray[0]==1){if(maskArray[2]){for(j=0;j<dirLevel;j++){printf("\t");}}printf("file number:%d total size:%d\n",cnt_dirFiles,total_size);}for(i=1;i<=cnt_dirFiles;i++){if(maskArray[2]&&(i<=row||maskArray[0]||maskArray[9])) {for(j=0;j<dirLevel;j++){printf("\t");}}len=outFileByMaskArray(m_fileInfo[i-1],maskArray);if(maskArray[0]==1){printf("\n");}else if(maskArray[9]==1){printf("\n");}else if(maskArray[8]==1){if(i!=cnt_dirFiles)printf(",");}else{if(i==cnt_dirFiles){if(i%row!=0){moveOutPos(-(row-(i%row)),total_lenRow+len);}}else if(i%row==0){total_lenRow+=max_lenRowOfCol;max_lenRowOfCol=0;if(row>1)moveOutPos(row-1,-total_lenRow);printf("\033[%dC",total_lenRow+3);total_lenRow+=3;firColFlag=1;}else{if(max_lenRowOfCol<len){max_lenRowOfCol=len;}if(firColFlag)//不是首列{if(row>1)moveOutPos(-1,-len);}else{printf("\n");}}}}closedir(curDir);printf("\n");//递归遍历子目录char dirPath[50]="";if(maskArray[2]){for(i=0;i<cnt_subDir;i++){if(!strcmp(subDirFile[i],".")||!strcmp(subDirFile[i],"..")){continue;}sprintf(dirPath,"%s/%s",dirName,subDirFile[i]);getDirInfo(dirPath,dirLevel+1);}}return true;}//获得帮助菜单void getHelpMenu(){FILE*fp=NULL;char ch;fopen_s(&fp,HELP_FILE,"rb");if(fp==NULL){fopen_s(&fp,TMP_FILE,"rb");if(fp==NULL){return;}}while((ch=fgetc(fp))!=EOF){fputc(ch,stdout);}fclose(fp);return;}//初始化bool init(){m_fileInfo=(fileInfo*)malloc(sizeof(fileInfo)*MAX_FILE_NUM);ALLOC_MEM_LEN+=MAX_FILE_NUM;if(m_fileInfo==NULL){return false;}return true;}//释放内存void freeMem(){free(m_fileInfo);m_fileInfo=NULL;}##MakeFile#CC=gccCFLAGS=CFILES=$(wildcard*.c)OBJS=$(CFILES:%c=%o)ls:$(OBJS)$(CC)$(CFLAGS)-o ls$(OBJS).c.o:$(CC)-c$^.PHONY:cleanclean:rm-f ls_fileHandle*.o main*.ohel p I nf o.d at l s.c l s_f i l eH and l e.c l s_f i l eH and l e.h M akef i l e。
首先我讲一下写这篇东西的目的。
我觉得对于很多linux新手。
尤其是在自学的同学。
最好的学习的方法就是通过具体的例子。
通过一个实践的例子,在学习相关的知识点的同时,就把它们应用到这例子中。
这样不仅知道了原理。
也知道了怎么去应用。
下面就开始用一个常用的命令”ls”开始。
所有的东西都是从最基本的原理开始。
一步步来教你怎么实践出一个命令(一)ls命令简单介绍第一步当然是要明白ls究竟是做什么的。
如果你要做一个东西却不知道要用来干嘛。
会不会很搞笑?所以下面就简单的介绍ls命令的作用和怎么使用1.Ls可以列出文件名和文件的属性在命令行输入ls:ls 命令.jpgLs的默认动作是找出当前所有文件的文件名。
按字典排序后输出。
Ls还能显示其他的信息。
如果加上-l就会列出每个文件的详细信息。
也叫ls的长格式:2. 列出指定目录或文件的信息Linux系统中会有很多目录。
每个目录中又会有很多文件。
如果要列出一个非当前目录的内容或者是一个特定文件的信息,则需要在参数中给出目录名或文件名。
如:ls /tmp //列出/tmp目录中各文件的文件名ls – docs //列出docs目录中各文件的属性ls *.c //列出当前目录下与*.c匹配的文件,即当前目录下所有以.c 为后缀的文件3. 经常用到的命令行选项ls -l 在前面已经提到过,-l就是输出文件详细的信息。
也叫长格式;ls -a 列出的内容包含以“.“开头的让文件,即所谓有隐藏文件ls –lu 显示最后访问时间ls –t 输出时按时间排序ls –F 显示文件类型ls 命令的参数选项非常多,大多也可以组合使用。
所以还是比较复杂的。
但是我们第一步要实现的就是它最基本的功能:列出当前目录下的所有文件或子目录。
(二)学习必备的知识既然是列出文件和目录,那么肯定是和linux文件系统有关系的,所以要写ls命令,至少要对文件系统的基本原理有一定的了解。
为了不至于使这个帖子内容过于复杂,我把这方面的知识介绍单独开了一个帖子:linux 文件系统详解如果你对这些已经有所了解。
linux中的ls命令参数详解及ls命令的使⽤实例⼀、ls命令参数详解可以通过阅读 ls 的说明书页(man ls)来获得选项的完整列表。
-a – 全部(all)。
列举⽬录中的全部⽂件,包括隐藏⽂件(.filename)。
位于这个列表的起⾸处的 .. 和 . 依次是指⽗⽬录和你的当前⽬录。
-l – 长(long)。
列举⽬录内容的细节,包括权限(模式)、所有者、组群、⼤⼩、创建⽇期、⽂件是否是到系统其它地⽅的链接,以及链接的指向。
-F – ⽂件类型(File type)。
在每⼀个列举项⽬之后添加⼀个符号。
这些符号包括:/ 表明是⼀个⽬录;@ 表明是到其它⽂件的符号链接;* 表明是⼀个可执⾏⽂件。
-r – 逆向(reverse)。
从后向前地列举⽬录中的内容。
-R – 递归(recursive)。
该选项递归地列举所有⽬录(在当前⽬录之下)的内容。
-S – ⼤⼩(size)。
按⽂件⼤⼩排序。
ls命令是linux下最常⽤的命令。
【linux ls命令参数详解及ls命令的使⽤实例】ls命令就是list的缩写,缺省下ls⽤来打印出当前⽬录的清单,如果ls指定其他⽬录,那么就会显⽰指定⽬录⾥的⽂件及⽂件夹清单。
通过ls 命令不仅可以查看linux⽂件夹包含的⽂件,⽽且可以查看⽂件权限(包括⽬录、⽂件夹、⽂件权限),查看⽬录信息等等。
ls 命令在⽇常的linux操作中⽤的很多!1. 命令格式:ls [选项] [⽬录名]2. 命令功能:列出⽬标⽬录中所有的⼦⽬录和⽂件。
3. 常⽤参数:-a, –all 列出⽬录下的所有⽂件,包括以 . 开头的隐含⽂件-A 同-a,但不列出“.”(表⽰当前⽬录)和“..”(表⽰当前⽬录的⽗⽬录)。
-c 配合 -lt:根据 ctime 排序及显⽰ ctime (⽂件状态最后更改的时间)配合 -l:显⽰ ctime 但根据名称排序否则:根据 ctime 排序-C 每栏由上⾄下列出项⽬–color[=WHEN] 控制是否使⽤⾊彩分辨⽂件。
使用Linux C编程实现简单的ls命令使用Linux C编程实现简单的ls命令具体代码如下:加载的头文件有stdio.h,sys/types.h,dirent.h,unistd.h,sys/stat.h,fcntl.h,string.h等。
void main(int argc,char **argv){ DIR *dir; struct dirent *rdir; struct stat statbuf; char * buffer=”/”; char *file_; char *p; int lenght=strlen(argv[argc-1]); int len=argc; char parameter[]={‘i’,’t’,’a’,’u’,’g’,’b’,’s’}; //参数属组if(argc==1 ||strstr(argv[argc-1],buffer)==NULL){ argv[argc++]=”./”; dir=opendir(“./”); //打开目录文件}else{ dir=opendir(argv[argc-1]); file_=argv[argc-1]; //打开目录文件} while((rdir=readdir(dir))!=NULL){ //读取目录中的目录或者文件if(len!=argc){ file_=rdir->d_name; //从struct dirent结构取出文件名称}else{ p=rindex(file_,’/’); if(strlen(p)!=1){ strcat(file_,buffer); } st rcat(file_,rdir->d_name); } int file=open(file_,O_RDONLY,0); //打开文件stat(file_, //通过stat函数读取文件的状态信息放在struct stat 这个结构体中,这个结构包含文件的属组,属主,权限,时间戳,文件大小等。
Linux中ls命令的⽤法详解⼀.⽬录结构使⽤ls命令我们⾸先要了解Linux下的⽬录结构Linux系统是由各种⽂件和⽬录构成的,就像Windows系统下⽂件和⽂件夹的关系,⼀级⼀级的向下包含扩展,例如在根⽬录下有bin,boot,dev,etc,home等⽬录⽽在这些⽬录下⼜包含了其他的⽂件和⽬录,这样就形成了以根⽬录”/”为根的树形结构另:每个⽬录下都有“.”“..”这样的两个隐藏⽂件,“.”表⽰本⽂件,“..”表⽰⽗⽬录⼆. Linux下的⽂件类型在Linux下⼀切皆⽂件 everything is file,包括⽬录也是⽂件的⼀种⽽这些⽂件被分为七种类型:• -:普通⽂件• d: ⽬录⽂件• b: 块设备• c: 字符设备• l: 符号链接⽂件• p: 管道⽂件pipe• s: 套接字⽂件sock三.Linux中ls命令及其常⽤参数ls功能:列出⾮⽬录的⽂件项,然后是每⼀个⽬录中的“可显⽰”⽂件(可理解为ls命令将本⽬录向下展开两级)ls⽤法:ls [参数] [⽬录名](如过要显⽰当前⽬录的⽂件可不加⽬录名)ls常⽤参数-a 显⽰所有⽂件,包含隐藏⽂件-A 显⽰所有⽂件,包含隐藏⽂件,但不包含.及..-l 显⽰为long format(长格式),列出⽂件的类型、权限、链接数、owner、group、⼤⼩,时间,名字-R-d 不展开⽬录,只显⽰⽬录⾃⾝,⼀般与-l配合使⽤以显⽰⽬录⾃⾝的属性信息(只显⽰当前⽬录的内容)-1 数字1,成列显⽰内容-S 以⽂件⼤⼩排序显⽰,默认从⼤到⼩ -r后,从⼩到⼤-U 按存放顺序排序显⽰-X 按扩展名的⾸字母来排序-t 按mtime排序(先显⽰时间最近的)-ul 按atime排序(先显⽰时间最近的)-ct 按ctime排序(先显⽰时间最近的)补充:关于时间戳:atime 访问时间mtime 数据修改时间(写⼊,修改数据mtime改变,mtime改变ctime必改变)ctime 元数据修改时间(修改权限的时候只有ctime改变)可过“stat ⽂件路径”查看全部时间戳扩展: 如何通过ls只显⽰指定格式的⽂件⾸先我们要了解什么是⽂件名通配符Shell提供了⼀套完整的字符串模式匹配规则,或者称之为元字符,当s h e l l遇到上述字符时,就会把它们当作特殊字符,⽽不是⽂件名中的普通字符,这样⽤户就可以⽤它们来匹配相应的⽂件名,我理解这可以称为通配符。
Linuxls命令实现(简化版)在学习linux系统编程的时候,实现了ls命令的简化版本号。
实现的功能例如以下:1. 每种⽂件类型有⾃⼰的颜⾊(- 普通⽂件, d ⽂件夹⽂件, l 链接⽂件。
c 字符设备⽂件。
b 快设备⽂件, p 管道⽂件, s socket⽂件。
共7种)2. ⽀持的參数有 -hali (a: 显⽰隐藏⽂件。
i: 显⽰inode节点号,l: 以列表形式显⽰⽂件的具体信息。
h: ⼈类可读的⽂件⼤⼩显⽰)3. 对于符号链接,显⽰出其指向的⽂件。
4. 设备⽂件。
显⽰主设备号和次设备号,不显⽰⽂件⼤⼩(设备⽂件没有⼤⼩属性,对于设备号,不同的 *nix 存储⽅式可能不同)5. ⽂件依照字典序排序显⽰。
程序说明:1. 程序中⼤部分使⽤的都是linux系统调⽤和c标准库函数。
仅仅有⽂件排序⽤到了c++ stl 的vector和sort算法(好吧,我⼜偷懒了!)2. lstat(): 获取⽂件的具体信息。
inode, 权限, 连接数, uid, gid, size, time 等(对于符号链接⽂件。
返回⾃⾝的信息,⽽不是⽬标⽂件的)opendir(), readdir(), closedir(): 读取⽂件夹信息。
getpwuid(), getgrgid(): 通过uid, gid 获取⽤户和组的具体信息。
3. 对于不同⽂件类型的颜⾊。
在Linux下能够使⽤env命令获取,也能够在程序中使⽤ extern char **environ 或 getenv() 获取。
程序编译执⾏(见下图)程序源代码:#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <time.h>#include <errno.h>#include <dirent.h>#include <grp.h>#include <pwd.h>// c++#include <vector>#include <algorithm>#include <string>using namespace std;#define BUF_SIZE 1024#define COLOR_R (char*)"\33[0m"#define COLOR_D (char*)"\33[01m\33[34m"#define COLOR_L (char*)"\33[01m\33[36m"#define COLOR_P (char*)"\33[40m\33[33m"#define COLOR_B (char*)"\33[40m\33[33m"#define COLOR_C (char*)"\33[40m\33[33m"#define COLOR_S (char*)"\33[02m\33[35m"#define RESET_CLOLR (char*)"\33[0m"int get_option(const char *opt);int show_ls();int show_ls_one_path(const char *path);int show_ls_file(const char *path, const char *name); int show_ll_part(struct stat *p_stat, int bHuman); void to_humen_size(char *buf, off_t size);char get_file_type(mode_t st_mode);void get_mode(char *buf, mode_t st_mode);// global varenum EOPT{E_a, E_i, E_l, E_h, E_num};int g_opt[E_num] = {0}; // order: -ailhchar *g_scolor;vector<string> gv_path;/* ls: ./a.out argv... */int main(int argc, char const *argv[]){int i;for (i = 1; i < argc; ++i){if ('-' == argv[i][0]){if (-1 == get_option(argv[i]+1)){fprintf(stderr, "bad option!\n");return 1;}}else{gv_path.push_back(argv[i]);}}if (0 == gv_path.size()){gv_path.push_back(".");}show_ls();return 0;}/* -ailh */int get_option(const char *opt){while (*opt != '\0'){switch (*opt){case 'a':g_opt[E_a] = 1;break;case 'i':g_opt[E_i] = 1;break;case 'l':g_opt[E_l] = 1;break;case 'h':g_opt[E_h] = 1;break;default:return -1;}opt++;}return 0;}int show_ls(){for (vector<string>::iterator it = gv_path.begin();it != gv_path.end(); ++it){show_ls_one_path(it->c_str());}return 0;}int show_ls_one_path(const char *path){DIR *dir;dir = opendir(path);if (NULL == dir){// not a dirif (ENOTDIR == errno){char *p = rindex((char *)path, '/');if (NULL == p){show_ls_file("./", path);}else{char sdir[BUF_SIZE] = {'\0'};strncpy(sdir, path, p-path);show_ls_file(sdir, p+1);}printf("\n");return 0;}perror(path);return -1;}if (gv_path.size() > 1){fprintf(stdout, "%s:\n", path);}struct dirent *entry;vector<string> v_name;while (1){entry = readdir(dir);if (NULL == entry){break;}// show conten depends on option(g_opt)if (g_opt[E_a] != 1){if ('.' == entry->d_name[0]){continue;}}v_name.push_back(entry->d_name);}// sort filenamesort(v_name.begin(), v_name.end());for (vector<string>::iterator it = v_name.begin();it != v_name.end(); ++it){show_ls_file(path, it->c_str());}fprintf(stdout, "\n");closedir(dir);}int show_ls_file(const char *path, const char *name) {// statchar full_path[BUF_SIZE];int ret;struct stat st_stat;snprintf(full_path, BUF_SIZE, "%s/%s", path, name);ret = lstat(full_path, &st_stat);if (-1 == ret){perror(full_path);return -1;}if (1 == g_opt[E_i]){fprintf(stdout, "%7d ", (int)st_stat.st_ino);}if (1 == g_opt[E_l]){show_ll_part(&st_stat, g_opt[E_h]);}else{get_file_type(st_stat.st_mode);//get file color actually }// show filename with colorfprintf(stdout, "%s", g_scolor);fprintf(stdout, "%s ", name);fprintf(stdout, RESET_CLOLR);if (1 == g_opt[E_l] && 'l' == get_file_type(st_stat.st_mode)) {// -> real filechar real_file[BUF_SIZE];int path_size = readlink(full_path, real_file, BUF_SIZE);real_file[path_size] = '\0';fprintf(stdout, "-> %s", real_file);}if (1 == g_opt[E_l]){fprintf(stdout, "\n");}return 0;}/* show ll: mode, link num, user, group, size, time */int show_ll_part(struct stat *p_stat, int bHuman){// modechar buf[BUF_SIZE];get_mode(buf, p_stat->st_mode);char file_type = buf[0];fprintf(stdout, "%s", buf);// link numfprintf(stdout, " %d", p_stat->st_nlink);// uid gid// get_id_name(buf, p_stat->st_uid, "/etc/passwd");// fprintf(stdout, " %s", buf);// get_id_name(buf, p_stat->st_gid, "/etc/group");// fprintf(stdout, " %s", buf);struct passwd * st_user = getpwuid(p_stat->st_uid);fprintf(stdout, " %s", st_user->pw_name);struct group * st_group = getgrgid(p_stat->st_gid);fprintf(stdout, " %s", st_group->gr_name);// show dev idif ('c' == file_type || 'b' == file_type/* || 'p' == file_type*/){// dev_idint major = 0xFF00 & p_stat->st_rdev;major >>= 8;int sub = 0x00FF & p_stat->st_rdev;fprintf(stdout, "\t%4d,%4d", major, sub);}else // show file size{// -h bHuman sizeoff_t size = p_stat->st_size;if (bHuman){char buf[BUF_SIZE];to_humen_size(buf, size);fprintf(stdout, " %s", buf);}else{fprintf(stdout, " %9ld", size);}}// timechar stime[BUF_SIZE] = {'\0'};snprintf(stime, 13, "%s", 4+ctime(&p_stat->st_ctime)); fprintf(stdout, " %s ", stime);return 0;}// -h optionvoid to_humen_size(char *buf, off_t size){double tmp = size;if (size >= 1024*1024*1024){tmp /= 1024*1024*1024;snprintf(buf, BUF_SIZE, "%5.1fG", tmp);}else if (size >= 1024*1024){tmp /= 1024*1024;snprintf(buf, BUF_SIZE, "%5.1fM", tmp);}else if (size >= 1024){tmp /= 1024;snprintf(buf, BUF_SIZE, "%5.1fK", tmp);}else{snprintf(buf, BUF_SIZE, "%6ld", size);}}char get_file_type(mode_t st_mode){if (S_ISREG(st_mode)){g_scolor = COLOR_R;return '-';}if (S_ISDIR(st_mode)){g_scolor = COLOR_D;return 'd';}if (S_ISCHR(st_mode)){g_scolor = COLOR_C;return 'c';}if (S_ISBLK(st_mode)){g_scolor = COLOR_B;return 'b';}if (S_ISFIFO(st_mode)){g_scolor = COLOR_P;return 'p';}if (S_ISLNK(st_mode)){g_scolor = COLOR_L;return 'l';}if (S_ISSOCK(st_mode)){g_scolor = COLOR_S;return 's';}g_scolor = COLOR_R;return '-';}// -rwx---...void get_mode(char *buf, mode_t st_mode){buf[0] = get_file_type(st_mode); int i;mode_t bit;for (i = 3; i > 0; --i){bit = st_mode & 0x01;buf[i*3] = (1 == bit ? 'x' : '-');st_mode >>= 1;bit = st_mode & 0x01;buf[i*3-1] = (1 == bit ? 'w' : '-'); st_mode >>= 1;bit = st_mode & 0x01;buf[i*3-2] = (1 == bit ? 'r' : '-'); st_mode >>= 1;}buf[10] = '\0';}:。
Readme:将两个文件list.h和ls.c文件放入linux下同一目录下,gcc编译,之后就可以通过./可执行文件名-选项参数运行了。
本程序实现大部分ls的功能,在ubuntu16.04下测试可用,大家有什么不懂的欢迎探讨。
qq:280438369List.h文件代码内容如下:#ifndef _LINUX_LIST_H#define _LINUX_LIST_H/** Simple doubly linked list implementation.** Some of the internal functions ("__xxx") are useful when* manipulating whole lists rather than single entries, as* sometimes we already know the next/prev entries and we can* generate better code by using them directly rather than* using the generic single-entry routines.*/struct list_head {struct list_head *next, *prev;};#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)#define INIT_LIST_HEAD(ptr) do { \(ptr)->next = (ptr); (ptr)->prev = (ptr); \} while (0)/** Insert a new entry between two known consecutive entries. ** This is only for internal list manipulation where we know* the prev/next entries already!*/static __inline__ void __list_add(struct list_head * new, struct list_head * prev,struct list_head * next){next->prev = new;new->next = next;new->prev = prev;prev->next = new;}/*** list_add - add a new entry* @new: new entry to be added* @head: list head to add it after** Insert a new entry after the specified head.* This is good for implementing stacks.*/static __inline__ void list_add(struct list_head *new, struct list_head *head){__list_add(new, head, head->next);}/*** list_add_tail - add a new entry* @new: new entry to be added* @head: list head to add it before** Insert a new entry before the specified head.* This is useful for implementing queues.*/static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) {__list_add(new, head->prev, head);}/** Delete a list entry by making the prev/next entries* point to each other.** This is only for internal list manipulation where we know* the prev/next entries already!*/static __inline__ void __list_del(struct list_head * prev,struct list_head * next){next->prev = prev;prev->next = next;}/*** list_del - deletes entry from list.* @entry: the element to delete from the list.* Note: list_empty on entry does not return true after this, the entry is in an undefined state. */static __inline__ void list_del(struct list_head *entry){__list_del(entry->prev, entry->next);entry->next = entry->prev = 0;}/*** list_del_init - deletes entry from list and reinitialize it.* @entry: the element to delete from the list.*/static __inline__ void list_del_init(struct list_head *entry){__list_del(entry->prev, entry->next);INIT_LIST_HEAD(entry);}/*** list_empty - tests whether a list is empty* @head: the list to test.*/static __inline__ int list_empty(struct list_head *head){return head->next == head;}/*** list_splice - join two lists* @list: the new list to add.* @head: the place to add it in the first list.*/static __inline__ void list_splice(struct list_head *list, struct list_head *head) {struct list_head *first = list->next;if (first != list) {struct list_head *last = list->prev;struct list_head *at = head->next;first->prev = head;head->next = first;last->next = at;at->prev = last;}}/*** list_entry - get the struct for this entry* @ptr: the &struct list_head pointer.* @type: the type of the struct this is embedded in.* @member: the name of the list_struct within the struct.*/#define list_entry(ptr, type, member) \((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /*** list_for_each - iterate over a list* @pos: the &struct list_head to use as a loop counter.* @head: the head for your list.*/#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); \pos = pos->next)/*** list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter.* @n: another &struct list_head to use as temporary storage* @head: the head for your list.*/#define list_for_each_safe(pos, n, head) \for (pos = (head)->next, n = pos->next; pos != (head); \pos = n, n = pos->next)#endifls.c文件内容如下:/*该文件简单模拟linux系统的ls命令(实现了大部份功能)功能需求(FIXME),实现的常用的选项:--help 显示帮助信息-a 显示所有文件(即包括隐藏文件)-l 显示详细信息-L 只打印链接文件名-r 反排序-R 递归显示,即遇到目录会再次进入目录把文件列举出来-c 以文件最后状态修改时间排序,st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、权限被更改时更新-t 以文件最后修改时间排序,st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、utime 和write 时才会改变-u 以文件最后访问时间排序,st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、utime、read、write 与tructate 时改变-S 以文件大小排序-n 以文件名排序(以文件名排序,是默认排序,如果有多种排序也只采用文件名排序)-i 显示I节点-h –human-readable 以容易理解的格式列出文件大小(例如1K 234M 2G)FIXME:已知BUG:(1) 输出的格式与系统由一定差别(2) 文件与文件夹没有颜色区分*/#include <time.h>#include <stdio.h>#include <getopt.h>#include <errno.h>#include <string.h>#include <sys/stat.h>#include <dirent.h>#include <stdlib.h>#include <assert.h>#include <getopt.h>#include <pwd.h>#include <grp.h>#include <unistd.h>#include "list.h"#define MAX_PATH 256 /*文件或者目录名的最大长度*/#define PEER_MALLOC_FILE 64 /*当内存不够时,最少申请多少个struct file_info的大小避免频繁申请内存*//* sys/stat.h 中struct stat结构体*//*struct stat {dev_t st_dev; //device 文件的设备编号ino_t st_ino; //inode 文件的i-nodemode_t st_mode; //protection 文件的类型和存取的权限nlink_t st_nlink; //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1.uid_t st_uid; //user ID of owner 文件所有者的用户识别码gid_t st_gid; //group ID of owner 文件所有者的组识别码dev_t st_rdev; //device type 若此文件为装置设备文件, 则为其设备编号off_t st_size; //total size, in bytes 文件大小, 以字节计算unsigned long st_blksize; //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小.u nsigned long st_blocks; //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节.time_t st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、utime、read、write 与tructate 时改变.time_t st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、utime 和write 时才会改变time_t st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、权限被更改时更新};*//*一个文件基本信息的节点*/struct file_info{char fil_name[MAX_PATH]; /* 文件名节点*/char dst_name[MAX_PATH]; /* 链接文件名真实名*/char is_link; /* 是否是链接文件1:是0:否*/struct stat statbuf; /*文件属性节点*/};/*一个目录的信息列表*/struct dir_info{char dir_path[MAX_PATH]; /*目录名节点*/struct file_info *p_filenode; /*指向该目录下的文件信息内存类似于数组,之所以不采用链表,是为了好用qsort进行排序*/size_t used_size; /*已用了多少个strcut file_info*/size_t free_size; /*空余还有多少个strcut file_info*/size_t dir_size; /*该目录的大小(单位为k),用ls -l显示的第一行total(总用量)的值*/char need_print_total; /*该目录是否需要打印total*/};/*等待遍历节点的节点*/struct dir_list{char dir_path[MAX_PATH]; /*待遍历的目录节点*/struct list_head list_node; /*链表节点*/};struct param{char a; /* 显示所有文件*/char l; /* 显示详细信息*/char L; /* 只显示链接文件*/char r; /* 反排序*/char R; /* 递归显示*/char c; /* 状态修改时间排序*/char t; /* 最后修改时间排序*/char u; /* 最后访问时间排序*/char S; /* 以文件大小排序*/char n; /* 以文件名排序*/char i; /* 显示I节点*/char d; /* 显示每块大小*/char h; /* 以k为单位显示*/char m; /* 显示帮助信息*/};//全局typedef int (*COM_FUNC)(const void *, const void *);//定义了一个指向函数的指针COM_FUNC,其返回值int类型,参数也是后面的(const void *),接下来我们就可以直接使用COM_FUNC来定义这种指针变量,比如:COM_FUNC g_com_func; //等价于int g_com_func(const void *,const void *);struct dir_info g_dir_info; /*当前正处理的目录*/struct param g_param; /*传入参数*/struct list_head g_dir_head; /*需要扫描目录的链表头*/COM_FUNC g_com_func = NULL;/*帮助信息*/static void printf_usage(){printf("usage:\n");printf("--help show the help infomation\n");printf("-a show all files\n");printf("-l show the detailed information\n");printf("-L only show linkname if the file is linkfile\n");printf("-r recursive display\n");printf("-R Recursive display\n");printf("-c sort by status change\n");printf("-t sort by last modify time\n");printf("-u sort by last access time\n");printf("-S sort by file size\n");printf("-h –human-readable display\n");printf("-n sort by file name, the default.And if input more than one sort way, only sort by file name\n");printf("-i show i-node info\n");printf("-d show I/O block size\n");}/*计算一个目录的大小,即ls -l显示出来的第一行"total" */static void cal_dir_size(){size_t i;struct file_info *p;g_dir_info.dir_size = 0;g_dir_info.need_print_total = 1; /*需要打印total字段标志*/for(i = 0; i < g_dir_ed_size; ++i) //used_size为size_t类型{p = g_dir_info.p_filenode + i;g_dir_info.dir_size += p->statbuf.st_blksize * p->statbuf.st_blocks;//文件系统的I/O缓冲区大小占用文件区块的个数, 每一区块大小为512 个字节}/*换算为k*/g_dir_info.dir_size = g_dir_info.dir_size/1024/8;}/*程序带错误码退出*/static void dead_errno(int no){assert(0);//在assert.h中,assert的作用是现计算表达式expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用abort 来终止程序运行。
linux中的ls命令Linux系统中的ls命令的主要功能是显示指定工作目录之下的内容,下面由店铺为大家整理了linux中的ls命令的相关知识,希望对大家有帮助!linux中的ls命令详解Linux ls命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录)。
语法ls [-alrtAFR] [name...]参数 :-a 显示所有文件及目录(ls内定将文件名或目录名称开头为"."的视为隐藏档,不会列出)-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出-r 将文件以相反次序显示(原定依英文字母次序)-t 将文件依建立时间之先后次序列出-A 同 -a ,但不列出 "." (目前目录) 及 ".." (父目录)-F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加"/"-R 若目录下有文件,则以下之文件亦皆依序列出linux中的ls命令实例列出根目录(\)下的所有目录:# ls /bin dev lib media net root srv upload wwwboot etc lib64 misc opt sbin sys usrhome lost+found mnt proc selinux tmp var列出目前工作目录下所有名称是 s 开头的文件,越新的排越后面 : ls -ltr s*将 /bin 目录以下所有目录及文件详细资料列出 :ls -lR /bin列出目前工作目录下所有文件及目录;目录于名称后加"/", 可执行档于名称后加 "*" :ls -AF。
《L i n u x环境程序设计》大作业报告题目:Linux下ls命令的实现学院物联网工程学院专业计算机科学与技术班级计科1105班学号03041105学生二〇一四年十二月目录一、设计思想 (1)1.1 实验要求 (1)1.2 设计思路 (1)二、数据定义、系统(函数)调用、处理流程 (1)2.1 数据定义 (1)2.1.1 DIR结构体 (1)2.1.2 dirent结构体 (2)2.1.3 stat结构体 (2)2.2 系统调用 (3)2.2.1 opendir函数 (3)2.2.2 readdir函数 (3)2.2.3 closedir函数 (4)2.3 处理流程 (4)三、详细设计(含源程序) (5)四、运行结果与分析 (10)五、设计体会 (13)六、参考文献 (13)一、设计思想1.1 实验要求使用opendir、readdir、closedir等函数来操作目录,利用stat函数来获取文件信息。
编写一个功能完整的实现Linux下ls命令的程序,该程序实现了-l、-i、-t这几个选项的功能。
其中,-l、-i、-t选项说明:-l:use a long listing format.-i:print the index number of each file.-t:sort by modification time, newest first.1.2 设计思路本实验是实现Linux下的ls功能。
其设计思路如下:目的是获取某目录下文件的详细信息。
(1)首先使用opendir()函数打开目录,返回指向该目录的DIR结构体。
(2)接着,调用readdir()函数读取这个目录下所有文件,其中应该包括目录本身,返回指向该目录下所有文件的dirent结构体。
(3)最后,遍历dirent结构体,调用stat来获取每个文件的详细信息并存储在stat结构体中。
如果这个参数是一个文件名,我们输出这个文件的大小和最后修改的时间,如果是一个目录我们输出这个目录下所有文件的大小和修改时间。
linux ls命令的实用范例ls命令用于列出文件和目录。
默认上,他会列出当前目录的内容。
带上参数后,我们可以用ls做更多的事情。
接下来是小编为大家收集的linux ls命令的实用范例,欢迎大家阅读:linux ls命令的实用范例1. 不带参数运行ls不带参数运行ls会只列出文件或者目录。
看不到其他信息输出(译注:有时候你发现无参数的ls命令和这里描述的不同,那有可能是你的ls命令实际上带参数的ls别名)。
2. 使用长清单模式使用-l字符(小写L字符),会显示当前目录内容的长列表。
在接下来的例子中,我们会结合-l参数(这个参数经常使用)来得到更好的结果。
这里是如何读取输出 :第1列第一个字母d 意味着内容是目录或者文件。
在上面的截图中,Desktop、 Documents、 Downloads 和 lynis-1.3.8是目录。
如果是'-'( 减号 ),这意味着它的内容是文件。
当它是l( 小写l字符 ),意味这内容是链接文件。
下面的9个字符是关于文件权限。
前3个rwx 字符是文件的拥有者的权限,第二组3rwx 是文件的所有组的权限,最后的rwx 是对其他人访问文件的权限。
第2列这行告诉我们有多少链接指向这个文件。
第3列这行告诉我们谁是这个文件/文件夹的所有者。
第4列这行告诉我们谁是这个文件/文件夹的所有组。
第5列这行告诉我们这个文件/文件夹的以字节为单位的大小。
目录的大小总是4096字节。
第6列这告诉我们文件最后的修改时间。
第7列这告诉我们文件名或者目录名。
3. 显示文件大小以字节为单位看大小可能会不方便。
6.5M读起来比6727680字节更简单。
要这么做,我们可以使用-h与-l 结合的参数。
-h参数意味着便于人识别。
另外一个可以这么做的参数是--si 。
这个参数和-h参数类似,但是 -si以1000为单位,而-h以1024为单位。
4. 排序文件大小在我们可以显示文件大小之后,我们希望以文件大小排序。
程序截图#include<stdio。
h>#include<sys/types。
h〉#include<unistd.h〉#include〈sys/stat。
h>#include〈time。
h>#include〈pwd。
h〉#include<grp。
h>#include〈dirent。
h〉#include〈stdlib.h>void display_file(char *filename); void display_dir(char *dirname);int main(int argc,char *argv[]){struct stat buf;if(argc < 2){printf(”usage:%s file\n",argv[0]); return 0;}if(lstat(argv[1],&buf)== —1){perror(”stat”);return —1;}if(S_ISDIR(buf。
st_mode))//判断是否是文件夹{display_dir(argv[1]);}elsedisplay_file(argv[1]);//不是文件夹情况 return 0;}void display_dir(char *dirname){DIR *dp;struct dirent *filename;char dirfilename[100]={0};int i=0;dp=opendir(dirname);if(dp == NULL){perror("opendtr");}while((filename=readdir(dp))!=NULL){if(strcmp("。
",filename—>d_name)==0||strcmp("。
",filename —>d_name)==0)continue;sprintf(dirfilename,"%s/%s",dirname,filename—〉d_name);//把文件夹中的文件名以字符串型式写到数组中display_file(dirfilename);//调用文件函数}closedir(dp);}void display_file(char *filename){int i=8;struct stat buf;struct tm *p;if(lstat(filename,&buf)==—1){perror("stat");//return -1;}switch(buf.st_mode & 0170000){case S_IFLNK: printf(”l”);break; case S_IFREG: printf(”—”);break; case S_IFBLK: printf(”b”);break; case S_IFDIR: printf(”d");break; case S_IFCHR: printf("c”);break; case S_IFIFO: printf(”i");break; case S_IFSOCK: printf(”s");break;}for(i=8;i〉=0;i--){if(buf.st_mode & (1〈<i)){switch(i%3){case 0:printf("x");break; case 1:printf("w”);break;case 2:printf(”r”);break;}}elseprintf(”—");}p=localtime(&buf。
linux系统编程:⾃⼰动⼿写⼀个ls命令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 supportedby all filesystem types */char d_name[256]; /* filename */};有了这两个api,就可以实现⼀个简易的ls功能1/*================================================================2* Copyright (C) 2018 . All rights reserved.3*4* ⽂件名称:myls.c5* 创建者:ghostwu(吴华)6* 创建⽇期:2018年01⽉09⽇7* 描述: ls命令8*9================================================================*/1011 #include <stdio.h>12 #include <sys/types.h>13 #include <dirent.h>14 #include <stdlib.h>1516void do_ls( char [] );1718int main(int argc, char *argv[])19 {20if( argc == 1 ) {21 do_ls( "." );22 }else {23while( --argc ) {24 printf( "arg=%s\n", * ++argv );25 do_ls( *argv );26 }27 }28return0;29 }3031void do_ls( char dir_entry[] ) {32 DIR* pDir;33struct dirent* pCurDir;34if( ( pDir = opendir( dir_entry ) ) == NULL ){35 perror( "read dir" );36 exit( -1 );37 }else {38while( ( pCurDir = readdir( pDir ) ) != NULL ) {39 printf( "%s\n", pCurDir->d_name );40 }41 }42 }View Code这个简易的ls功能,列举出了所有的⽂件( 包括隐藏的 ),但是很多的信息不全,如: 权限,⽤户和组,修改时间,⽂件⼤⼩,链接数⽬等,stat这个api可以获取⽂件的这些信息stat:获取⽂件状态信息原型:int stat(const char *pathname, struct stat *buf), 第⼀个参数:⽂件名,第⼆个参数:保存⽂件状态信息的结构体( man 2 stat 有结构体相关说明 )1、获取⽂件的⼤⼩1/*================================================================2* Copyright (C) 2018 . All rights reserved.3*4* ⽂件名称:stat.c5* 创建者:ghostwu(吴华)6* 创建⽇期:2018年01⽉09⽇7* 描述:8*9================================================================*/ 1011 #include <stdio.h>12 #include <sys/stat.h>1314#define FILENAME "/etc/passwd"1516int main(int argc, char *argv[])17 {18struct stat filestat;1920if( -1 == stat( FILENAME, &filestat ) ) {21 perror( "file stat" );22return -1;23 }else {24 printf( "the size of %s is %ld\n",FILENAME, filestat.st_size );25 }2627return0;28 }View Code2、读取⽂件st_mode(权限位), ⽤户id, 组id, 修改时间,链接数⽬1/*================================================================ 2* Copyright (C) 2018 . All rights reserved.3*4* ⽂件名称:stat2.c5* 创建者:ghostwu(吴华)6* 创建⽇期:2018年01⽉09⽇7* 描述:8*9================================================================*/ 1011 #include <stdio.h>12 #include <sys/stat.h>13 #include <string.h>14 #include <time.h>1516void show_info( char *file, struct stat* statinfo );17void show_time( time_t filetime );18char* format_time( char* dsttime, const char* srctime );1920int main(int argc, char *argv[])21 {22struct stat fileinfo;23if( argc > 1 ) {24/*调试信息25 printf( "%s\n", argv[1] );26 int res = stat( argv[1], &fileinfo );27 printf( "%d\n", res );28*/29if( stat( argv[1], &fileinfo ) != -1 ) {30 show_info( argv[1], &fileinfo );31 }32 }else {33 perror( "get args from terminal" );34 }3536return0;37 }3839void show_info( char* file, struct stat* statinfo ){40 printf( "%s⽂件信息如下:\n", file );41 printf( "st_mode = %d\n", statinfo->st_mode );42 printf( "links = %ld\n", statinfo->st_nlink );43 printf( "uid = %d\n", statinfo->st_uid );44 printf( "gid = %d\n", statinfo->st_gid );45 printf( "file size = %ld\n", statinfo->st_size );46 show_time( statinfo->st_mtime );47 }4849void show_time( time_t filetime ) {50struct tm* ptm;51 ptm = localtime( &filetime );5253int month = ptm->tm_mon + 1;54int day = ptm->tm_mday;55int hour = ptm->tm_hour;56int min = ptm->tm_min;5758char srchour[3] = "0";59char srcmin[3] = "0";60char dsthour[3] = "0";61char dstmin[3] = "0";62 sprintf( srchour, "%d", hour );63 sprintf( srcmin, "%d", min );64 format_time( dsthour, srchour );65 format_time( dstmin, srcmin );6667 printf( "⽂件最后修改时间: %d⽉\t%d\t%s:%s\n", month, day, dsthour, dstmin );68 }6970char* format_time( char* dsttime, const char* srctime ) {71if( strlen( srctime ) < 2 ) {72return strcat( dsttime, srctime );73 }74return strcpy( dsttime, srctime );75 }View Code3、权限st_mode转字符权限位( 如: -rwxrwxrwx ), ⽤户id和组id转⽤户名和组名称,判断⽂件类型 1/*================================================================2* Copyright (C) 2018 . All rights reserved.3*4* ⽂件名称:stat3.c5* 创建者:ghostwu(吴华)6* 创建⽇期:2018年01⽉09⽇7* 描述:⽂件类型与权限位8*9================================================================*/1011 #include <stdio.h>12 #include <stdlib.h>13 #include <sys/stat.h>14 #include <string.h>15 #include <sys/types.h>16 #include <pwd.h>17 #include <grp.h>1819void do_ls( char* filename );20void show_filetype( char* filename, int filemode );21void show_filetype2( char* filename, int filemode );22void mode_to_letters( int filemode, char str[] );23//⽤户id转名称24char* uid_to_name( uid_t uid );25//组id转名称26char* gid_to_name( gid_t gid );2728int main(int argc, char *argv[])29 {30if( argc < 2 ) {31 printf( "usage:%s file\n", argv[0] );32return -1;33 }else {34 do_ls( argv[1] );35 }36return0;37 }3839char* uid_to_name( uid_t uid ){40return getpwuid( uid )->pw_name;41 }4243char* gid_to_name( gid_t gid ){44return getgrgid( gid )->gr_name;45 }4647void do_ls( char* filename ) {48struct stat fileinfo;49if( stat( filename, &fileinfo ) == -1 ) {50 printf( "%s open failure\n", filename );51 exit( -1 );52 }53//printf( "st_mode = %d\n", fileinfo.st_mode );54 show_filetype( filename, fileinfo.st_mode );55 show_filetype2( filename, fileinfo.st_mode );56char file_permission[10];57 mode_to_letters( fileinfo.st_mode, file_permission );58 printf( "%s\n", file_permission );59 printf( "⽤户:%s\n", uid_to_name( fileinfo.st_uid ) );60 printf( "组:%s\n", gid_to_name( fileinfo.st_gid ) );61 }6263//掩码判断⽂件类型64void show_filetype( char* filename, int filemode ){65//⽤st_mode的值跟0170000这个掩码相位与的结果 判断⽂件类型66if ( ( filemode & 0170000 ) == 0100000 ){67 printf( "%s是普通⽂件\n", filename );68 }else if( ( filemode & 0170000 ) == 0040000 ){69 printf( "%s是⽬录\n", filename );70 }else if ( ( filemode & S_IFMT ) == S_IFLNK ){71 printf( "%s是符号链接\n", filename );72 }73 }7475//⽤宏判断⽂件类型76void show_filetype2( char* filename, int filemode ){77if( S_ISREG( filemode ) ) {78 printf( "%s是普通⽂件\n", filename );79 }else if( S_ISDIR( filemode ) ) {80 printf( "%s是⽬录\n", filename );81 }else if( S_ISLNK( filemode ) ){82 printf( "%s是符号链接\n", filename );83 }84 }8586//数字解码成字母权限位87void mode_to_letters( int filemode, char str[] ) {88 strcpy( str, "----------" );89if( S_ISREG( filemode ) ) str[0] = '-';90if( S_ISDIR( filemode ) ) str[0] = 'd';91if( S_ISLNK( filemode ) ) str[0] = 'l';9293//⽤户权限位94if( filemode & S_IRUSR ) str[1] = 'r';95if( filemode & S_IWUSR ) str[2] = 'w';96if( filemode & S_IXUSR ) str[3] = 'x';9798//组权限位99if( filemode & S_IRGRP ) str[4] = 'r';100if( filemode & S_IWGRP ) str[5] = 'w';101if( filemode & S_IXGRP ) str[6] = 'x';102103//其他组权限位104if( filemode & S_IROTH ) str[7] = 'r';105if( filemode & S_IWOTH ) str[8] = 'w';106if( filemode & S_IXOTH ) str[9] = 'x';107 }View Code综合上⾯3个⼩实例,可以得到格式化⽐较好的ls命令版本:1/*================================================================ 2* Copyright (C) 2018 . All rights reserved.3*4* ⽂件名称:myls2.c5* 创建者:ghostwu(吴华)6* 创建⽇期:2018年01⽉09⽇7* 描述:ls命令( version 1.2 )8*9================================================================*/ 1011 #include <stdio.h>12 #include <sys/types.h>13 #include <dirent.h>14 #include <stdlib.h>15 #include <sys/types.h>16 #include <sys/stat.h>17 #include <unistd.h>18 #include <string.h>19 #include <sys/types.h>20 #include <pwd.h>21 #include <grp.h>22 #include <time.h>2324void do_ls( char [] );25void do_stat( char* filename );26void show_list( char* filename, struct stat* statinfo );27void mode_to_letters( mode_t filemode, char str[] );28void show_time( time_t filetime );29char* format_time( char* dsttime, const char* srctime );3031//⽤户id转名称32char* uid_to_name( uid_t uid );33//组id转名称34char* gid_to_name( gid_t gid );3536int main(int argc, char *argv[])37 {38if( argc == 1 ) {39 do_ls( "." );40 }else {41while( --argc ) {42 printf( "arg=%s\n", * ++argv );43 do_ls( *argv );44 }45 }46return0;47 }4849void do_ls( char dir_entry[] ) {50 DIR* pDir;51struct dirent* pCurDir;52if( ( pDir = opendir( dir_entry ) ) == NULL ){53 perror( "read dir" );54 exit( -1 );55 }else {56while( ( pCurDir = readdir( pDir ) ) != NULL ) {57 do_stat( pCurDir->d_name );58 }59 closedir( pDir );60 }61 }6263//得到⽂件信息64void do_stat( char* filename ){65struct stat statinfo;66if ( stat( filename, &statinfo ) == -1 ) {67 printf( "打开%s失败\n", filename );68 exit( -1 );69 }else {70 show_list( filename, &statinfo );71 }72 }7374//显⽰⽂件列表75void show_list( char* filename, struct stat* statinfo ) {76 mode_t st_mode = statinfo->st_mode;7778char str[10];79 mode_to_letters( st_mode, str );80 printf( "%s\t", str );8182 printf( "%ld\t", statinfo->st_nlink ); //符号链接83 printf( "%s\t\t", uid_to_name( statinfo->st_uid ) ); //⽤户名84 printf( "%s\t", gid_to_name( statinfo->st_gid ) ); //组名85 printf( "%10ld", statinfo->st_size ); //⽂件⼤⼩86 show_time( statinfo->st_mtime ); //最后⼀次修改时间87 printf( "\t%s", filename );8889 printf( "\n" );90 }9192char* uid_to_name( uid_t uid ){93return getpwuid( uid )->pw_name;94 }9596char* gid_to_name( gid_t gid ){97return getgrgid( gid )->gr_name;98 }99100void mode_to_letters( mode_t filemode, char str[] ) {101102 strcpy( str, "----------" );103if( S_ISREG( filemode ) ) str[0] = '-';104if( S_ISDIR( filemode ) ) str[0] = 'd';105if( S_ISLNK( filemode ) ) str[0] = 'l';106107//⽤户权限位108if( filemode & S_IRUSR ) str[1] = 'r';109if( filemode & S_IWUSR ) str[2] = 'w';110if( filemode & S_IXUSR ) str[3] = 'x';111112//组权限位113if( filemode & S_IRGRP ) str[4] = 'r';114if( filemode & S_IWGRP ) str[5] = 'w';115if( filemode & S_IXGRP ) str[6] = 'x';116117//其他组权限位118if( filemode & S_IROTH ) str[7] = 'r';119if( filemode & S_IWOTH ) str[8] = 'w';120if( filemode & S_IXOTH ) str[9] = 'x';121 }122123void show_time( time_t filetime ) {124struct tm* ptm;125 ptm = localtime( &filetime );126127int month = ptm->tm_mon + 1;128int day = ptm->tm_mday;129int hour = ptm->tm_hour;130int min = ptm->tm_min;131132char srchour[3] = "0";133char srcmin[3] = "0";134char dsthour[3] = "0";135char dstmin[3] = "0";136 sprintf( srchour, "%d", hour );137 sprintf( srcmin, "%d", min );138 format_time( dsthour, srchour );139 format_time( dstmin, srcmin );140141 printf( "%4d⽉%4d%4s:%2s", month, day, dsthour, dstmin ); 142 }143144char* format_time( char* dsttime, const char* srctime ) {145if( strlen( srctime ) < 2 ) {146return strcat( dsttime, srctime );147 }148return strcpy( dsttime, srctime );149 }View Code总结:1)opendir和readdir的⽤法2)结构体struct dirent的应⽤3)stat的⽤法。