linux输入ls命令报错,linux下实现ls命令

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函数.

*/

//print

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");

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值