admin管理员组文章数量:1655467
Linux下实现ls命令
(仅适用于ls
-a pathname ; ls -l pathname; ls pathname )
ls命令就是list的缩写,缺省下ls用来打印出当前目录的清单,如果ls指定其他目录,那么就会显示指定目录里的文件及文件夹清单。通过ls命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录、文件夹、文件权限),查看目录信息等等,ls命令在日常的linux操作中用的很多
-a选项:表示显示该目录下的所有文件,包括隐藏文件。
-l选项:表示显示文件的详细信息,包括访问权限,文件大小……
例如:ls
–a /
ls
–l /
1)主要构造的函数
void
error(const char *err_string, int line);
//错误处理函数,打印错误所在行数和错误信息
void
Demonstrate_attribute(struct stat buf, char *name);
//获得文件属性并打印
void
Demonstrate_single(char *name);
//输出文件名,命令没有-l选项。输出文件名要保持上下对齐
void
Demonstrate(int flag, char *pathname);
//根据命令行参数和文件路径名来显示目标文件
void
Demonstrate_dir(int flag_parameter, char *path);
//为显示某个目录下的文件做准备
2)函数流程
(1)获取该目录下文件的总数和最长文件名
(2)若获该目录下所有文件的文件名,存放于变量filenames中
(3)使用冒泡法对文件名按字母顺序存储于filenames中
(4)调用Demonstrate()函数来显示每个文件信息
3)程序中主要的结构体:
参数struct
stat *buf是一个保存文件状态信息的结构体
A):struct
stat {
dev
st_dev;//文件设备号
ino_t
st_ino;//文件的i-node
mode_t
st_mode;//文件类型和存储权限
nlink_t
st_nlink;//连到该文件的硬链接数目。
uid_t
st_uid;//文件所有者的用户id
gid_t
st_gid;//文件所有者的组id
dev_t
st_rdev;//若此文件为设备文件,则为其设备编号
off_t
st_size;//文件大小
blksize_t
st_blksize;//文件系统的I/O缓冲区大小
blkcnt_t
st_blocks;//占用文件区块的个数
time_t
st_atime;//文件最近一次被访问的时间
time_t
st_mtime;//文件最后一次被修改的时间
time_t
st_ctime;//文件最近一次被更改的时间
}
其中,对于st_mode包含的文件类型信息,POSIX标准定义了一系列的宏:
S_ISLNK(st_mode)//判断是否为符号链接
S_ISREG(st_mode)//判断是否为一般文件
S_ISDIR(st_mode)//判断是否为目录文件
S_ISCHR(st_mode)//判断是否为字符设备文件
S_IBLK(st_mode)//判断是否为块设备文件
S_ISFIFO(st_mode)//判断是否为先进先出FIFO
S_ISFOCK(st_mode)//判断是否为socket
B):
struct passwd*psd;//从该结构体中获取文件所有者的用户名
C):struct
group*grp;//从该结构体中获取文件所有者所属组的组名
4)心得体会
本次课程设计我写的是Linux下的ls命令,通过这次课程设计,不仅使我对ls命令有了更深一层的认识,还认识到了系统提供的命令实现的途径和方法。之前总是使用系统命令,如今自己编程实现了一些命令,每次使用系统提供的命令和调用自己编写的命令感觉大不相同。
5)具体解析与详细代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePARAMETER_NONE0//无参数
#definePARAMETER_A
1 // -a:显示所有文件
#definePARAMETER_L
2 // -l:一行显示一个文件的详细信息
#defineMAXROWLEN80//一行显示的最多字符数
intg_leave_len
= MAXROWLEN;//一行剩余长度,用于输出对齐
intg_maxlen;//存放某目录下最长文件名的长度
void
error(const char *err_string, int line); //错误处理函数,打印错误所在行数和错误信息
void
Demonstrate_attribute(struct stat buf, char * name); //获取文件属性并打印
void
Demonstrate_single(char * name);//输出文件名,命令没有-l选项,则输出文件名时要保持上下文对齐
void
Demonstrate(int flag, char * pathname); //根据命令行参数和文件路径名显示目标文件
void
Demonstrate_dir(int flag_parameter, char * path); //为显示某个目录下的文件做准备
int
main(int argc, char ** argv)
{
int
i, j, k, num;
charpath[PATH_MAX+1];
//文件路径名
charparameter[32];
//保存命令行参数,目标文件名和目录名不在此列
int
flag_parameter = PARAMETER_NONE; //用来标志参数种类,即是否有-l和-a选项
struct
statbuf;
/*
首先对命令行参数进行解析,即提取命令行参数中‘-’后的选项。用户的输入有多样性,如ls
-l -a; ls
-la。我们用两层循环类来解析参数,外层循环对argv[]数组中的元素依次进行内层循环的解析,二层循环对以‘-’为首的字符串进行选项提取,并把每个选项存于parameter[]数组当中,用num记下‘-’的数目,以备后用。而命令行参数中的总选项数目则用j计数。
*/
j
= 0,
num
= 0;
for
(i = 1 ; i < argc; i++)
{
if
(argv[i][0] == '-')
{
for(k
= 1; k < strlen(argv[i]); k++)
{
parameter[j]
= argv[i][k];//获取-后面的参数保存到数组parameter中
j++;
}
num++;
//保存"-"的个数
}
}
/*
检查刚刚提取的选项是否合法。并且用或运算记录参数,以备后用。最后为选项数组的末尾元素赋‘\0’。
*/
//check
the argument because of only supporting -a ang -l
for(i
= 0; i < j; i++)
{
if
(parameter[i] == 'a')
{
flag_parameter
= PARAMETER_A;
continue;
}
else
if (parameter[i] == 'l')
{
flag_parameter
= PARAMETER_L;
continue;
}
else
{
printf("my_ls:
invalid option -%c\n", parameter[i]);
exit(1);
}
}
parameter[j]
= '\0';
/*
由上面所知num记录的是参数中‘-’的数量,因此如果num+1==argc,那说明用户所输入的命令行参数不包含目录或文件名。只是显示当前目录下的文件。因为这是我们必须自动将path赋值为当前目录。为了使其称为一个字符串,必须在末尾加‘\0’。然后进入Demonstrate_dir函数.
*/
the information of current directory if the command without the name
of target file and current directory
if
((num + 1) == argc)
{
strcpy(path,
"./");// "./"当前目录
path[2]
= '\0';
Demonstrate_dir(flag_parameter,
path);
return
0;
}
/*
如果命令行参数包含目录或者文件名,那么我们要检查其合法性(参数中的目录或者文件是否存在)。这里我们利用stat族函数来获取文件的属性,实现上述功能。stat族函数通常有两个参数:文件路径/文件描述符,struct
stat
*buf类型的结构体。如果操作成功,那么buf将保存文件的属性。若合法,利用宏S_ISDIR(buf.st_mode),判断此文件是否为目录文件。若为目录文件则进入Demonstrate_dir函数,否则进入Demonstrate函数。通常情况,Demonstrate_dir函数是获取path目录下所有文件的完整路径名,在使每个文件执行Demonstrate函数。因此如果参数中是指定的文件名,则可绕过Demonstrate_dir函数,直接进入Demonstrate函数。
*/
i=1;
do
{
/*
**如果不是目标文件名或目录,解析下一个命令行参数
*/
if
(argv[i][0] == '-')
{
i++;
continue;
}
else
{
strcpy(path,
argv[i]);
/*
**如果目标文件或目录不存在,报错并退出程序
*/
if
( stat(path, &buf) == -1 )
{
error("stat",
__LINE__);
}
if
( S_ISDIR(buf.st_mode) ) // argv[i]是一个目录
//如果目录的最后一个字符不是'/',就加上'/'
{
if
( path[ strlen(argv[i])-1 ] != '/')
{
path[
strlen(argv[i]) ] = '/';
path[
strlen(argv[i])+1 ] = '\0';
}
else
{
path[
strlen(argv[i]) ] = '\0';
}
Demonstrate_dir(flag_parameter,path);
i++;
}
else
//argv[i]是一个文件
{
Demonstrate(flag_parameter,
path);
i++;
}
}
}
while (i < argc);
return
0;
}
/*
**错误处理函数,打印出错误所在行的行数和错误信息
*/
void
error(const char *err_string, int line)
{
fprintf(stderr,
"line:%d ", line);
perror(err_string);
exit(1);
}
/*
**获取文件属性并打印
*/
void
Demonstrate_attribute(struct stat buf, char * name)
{
charbuf_time[32];
//存放时间
struct
passwd*psd;//从该结构体中获取文件所有者的用户名
struct
group*grp;//从该结构体中获取文件所有者所属组的组名
/*
**获取并打印文件类型
*/
//st_mode:文件内容和存取权限
if
(S_ISLNK(buf.st_mode)) //判断是否为符号链接
{
printf("l");
}
else
if (S_ISREG(buf.st_mode)) //判断是否为文件
{
printf("-");
}
else
if (S_ISDIR(buf.st_mode)) //判断是否为目录
{
printf("d");
}
else
if (S_ISCHR(buf.st_mode)) //判断是否为字符设备文件
{
printf("c");
}
else
if (S_ISBLK(buf.st_mode)) //判断是否为块设备文件
{
printf("b");
}
else
if (S_ISFIFO(buf.st_mode)) //判断是否为先进先出的FIFO
{
printf("f");
}
else
if (S_ISSOCK(buf.st_mode)) //判断是否为socket
{
printf("s");
}
/*
**获取并打印文件所有者的权限
*/
if
(buf.st_mode & S_IRUSR)
{
printf("r");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IWUSR)
{
printf("w");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IXUSR)
{
printf("x");
}
else
{
printf("-");
}
/*
**获取并打印与文件所有者同组的用户对该文件的操作权限
*/
if
(buf.st_mode & S_IRGRP)
{
printf("r");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IWGRP)
{
printf("w");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IXGRP)
{
printf("x");
}
else
{
printf("-");
}
/*
**获取并打印其它用户的对该文件的操作权限
*/
if
(buf.st_mode & S_IROTH)
{
printf("r");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IWOTH)
{
printf("w");
}
else
{
printf("-");
}
if
(buf.st_mode & S_IXOTH)
{
printf("x");
}
else
{
printf("-");
}
printf("
");
/*
**根据uid与gid获取文件所有者的用户名与组名
*/
psd
= getpwuid(buf.st_uid);
grp
= getgrgid(buf.st_gid);
printf("%4d
",buf.st_nlink); //打印文件的链接数(该文件硬链接数目)
printf("%-9s",
psd->pw_name); //打印文件拥有者
printf("%-8s",
grp->gr_name); //打印文件所属用户组
printf("%6d",(int)buf.st_size);
//打印文件的大小
strcpy(buf_time,
ctime(&buf.st_mtime));
buf_time[strlen(buf_time)
- 1] = '\0';//去掉换行符
printf("
%s", buf_time);//打印文件的时间信息
}
/*
在没有使用-l选项时,打印一个文件名,打印时上下行之间进行对齐
*/
void
Demonstrate_single(char *name)
{
int
i, len;
/*
**如果本行不足以打印一个文件名则换行
*/
if
(g_leave_len < g_maxlen)
{
printf("\n");
g_leave_len
= MAXROWLEN;
}
len
= strlen(name);
len
= g_maxlen - len;
printf("%-s",
name);
for
(i = 0; i < len; i++)
{
printf("
");
}
printf("
");
/*
**下面的2指示空两格
*/
g_leave_len
-= (g_maxlen + 2);
}
/*
*根据命令行参数和完整路径名显示目标文件
*参数flag:
命令行参数
*参数pathname:
包含了文件名的路径名
*/
void
Demonstrate(int flag, char * pathname)
{
int
i, j;
struct
stat buf;
charname[NAME_MAX
+ 1];
/*
**从路径中解析出文件名
**/
for
(i = 0, j = 0; i < strlen(pathname); i++)
{
if
(pathname[i] == '/')
{
j
= 0;
continue;
}
name[j++]
= pathname[i];
}
name[j]
= '\0';
/*
**用lstat而不是stat以方便解析链接文件
*/
if
( lstat(pathname, &buf) == -1 ) //lstat返回的是符号链接文件文件本身的状态信息
{
error("stat",
__LINE__);
}
switch
(flag)
{
case
PARAMETER_NONE: //没有-l和-a选项
if
(name[0] != '.')
{
Demonstrate_single(name);
}
break;
case
PARAMETER_A: // -a:显示包括隐藏文件在内的所有文件
Demonstrate_single(name);
break;
case
PARAMETER_L: // -l:每个文件单独占一行,显示文件的详细属性信息
if
(name[0] != '.')
{
Demonstrate_attribute(buf,
name);
printf("
%-s\n", name);
}
break;
case
PARAMETER_A + PARAMETER_L://同时有-a和-l选项的情况
Demonstrate_attribute(buf,
name);
printf("
%-s\n", name);
break;
default:
break;
}
}
/*为显示目录下的文件做准备*/
void
Demonstrate_dir(int flag_parameter, char *path)
{
DIR
*dir;
struct
dirent *ptr;
int
count = 0;
char
filenames[256][PATH_MAX + 1],temp[PATH_MAX + 1];
//获取该目录下文件总数和最长的文件名
dir
= opendir(path);
if
(dir == NULL)
{
error("opendir",
__LINE__);
}
while
((ptr = readdir(dir)) != NULL)
{
if
(g_maxlen < strlen(ptr->d_name))
g_maxlen =
strlen(ptr->d_name);
count++;
}
closedir(dir);
if(count
> 256)
error("too
many files under this dir",__LINE__);
int
i, j, len = strlen(path);
//获取该目录下所有的文件名
dir
= opendir(path);
for(i
= 0; i < count; i++)
{
ptr
= readdir(dir);
if(
ptr == NULL)
{
error("readdir",__LINE__);
}
strncpy(filenames[i],path,len);
//filenames存放目录下的所有文件名
filenames[i][len] =
'\0';
strcat(filenames[i],ptr->d_name);
filenames[i][len +
strlen(ptr->d_name)] = '\0';
}
//使用冒泡法对文件名进行排序,排序后文件名按字母顺序存储于filenames
for(i
= 0; i < count-1; i++)
for(j
= 0; j < count - 1 - i; j++)
{
if(
strcmp(filenames[j],filenames[j + 1]) > 0 )
{
strcpy(temp,filenames[j
+ 1]);
temp[strlen(filenames[j
+ 1])] = '\0';
strcpy(filenames[j
+ 1],filenames[j]);
filenames[j +
1][strlen(filenames[j])] = '\0';
strcpy(filenames[j],
temp);
filenames[j][strlen(temp)]
= '\0';
}
}
for(i
= 0; i < count; i++)
Demonstrate(flag_parameter,
filenames[i]);
closedir(dir);
//如果命令行中没有-l选项,打印一个换行符
if(
(flag_parameter & PARAMETER_L) == 0)
printf("\n");
}
版权声明:本文标题:linux下ls命令无效,linux下实现ls命令 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1729699887a1210477.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论