Linux下ls命令的实现Word格式.docx
《Linux下ls命令的实现Word格式.docx》由会员分享,可在线阅读,更多相关《Linux下ls命令的实现Word格式.docx(17页珍藏版)》请在冰豆网上搜索。
*__fd;
char
*__data;
int
__entry_data;
*__ptr;
__entry_ptr;
size_t
__allocation;
__size;
__libc_lock_define
(,
__lock)
};
typedefstruct__dirstreamDIR;
DIR结构体类似于FILE,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息。
函数DIR*opendir(constchar*pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:
struct
dirent
*readdir(DIR
*dp);
void
rewinddir(DIR
closedir(DIR
long
telldir(DIR
seekdir(DIR
*dp,
longloc);
2.1.2dirent结构体
对于dirent结构体,首先我们要弄清楚目录文件(directoryfile)的概念。
这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针。
从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件。
以下为dirent结构体的定义:
structdirent
long
d_ino;
/*
inodenumber索引节点号
*/
off_t
d_off;
/*
offset
to
thisdirent在目录文件中的偏移
unsignedshort
d_reclen;
lengthofthisd_name
文件名长
unsignedchar
d_type;
thetypeofd_name
文件类型
char
d_name[NAME_MAX+1];
filename
(null-terminated)
文件名,最长255字符
}
从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用。
2.1.3stat结构体
如果想获得类似ls-l那种效果的文件信息,必须要靠stat函数了。
通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中,而函数
intstat(constchar*file_name,structstat*buf);
的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中。
以下为stat结构体的定义:
stat{
mode_tst_mode;
//文件访问权限
ino_t
st_ino;
//索引节点号
dev_t
st_dev;
//文件使用的设备号
st_rdev;
//设备文件的设备号
nlink_tst_nlink;
//文件的硬连接数
uid_t
st_uid;
//所有者用户识别号
gid_t
st_gid;
//组识别号
st_size;
//以字节为单位的文件容量
time_tst_atime;
//最后一次访问该文件的时间
time_tst_mtime;
//最后一次修改该文件的时间
time_tst_ctime;
//最后一次改变该文件状态的时间
blksize_tst_blksize;
//包含该文件的磁盘块的大小
blkcnt_tst_blocks;
//该文件所占的磁盘块
2.2系统调用
2.2.1opendir函数
该函数的功能是打开目录。
相关函数
open,readdir,closedir,rewinddir,seekdir,telldir,scandir
表头文件
#include<
sys/types.h>
定义函数
DIR*opendir(constchar*name);
函数说明
opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和open()类似,接下来对目录的读取和搜索都要使用此返回值。
返回值
如果成功则返回DIR*型态的目录流,如果打开失败则返回NULL。
2.2.2readdir函数
该函数的功能是读取目录。
open,opendir,closedir,rewinddir,seekdir,telldir,scandir
structdirent*readdir(DIR*dir);
readdir()返回参数dir目录流的下个目录进入点。
成功则返回下个目录进入点。
有错误发生或读取到目录文件尾则返回NULL。
附加说明
EBADF参数dir为无效的目录流。
2.2.3closedir函数
该函数的功能是关闭目录。
opendir
intclosedir(DIR*dir);
closedir()关闭参数dir所指的目录流。
如果关闭成功则返回0,如果失败返回-1,错误原因存于errno中。
2.3处理流程
三、详细设计(含源程序)
首先设置标志,判断输入的命令。
如果是普通文件,则递归输出文件的相关信息,如文件的大小和最后修改时间。
如果是目录,则输出该目录下的所有文件和非正常文件的大小以及修改时间。
普通文件使用S_ISREG()函数,而目录文件使用S_ISDIR()函数。
源代码如下:
/*
*************************
Linux下的ls功能实现
计科1105班颜潇雨
*/
#include<
sys/stat.h>
unistd.h>
stdio.h>
string.h>
errno.h>
pwd.h>
grp.h>
time.h>
stdbool.h>
staticboolflags[4];
//标志,选项设定全局变量,用来确定是-l,-t还是-i
intmyls(char*s,boolflag[]);
voidlprint(char*fname);
/*main函数入口*/
intmain(intargc,char**argv)
{
charc;
inti;
while((c=getopt(argc,argv,"
alidtFR"
))!
=-1)//获取命令行输入的选项参数
{
switch(c)
{
case'
l'
:
flags[0]=1;
break;
i'
flags[1]=1;
t'
flags[2]=1;
default:
return-1;
}
}
if(argc==optind)//命令行没有输入目录参数,设定函数目录参数为当前目录
myls("
."
flags);
else
for(i=optind;
i<
argc;
i++)//依序对输入的所有目录参数进行myls函数操作
myls(argv[i],flags);
return0;
/*myls函数,调用lprint函数进行-l格式输出*/
intmyls(char*s,boolflag[])
structstatbuf,statbuf,tmps;
structstatsort[256];
char*t;
charfname[256],tmpn[256],sfname[256];
charsname[256][256];
DIR*dir;
structdirent*pd;
intnum,i,j;
if(lstat(s,&
buf)<
0)return-1;
//读取文件状态信息
if(S_ISDIR(buf.st_mode))//处理目录文件
dir=opendir(s);
//打开目录
/*处理-t*/
/*对目录下所有文件进行排序,存放在缓存中进行按序输出*/
if(flag[2])
num=0;
while((pd=readdir(dir))!
=NULL)//遍历目录下所有文件
{
if((pd->
d_name[0]=='
.'
)||(pd->
d_name[0]!
='
))
{
memset(fname,0,256);
strcpy(fname,s);
strcat(fname,"
/"
);
strcat(fname,pd->
d_name);
lstat(fname,&
sort[num]);
//读取文件信息到缓存数组sort[]中
strcpy(sname[num],pd->
//保存文件名到缓存数组sname[]中
num++;
}
}
/*将sort[]存储的文件信息进行排序*/
for(i=0;
num-1;
i++)
for(j=i+1;
j<
num;
j++)
if(sort[i].st_mtime<
sort[j].st_mtime)//按最后修改时间进行排序
{
tmps=sort[i];
sort[i]=sort[j];
sort[j]=tmps;
//交换sort[i]与sort[j]
/*交换sname[i]与sname[j]*/
strcpy(tmpn,sname[i]);
strcpy(sname[i],sname[j]);
strcpy(sname[j],tmpn);
}
/*将排序后的文件信息输出*/
if(flag[1])printf("
%ld\t"
sort[i].st_ino);
//-i
memset(sfname,0,256);
strcpy(sfname,s);
strcat(sfname,"
strcat(sfname,sname[i]);
if(flag[0])lprint(sfname);
//-l
printf("
%s"
sname[i]);
if(flag[0])printf("
\n"
elseprintf("
\t"
printf("
return0;
/*其他情况*/
else
))//-a
memset(fname,0,256);
strcpy(fname,s);
strcat(fname,"
strcat(fname,pd->
lstat(fname,&
statbuf);
if(flag[1])printf("
statbuf.st_ino);
if(flag[0])lprint(fname);
pd->
if(flag[1])printf("
buf.st_ino);
if(flag[0])lprint(s);
printf("
s);
if(flag[0])printf("
elseprintf("
printf("
/*lprint函数处理-l格式输出*/
voidlprint(char*fname)
structstatbuf;
intn;
charlink[256];
structpasswd*pw;
structgroup*gr;
structtm*t;
lstat(fname,&
buf);
switch(buf.st_mode&
S_IFMT)//获取并转换后打印文件类型
caseS_IFREG:
-"
break;
caseS_IFDIR:
d"
caseS_IFCHR:
c"
caseS_IFBLK:
b"
caseS_IFIFO:
p"
caseS_IFLNK:
l"
caseS_IFSOCK:
s"
for(n=8;
n>
=0;
n--)//获取并转换后打印文件的读写属性
if(buf.st_mode&
(1<
<
n))
switch(n%3)
case2:
r"
break;
case1:
w"
case0:
x"
default:
%d"
buf.st_nlink);
//硬链接数
pw=getpwuid(buf.st_uid);
//所属用户名
%s"
pw->
pw_name);
gr=getgrgid(buf.st_gid);
//所属组名
gr->
gr_name);
%ld"
buf.st_size);
//字节数
t=localtime(&
buf.st_mtime);
//最后修改时间
%d-%d-%d%d:
%d"
t->
tm_year+1900
tm_mon+1
tm_mday
tm_hour
tm_min);
if(S_ISLNK(buf.st_mode))//判断是否为链接
->
"
readlink(fname,link,100);
link);
四、运行结果与分析
1.当不输入命令时,即为空命令。
运行结果如下:
2.-l命令运行结果如下:
3.-i命令运行结果如下:
4.-t命令运行结果如下:
5.-l-i组合命令运行结果如下:
6.-l-t组合命令运行结果如下:
7.-l-i-t组合命令运行结果如下:
此次实验的运行结果不仅包含单个的-l、-i、-t命令,而且还有两两之间的组合,甚至可以是三者的结合-l-i和-t一起输出。
五、设计体会
本次实验是实现Linux下的ls功能。
在实验过程中,首先初步熟悉了Linux系统,掌握了它的一些编程方法。
其次对Linux的一些系统函数以及结构体也有了一定的了解。
另外,通过这次实验,不仅使我对ls命令有了更深一层的认识,还学会了系统提供的命令实现的途径和方法。
从以前仅仅是单纯地使用系统命令到现在可以自己通过编程来实现一些命令,能够感觉到些许的成就感。
但同时,也发现了使用系统提供的命令和调用自己编写的命令感觉是相差很大的。
在这编程和使用的过程中,尽管出现了很多困难,软件不熟悉,代码不断报错出现bug,甚至是开发环境不知道如何配置,但是通过同学的帮助都顺利解决了这些问题。
所以这也表明了我们还需要不断的学习和进步,这样才能进一步完善我们的代码,努力做得更好。
六、参考文献
[1]W.Richard
Stevens.Stephen
A.Rago.UNIX环境高级编程(第二版)[M].人民邮电出版社.2006.05.
[2]MichaelKerrisk.Linux/UNIX系统编程手册.人民邮电出版社.2014.01.
[3]刘忆智.Linux从入门到精通.清华大学出版社.2010.01.
[4]Neil
Matthew,Richard
Stones.Linux程序设计.人民邮电出版社.2010.06.