博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux命令自己写 — ls
阅读量:4302 次
发布时间:2019-05-27

本文共 7927 字,大约阅读时间需要 26 分钟。

本文基于Ubuntu 12.04.4 (kernel version : 3.11.0-15-generic)

这几天在写一个Linux的基础命令——ls。

当然最终的效果可能和标准的GUN coreutils所提供的ls有些出入,但是在大致相同的情况下

了解其中的原理!

它的作用自然是明了的

先说说文件的属性相关的

文件的基本属性:文件类型,名字,大小,所有者以及所有者所在的组(具体就是他们拥有的权限),修改和访问时间,拥有的连接数。

这就是Linux中一个文件拥有的基本属性!

那么,这些的属性从哪里获得呢?一步一步来吧,这是和文件有关的命令,自然还是用man命令来帮助我们找找,看看不借助其他的工具(比如网络)的情况下我们能不能找到相关的信息。

首先要知道的是什么函数可以打开目录(或者说读取目录),借助联机帮助:

$ man -k direct

可以知道和目录有关的有很多的信息,继续找到我们想要的,

$ man -k direct | grep read

仔细查找找到了一个叫readdir的函数,这正是我们想要的东西!

继续搜索关于readdir的相关信息

$ man 3 reagier

关键的信息:

#include<drient.h>

struct direct *readdir(DIR *dirp);

在struct direct 中最重要的一个域就是 char d_name(还规定了大小为256)

readdir函数返回一个指向dirent结构的指针,只需要打印出dirent结构的d_name域就可以

得到文件的名字了。

(一)

接下来就来完成第一部分工作—-打印出文件的名字

现在我就把要查看的目录下的文件(或者目录)的名字都显示出来了

#include
#include
#include
void do_ls( char *dri_name ); int main(int argc, char *argv[]) { if( argc == 1 ) do_ls("."); else { do_ls( argv[1] ); } return 0; } void do_ls( char *dir_name ) { DIR *dir_ptr; struct dirent *dir_oper; /* open the file */ dir_ptr = opendir(dir_name); if( dir_ptr == NULL) fprintf(stderr, "Your-ls:cannot open %s\n", dir_name); /* read the file */ while( ( dir_oper = readdir( dir_ptr ) ) != NULL) printf(“%s\n”, dir_oper->d_name); closedir( dir_ptr); }

(二)

接下来我们要获得文件的相关的属性。

复习下文件(或者目录)的相关属性有哪些?

文件类型,大小,所有者以及所有者所在的组,相关的权限,修改和打开时间

怎么才能获得这些信息呢?还记得用man这个命令吗?

$ man -k file | grep status

通过返回的信息可以知道要查找文件的相关status(状态),继续进行以下操作

$ man 2 stat

坚持一下,胜利在望  (*^__^*) 

现在可以看到要得到文件的属性(在系统里面的标准说法是状态,即就是status)

有以下:

(我的Linux系统上sys/types.h位于/usr/include/x86_64-linux-gnu)

#include<sys/types.h>

#include<sys/stat.h>

#include<unistd.h>

这是所需要的头文件;关于stat的man信息可谓是相当的丰富

在末尾处还给了贴心的给了个例子,调用stat()显示出选择的文件的相关属性信息,而这些属性信息都包含在结构体stat之中。

下面是这个示例程序:

       #include 
#include
#include
#include
#include
int main(int argc, char *argv[]) { struct stat sb; if (argc != 2) { fprintf(stderr, "Usage: %s
\n", argv[0]); exit(EXIT_FAILURE); } if (stat(argv[1], &sb) == -1) { perror("stat"); exit(EXIT_FAILURE); } printf("File type: "); switch (sb.st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; } printf("I-node number: %ld\n", (long) sb.st_ino); printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode); printf("Link count: %ld\n", (long) sb.st_nlink); printf("Ownership: UID=%ld GID=%ld\n", (long) sb.st_uid, (long) sb.st_gid); printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize); printf("File size: %lld bytes\n", (long long) sb.st_size); printf("Blocks allocated: %lld\n", (long long) sb.st_blocks); printf("Last status change: %s", ctime(&sb.st_ctime)); printf("Last file access: %s", ctime(&sb.st_atime)); printf("Last file modification: %s", ctime(&sb.st_mtime)); exit(EXIT_SUCCESS); }

这里需要说明的就是在switch语句那里可能不是很明白。这个 info.st_mode & S_IMFT 是什么意思呢?

这里就牵涉到了一个重要的概念叫做掩码!!

掩码会将不需要的字段置0,需要的字段不会发生变化,

在<sys/stat.h>这个头文件中定义以下内容:

#define	S_IFMT	0170000	/*文件类型*/#define	S_IFREG	0100000	/*普通文件*/#define	S_IFDIR	0040000	/*目录*/#define	S_IFBLK	0060000	/*特殊的块文件*/#define	S_IFCHR	0020000	/*字符设备文件*/#define	S_IFIFO	0010000	/*管道文件*/#define 	S_IFLNK	0120000	/*符号链接文件*/#define 	S_IFSOCK	 0140000 /*socket文件*/

另外在sys/stat.h还提供了相关的宏,比如:

#define S_ISFIFO(m)	(((m)&(0170000)) == (0010000))#define S_ISDIR(m)	 (((m)&(0170000)) == (0040000))#define S_ISBLK(m)	 (((m)&(0170000)) == (0020000))#define S_ISREG(m)	 (((m)&(0170000)) == (0060000))

以上也差不多把Linux下面的常见的文件类型给列出来了

S_IFMT是一个掩码,它的值是0170000,可以用它来过滤前四位表示的文件类型。

下面的代码:

if( (info.st_mode & 0170000 ) == 0040000)

printf(“this is a directory! ”);

用过掩码将其他位置0,然后再与表示目录的代码作比较,从而判断是不是目录啦!

这里掩码的详细讲解不是重点,主要是明白info.st_mode & S_IMFT 是为了区分出文件类型!

区分出了文件类型,还要区分出文件用所有者,以及文件所有者所在的组对于文件所拥有的权限。

还是利用掩码技术得到文件所有者,所有者所在的组的权限,我们所需要的东西都在 <sys/stat.h>中定义好了

不知道在编写第一个程序(就是那个stat的)时候,最后我们运行出来在mode的那行直接给出的是一串数字。

间接告诉我们这些数字是和所有者、所有者所在的组、其他人对于文件的权限(包括了读、写、执行)

接下来的这个函数是将mode那行的数字信息转换为我们熟悉的形式,就是这样:dr-xrw—wx。

void mode_to_letter( int mode, char str[]){	str=“- - - - - - - - - - ”;	if( S_ISDIR(mode))	str[0] = ‘d’;	/*判断文件类型*/	if(S_ISCHR(mode))	str[0] = ‘c’;	if(S_ISBLK(mode))	str[0] = ‘b’;		if( mode & S_IRUSR) str[1] = ‘r’;	/*文件所有者所拥有的权限*/	if( mode & S_IWUSR) str[2] = ‘w’;	if( mode & S_IXUSR)  str[3] = ‘x’;	if( mode & S_IRGRP) str[4] = ‘r’;	/*所有者所在的组的权限*/	if( mode & S_IWGRP) str[5] = ‘w’;	if( mode & S_IXGRP) str[6] = ‘x’;	if( mode & S_IROTH) str[7] = ‘r’;	/*其他人的权限*/	if( mode & S_IWOTH) str[8] = ‘w’;	if( mode & S_IXOTH)	str[9] = ‘x’;}

到此为止我们已经处理了文件大小,文件名,模式(mode),最后修改时间

还有一个问题就是给出了uid和gid 如何找出相应的所有者名字和组的名字??

(三)将uid(用户ID)和gid(组ID)转换为字符串

通过阅读apue(UNIX环境高级编程)知道可以通过getpwuid访问用户信息;通过getgrpid访问用户组列表。就是这两个函数。

getpwuid定义在<pwd.h>,又可以使用man命令得到你想要的关于getpwuid的信息。getpwuid需要一个uid作为参数,并且返回一个

指向struct passwd的指针

getgrgid定义在<grp.h>,其他的和getpwuid类似。

好了我们的ls命令差不多就初具雏形了,

回想一下你做了什么呢?首先是找到文件的名字,然后是一系列的属性,

其实这里面最重要的是怎么去找这些东西——通过man命令去找!

现在就趁热打铁,写出你的ls吧!

Make your own ls !

#include	
#include
#include
#include
void do_ls(char[]);void dostat(char *);void show_file_info( char *, struct stat *);void mode_to_letters( int , char [] );char *uid_to_name( uid_t );char *gid_to_name( gid_t );main(int ac, char *av[]){ if ( ac == 1 ) do_ls( "." ); else while ( --ac ){ printf("%s:\n", *++av ); do_ls( *av ); }}void do_ls( char dirname[] ){ DIR *dir_ptr; /* the directory */ struct dirent *direntp; /* each entry */ if ( ( dir_ptr = opendir( dirname ) ) == NULL ) fprintf(stderr,"ls1: cannot open %s\n", dirname); else { while ( ( direntp = readdir( dir_ptr ) ) != NULL ) dostat( direntp->d_name ); closedir(dir_ptr); }}void dostat( char *filename ){ struct stat info; if ( stat(filename, &info) == -1 ) /* cannot stat */ perror( filename ); /* say why */ else /* else show info */ show_file_info( filename, &info );}void show_file_info( char *filename, struct stat *info_p ){ char *uid_to_name(), *ctime(), *gid_to_name(), *filemode(); void mode_to_letters(); char modestr[11]; mode_to_letters( info_p->st_mode, modestr ); printf( "%s" , modestr ); printf( "%4d " , (int) info_p->st_nlink); printf( "%-8s " , uid_to_name(info_p->st_uid) ); printf( "%-8s " , gid_to_name(info_p->st_gid) ); printf( "%8ld " , (long)info_p->st_size); printf( "%.12s ", 4+ctime(&info_p->st_mtime)); printf( "%s\n" , filename );}void mode_to_letters( int mode, char str[] ){ strcpy( str, "----------" ); /* default=no perms */ if ( S_ISDIR(mode) ) str[0] = 'd'; /* directory? */ if ( S_ISCHR(mode) ) str[0] = 'c'; /* char devices */ if ( S_ISBLK(mode) ) str[0] = 'b'; /* block device */ if ( mode & S_IRUSR ) str[1] = 'r'; /* 3 bits for user */ if ( mode & S_IWUSR ) str[2] = 'w'; if ( mode & S_IXUSR ) str[3] = 'x'; if ( mode & S_IRGRP ) str[4] = 'r'; /* 3 bits for group */ if ( mode & S_IWGRP ) str[5] = 'w'; if ( mode & S_IXGRP ) str[6] = 'x'; if ( mode & S_IROTH ) str[7] = 'r'; /* 3 bits for other */ if ( mode & S_IWOTH ) str[8] = 'w'; if ( mode & S_IXOTH ) str[9] = 'x';}#include
char *uid_to_name( uid_t uid ){ struct passwd *getpwuid(), *pw_ptr; static char numstr[10]; if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){ sprintf(numstr,"%d", uid); return numstr; } else return pw_ptr->pw_name ;}#include
char *gid_to_name( gid_t gid ){ struct group *getgrgid(), *grp_ptr; static char numstr[10]; if ( ( grp_ptr = getgrgid(gid) ) == NULL ){ sprintf(numstr,"%d", gid); return numstr; } else return grp_ptr->gr_name;}

欢迎交流E-mail:1070443499@qq.com

转载地址:http://uiows.baihongyu.com/

你可能感兴趣的文章
Codewars第五天--Stop gninnipS My sdroW!
查看>>
Codewars第五天--Sort the odd
查看>>
Codewars第六天--Where my anagrams at?
查看>>
Codewars第七天--Give me a Diamond
查看>>
Codewars第八天--Roman Numerals Encoder
查看>>
Codewars第八天--Good vs Evil
查看>>
Codewars第八天–Valid Braces
查看>>
Codewars第八天--Valid Parentheses(带有字母的单个括号匹配)
查看>>
Codewars第九天–Can you get the loop ?
查看>>
Codewars第九天–Length of missing array
查看>>
Codewars第九天–Regex Password Validation
查看>>
Codewars第十天–Permutations
查看>>
Codewars第十一天–PermutationsNumber of trailing zeros of N!
查看>>
Codewars第十一天–PermutationsPrimes in numbers
查看>>
Codewars第十二天–What's a Perfect Power anyway?
查看>>
Codewars第十三天–Simplifying multilinear polynomials
查看>>
LeetCode第一题-----三数之和
查看>>
Codewars第十四天–Numbers that are a power of their sum of digits
查看>>
剑指offer---连续子数组的最大和
查看>>
剑指offer---从头到尾打印列表
查看>>