实现代码如下(只支持-a 与-l 选项):
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>
#include<dirent.h>
#include<grp.h>
#include<errno.h>
#include<pwd.h>
#include<string.h>
#define PARAM_NONE 0
#define PARAM_A 1
#define PARAM_L 2
#define MAXROWLEN 80
void my_err(const char *err_string ,int line )
{
fprintf(stderr,"line:%d " ,line) ;
perror(err_string) ;
exit(1) ;
}
void display_attribute(struct stat buf,char *name)
{
char buf_time[32];
struct passwd *psd;
struct group *grp;
if(S_ISREG(buf.st_mode))
printf("-");
else if(S_ISDIR(buf.st_mode))
printf("d");
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(". ");
printf("%4d",buf.st_nlink);
psd=getpwuid(buf.st_uid);
grp=getgrgid(buf.st_gid);
printf("%-8s",psd->pw_name);
printf("%-8s",grp->gr_name);
printf("%6d",buf.st_size);
strcpy(buf_time,ctime(&buf.st_mtime));
buf_time[strlen(buf_time)- 1]='\0';
printf(" %s",buf_time);
}
void display(int flag_param,char *pathname)///home/liushengxi/test.c /home/liushengxi/.vimrc
{
int i,j;
struct stat buf;
char name[NAME_MAX + 1];//最长文件名 name
for(i= 0,j= 0;i<strlen(pathname);i++)
{
if(pathname[i]=='/')
{
j= 0;
continue;
}
name[j++]=pathname[i];
}
name[j]='\0';
if(lstat(pathname,&buf) < 0) //buf 存储文件
my_err("lstat",__LINE__);
switch(flag_param)
{
case PARAM_NONE:
if(name[0] != '.')
printf("%s\n",name);//打印单个文件
break;
case PARAM_A:printf("%s\n",name);
break;
case PARAM_L:
if(name[0] != '.')
{
display_attribute(buf,name); //另一个函数
printf("%-8s\n",name);
}
break;
case PARAM_A+PARAM_L:
display_attribute(buf,name);
printf("%-8s\n",name);
break;
default:break;
}
}
void display_dir(int flag_param,char *path) //path 目录名
{
DIR *dir;
struct dirent *ptr;
int count= 0;
char filename[256][PATH_MAX+ 1],temp[PATH_MAX + 1];
dir=opendir(path);
if(dir == NULL)
my_err("opendir",__LINE__);
while((ptr=readdir(dir)) != NULL)//目录下的文件名ptr->d_name
count++;
closedir(dir);
if(count > 256)
my_err("too many files in the dir ",__LINE__);
int i,j,len=strlen(path); //路径
dir=opendir(path);
for(i= 0;i<count;i++) //一个文件一个文件的打开
{
ptr=readdir(dir);
if(ptr == NULL )
{
my_err("readdir",__LINE__);
}
strncpy(filename[i],path,len);//把目录名考到filename中
filename[i][len]='\0';
strcat(filename[i],ptr->d_name);//把文件名考到filename中
filename[i][len+strlen(ptr->d_name)]='\0';
}
for(i= 0;i< count- 1;i++)
{
for(j= 0;j< count -1 -i ;j++)
{
if(strcmp(filename[j],filename[j + 1]) > 0 )//
{
strcpy(temp,filename[j+ 1]);
strcpy(filename[j + 1],filename[j]);
strcpy(filename[j],temp);
}
}
}
for(i= 0;i< count; i++)
display(flag_param,filename[i]);
closedir(dir);
}
int main(int argc,char **argv)
{
int i,j,k,num;
char path[PATH_MAX+ 1]; //路径
int param[32]; //保存命令行参数
struct stat buf; //文件信息
int flag_param=PARAM_NONE;//参数种类
j= 0;
num = 0;
for(i= 1;i<argc;i++) //ls -a -l rgbobn argc==4;num == 3
{
if(argv[i][0] == '-')
{
for(k= 1;k <strlen(argv[i]);k++,j++)
param[j]=argv[i][k];
}
num++;
}
for(i= 0;i< j;i++)
{
if(param[i] == 'a')
{
flag_param |= PARAM_A;
continue;
}
else if(param[i]== 'l')
{
flag_param |= PARAM_L;
continue;
}
else
{
printf("sorry !! now we agree -al\n");
exit(1);
}
}
param[j]='\0';
if((num + 1) != argc) //只输入a.out ,即 ls
{
strcpy(path,"./");
path[2]='\0';
display_dir(flag_param,path);//parh== './'
return 0;
}
i= 1;
do
{
if(argv[i][0] == '-')
{
i++;
continue;
}
else
{
strcpy(path,argv[i]);
if(stat(path,&buf)< 0)
my_err("stat",__LINE__);
if(S_ISDIR(buf.st_mode))// argv[i] 是一个目录
{
printf("ISDIR\n");
if(path[strlen(argv[i])- 1] != '/')
{
path[strlen(argv[i])] ='/';
path[strlen(argv[i]+ 1)] ='\0';
}
else path[strlen(argv[i])] ='\0';
display_dir(flag_param,path);//flag_param == 0
i++ ;
}
else //arhv[i]是一个文件
{
display(flag_param,path);
i++ ;
}
}
}while(i< argc);
return 0;
}
输入命令时的几种可能情况:
- ls
- ls -a
- ls -l
- ls -al
- ls -l /home
- ls -a -l /home/
- ls 文件
- ls -l 文件名
- ls -a -l 文件名
设计思路:
只有两种情况:
1. 查看文件
2. 查看目录
获取文件属性的三个函数:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
##struct stat *buf 保存文件状态信息的结构体
struct stat
{
dev_t st_dev; /* ID of device containing file -文件所在设备的ID*/
ino_t st_ino; /* inode number -inode节点号*/
mode_t st_mode; /* protection -保护模式?*/
nlink_t st_nlink; /* number of hard links -链向此文件的连接数(硬连接)*/
uid_t st_uid; /* user ID of owner -user id*/
gid_t st_gid; /* group ID of owner - group id*/
dev_t st_rdev; /* device ID (if special file) -设备号,针对设备文件*/
off_t st_size; /* total size, in bytes -文件大小,字节为单位*/
blksize_t st_blksize; /* blocksize for filesystem I/O -系统块的大小*/
blkcnt_t st_blocks; /* number of blocks allocated -文件所占块数*/
time_t st_atime; /* time of last access -最近存取时间*/
time_t st_mtime; /* time of last modification -最近修改时间*/
time_t st_ctime; /* time of last status change - */
};
struct passwd //保存文件所有者的信息
{
char * pw_name; /* Username, POSIX.1 /
char * pw_passwd; / Password /
__uid_t pw_uid; / User ID, POSIX.1 /
__gid_t pw_gid; / Group ID, POSIX.1 /
char * pw_gecos; / Real Name or Comment field /
char * pw_dir; / Home directory, POSIX.1 /
char * pw_shell; / Shell Program, POSIX.1 */
};
struct group { //保存文件所有者所属组的信息
char gr_name; / group name */
char gr_passwd; / group password /
gid_t gr_gid; / group ID */
char *gr_mem; / NULL-terminated array of pointers
to names of group members */
};
getpwuid函数是通过用户的uid查找用户的passwd数据
getgrgid()用来依参数gid指定的组识别码逐一搜索组文件,找到时便将该组的数据以group结构返回
The group structure is defined in\<grp.h> as follows:
struct group
{
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
系统标准配置变量包含由一个特殊系统标准所要求的最小值。POSIX、POSIX2_ 和 XOPEN 前缀显示变量包含分别由 POSIX 1003.1、POSIX 1003.2 和 X/Open 系统标准要求的系统特性最小值。系统标准是系统满足的用来支持特定系统标准的全系统最小值。实际配置值可能超出这些标准。用于 getconf 命令的这些系统标准配置变量的定义如下:
NAME_MAX
文件名中的最大字节数(不包含终止空字符)。如果 PathName 参数引用目录,返回值应用于目录内的文件名。
PATH_MAX
路径名中的最大字节数,包含终止空字符。如果 PathName 参数引用目录,返回值为当指定目录是工作目录时的相对路径名的最大长度。
struct dirent
{
long d_ino; /* inode number 索引节点号 /
off_t d_off; / offset to this dirent 在目录文件中的偏移 /
unsigned short d_reclen; / length of this d_name 文件名长 /
unsigned char d_type; / the type of d_name 文件类型 /
char d_name [NAME_MAX+1]; / file name (null-terminated) 文件名,最长255字符 */
}
从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。
转义序列以控制字符'ESC'开头。该字符的ASCII码十进制表示为27,十六进制表示为0x1B,八进制表示为033。多数转义序列超过两个字符,故通常以'ESC'和左括号'['开头。该起始序列称为控制序列引导符(CSI,Control Sequence Intro),通常由'\033['或'\e['代替。
通过转义序列设置终端显示属性时,可采用以下格式:
\033[ Param {;Param;…}m
或
\e[ Param {;Param;…}m
其中,'\033['或'\e['引导转义序列,'m'表示设置属性并结束转义序列。Param为属性值,{...}表示可选(多个参数之间用分号隔开,与顺序无关)。例如,在Linux Shell中执行下述命令:
即设置输出为红色字体(31),白色背景(47)。选项'-e'为echo命令激活特殊字符的解析器。
注意,转义序列可被控制字符'CAN'(Cancel )和'SUB'(Substitute)中断。
转义序列相关的常用参数如下(通过man console_codes命令可查看更多的参数描述):
显示:0(默认)、1(粗体/高亮)、22(非粗体)、4(单条下划线)、24(无下划线)、5(闪烁)、25(无闪烁)、7(反显、翻转前景色和背景色)、27(无反显)
颜色:0(黑)、1(红)、2(绿)、 3(黄)、4(蓝)、5(洋红)、6(青)、7(白)
前景色为30+颜色值,如31表示前景色为红色;背景色为40+颜色值,如41表示背景色为红色。
调色效果如下图所示:
因此,通过转义序列设置终端显示属性时,常见格式为:
\033[显示方式;前景色;背景色m输出字符串\033[0m
或
\e[显示方式;前景色;背景色m输出字符串\033[0m
其中 ,'\033[0m'用于恢复默认的终端输出属性,否则会影响后续的输出。
此外,还有一些ANSI控制码,如:nA (光标上移n行 )、nB(光标下移n行 )、nC(光标右移n行 )、nD (光标左移n行 )、2J(清屏)、K(清除从光标到行尾的内容)、s(保存光标位置)、u(恢复光标位置)、?25l(隐藏光标)、?25l(显示光标)。
基于常用参数,可定义如下单一控制宏,用于printf系列语句:
复制代码
1 #define NONE “\e[0m”
2 #define BLACK “\e[0;30m”
3 #define L_BLACK “\e[1;30m”
4 #define RED “\e[0;31m”
5 #define L_RED “\e[1;31m”
6 #define GREEN “\e[0;32m”
7 #define L_GREEN “\e[1;32m”
8 #define BROWN “\e[0;33m”
9 #define YELLOW “\e[1;33m”
10 #define BLUE “\e[0;34m”
11 #define L_BLUE “\e[1;34m”
12 #define PURPLE “\e[0;35m”
13 #define L_PURPLE “\e[1;35m”
14 #define CYAN “\e[0;36m”
15 #define L_CYAN “\e[1;36m”
16 #define GRAY “\e[0;37m”
17 #define WHITE “\e[1;37m”
18
19 #define BOLD “\e[1m”
20 #define UNDERLINE “\e[4m”
21 #define BLINK “\e[5m”
22 #define REVERSE “\e[7m”
23 #define HIDE “\e[8m”
24 #define CLEAR “\e[2J”
25 #define CLRLINE “\r\e[K” //or “\e[1K\r”
求10(1010)的第三位数
int a=10;
int b=a;
b=b>>(3-1)&1;
得到的b就是10的第三位