在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遇到上述字符时,就会把它们当作特殊字符,⽽不是⽂件名中的普通字符,这样⽤户就可以⽤它们来匹配相应的⽂件名,我理解这可以称为通配符。