首页 > 系统相关 >Linux命令基础——stat-readdir-dup2

Linux命令基础——stat-readdir-dup2

时间:2022-11-08 20:04:20浏览次数:60  
标签:stat dup2 int readdir char sb include hello

在学习Linux命令基础总结了笔记,并分享出来。

08-linux-day04(stat-readdir-dup2)

目录:一、学习目标二、文件和目录操作1、打开最大文件数量2、stat函数介绍3、stat函数介绍2与stat命令4、实现ls -l命令5、stat与lstat的区别6、access与truncate7、readlink、unlink8、unlink补充9、chown与rename10、chdir、getcwd切换目录和获得工作路径11、mkdir创建目录12、读目录相关函数介绍13、递归子目录统计普通文件个数14、errno说明15、dup2和dup说明16、dup2和dup的使用

一、学习目标

1、掌握stat/lstat函数的使用

2、了解文件属性相关的函数使用

3、了解目录操作相关的函数的使用

4、掌握目录遍历相关函数的使用

5、掌握dup、dup2函数的使用

6、掌握fcntl函数的使用


虚函数地址空间



Linux命令基础——stat-readdir-dup2_c++




二、文件和目录操作

1、打开最大文件数量


### xxx.c ---> xxx

>touch makefile

>vi makefile



1 ### xxx.c ---> xxx
2 SrcFiles=$(wildcard *.c)
3 TargetFiles=$(patsubst %.c,%,$(SrcFiles))
4
5 all:$(TargetFiles)
6
7 %:%.c
8 gcc -o $@ $^ -g
9
10 clean:
11 rm -f $(TargetFiles)




>touch openmax.c

>vi openmax.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main()
8 {
9 int num = 3;
10 char filename[128]={0};
11 while(1)
12 {
13 sprintf(filename,"temp_%04d",num++);
14 if(open(filename,O_RDONLY|O_CREAT,0666) < 0)
15 {
16 perror("open error");
17 break;
18 }
19 }
20 printf("num == %d\n", num);
21 return 0;
22 }



>make
>./openmax
open err:Too many open files
num == 1025
2、stat函数介绍
》man 2 stat
  int stat(const char* pathname, struct stat *buf);

存储原理:

>touch hello

>vi hello

(随便输入内容后保存退出)

>ln hello hello.hard

>ls -lrt

>ls -i hello*

输出:2642317 hello 2642317 hello.hard(ls -i 指定文件——查看指定文件的索引号)



Linux命令基础——stat-readdir-dup2_运维_02





Linux命令基础——stat-readdir-dup2_c++_03






Linux命令基础——stat-readdir-dup2_java_04



查找timespec结构体
>sudo grep -rn "struct timespec {" /usr/
查到time.h的位置 打开
>vi +9 文件位置
struct timespec {
  __kernel_time_t tv_sec;/*seconds*/当前时间到1970.1.1 0:0:0秒数
  long tv_nsec;/*nanoseconds*/纳秒
};
3、stat函数介绍2与stat命令
》stat函数参数
  pathname 文件名
  struct stat *buf 传出参数,定义struct stat sb;&sb
  返回值:成功返回0,失败返回-1
>touch stat.c
>vi stat.c


1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<unistd.h>
5
6 int main(int argc, char* argv[])
7 {
8 if(argc != 2)
9 {
10 printf("./a.out filename\n");
11 return -1;
12 }
13 struct stat sb;
14 stat(argv[1],&sb);
15 return 0;
16 }



保存退出
>make
>gdb stat
(gdb)b main
(gdb)run hello
(gdb)n
回车直到return 0;
(gdb)p sb
输出了结构体sb的信息
(gdb)p/o sb.st_mode
p/o 变量名:可以8进制查看某变量

》stat命令

>stat stat.c

还可以输出文件最近访问的时间(文件最新被读的时间)、最近更改的时间(内容更改)、最近改动的时间(大小、权限、硬链接等属性更改)

扩展:重定向可以只更改最近更改时间和最近改动时间,而不会更改文件最近访问时间

如:echo "hello world" >> hello;然后stat hello

4、实现ls -l命令

需要使用struct passwd* getpwuid(uid_t uid);获得用户名,需要传入uid



1 struct passwd{
2 char *pw_name;/*username*/用户名
3 char *pw_passwd;/*user password*/
4 uid_t pw_uid;/*user ID*/
5 gid_t pw_gid;/*group ID*/
6 char *pw_gecos;/*user information*/
7 char *pw_dir;/*home directory*/
8 char *pw_shell;/*shell program*/
9 };



struct group *getgrgid(gid_t gid);获得组名



1 struct group{
2 char *gr_name;/*group name*/组名
3 char *gr_passwd;/*group password*/
4 gid_t gr_gid;/*group ID*/
5 char **gr_mem;/*NULL-terminated array of pointers to names of group members*/
6 };



获得本地时间 struct tm *localtime(const time_t *timep); 传入参数timep对应stat函数得到的结构体的秒数(time_t类型),返回tm结构体



1 struct tm{
2 int tm_sec;/*Seconds(0-60)*/秒
3 int tm_min;/*Minutes(0-59)*/分钟
4 int tm_hour;/*Hours(0-23)*/小时
5 int tm_mday;/*Day of the month(1-31)*/天
6 int tm_mon;/*Month(0-11)*/月,需要+1
7 int tm_year;/*Year-1900*/年,需要+1900
8 int tm_wday;/*Day of the week(0-6,Sunday=0)*/
9 int tm_yday;/*Day in the year(0-365,1 Jan = 0)*/
10 int tm_isdst;/*Daylight saving time*/
11 };



>touch ls_l.c

>vi ls_l.c



1 //-rwrwxr-x 2 wang wang 22 6月 30 10:19 hello
2 #include<stdio.h>
3 #include<sys/types.h>
4 #include<sys/stat.h>
5 #include<unistd.h>
6 #include<fcntl.h>
7 #include<string.h>
8 #include<time.h>
9 #include<pwd.h>
10 #include<grp.h>
11
12 int main(int argc, char* argv[])
13 {
14 if(argc != 2)
15 {
16 printf("./a.out filename\n");
17 return -1;
18 }
19 //调用stat,得到文件属性信息
20 struct stat sb;
21 stat(argv[1],&sb);
22 //解析属性信息,st_mode,uid,gid,time
23 //st_mode
24 char stmode[11] = {0};
25 memset(stmode,'-',sizeof(stmode)-1);
26 if(S_ISREG(sb.st_mode)) stmode[0]='-';//普通文件
27 if(S_ISDIR(sb.st_mode)) stmode[0]='d';
28 if(S_ISCHR(sb.st_mode)) stmode[0]='c';
29 if(S_ISBLK(sb.st_mode)) stmode[0]='b';
30 if(S_ISFIFO(sb.st_mode)) stmode[0]='p';
31 if(S_ISLNK(sb.st_mode)) stmode[0]='l';
32 if(S_ISSOCK(sb.st_mode)) stmode[0]='s';
33
34 //解析权限
35 if(sb.st_mode & S_IRUSR) stmode[1]='r';
36 if(sb.st_mode & S_IWUSR) stmode[2]='w';
37 if(sb.st_mode & S_IXUSR) stmode[3]='x';
38
39 if(sb.st_mode & S_IRGRP) stmode[4]='r';
40 if(sb.st_mode & S_IWGRP) stmode[5]='w';
41 if(sb.st_mode & S_IXGRP) stmode[6]='x';
42
43 if(sb.st_mode & S_IROTH) stmode[7]='r';
44 if(sb.st_mode & S_IWOTH) stmode[8]='w';
45 if(sb.st_mode & S_IXOTH) stmode[9]='x';
46
47 //分析用户名,组名可以通过函数获得getpwuid,getgrgid
48 //时间获取
49 struct tm *filetm = localtime(&sb.st_atim.tv_sec);
50 char timebuf[20]={0};
51 sprintf(timebuf,"%d月 %d %02d:%02d",filetm->tm_mon+1,filetm->tm_mday,
52 filetm->tm_hour,filetm->tm_min);
53
54 printf("%s %ld %s %s %ld %s %s\n",stmode,sb.st_nlink,getpwuid(sb.st_uid)->pw_name,getgrgid(sb.st_gid)->gr_name,sb.st_size,timebuf,argv[1]);
55 printf("-rwrwxr-x 2 wang wang 22 6月 30 10:19 hello\n");
56 return 0;
57 }



>make

>ls -lrt

>./ls_l ls_l.c

结果与ls -l ls_l.c进行对比

5、stat与lstat的区别

>ln -s hello hello.soft

>ls -lrt

>./ls_l hello.soft

问题:stat编写的ls_l函数在查看软链接时,对软件大小出现错误(显示的是原来文件的大小),穿透功能。

解决:更改为lstat函数

>make

>ls -lrt

>./ls_l hello.soft

注意:stat与lstat的区别:stat碰到链接,会追溯到源文件,穿透!!!lstat并不会穿透。

6、access与truncate

》access判断文件的权限是否存在

man 2 access

int access(const char *pathname, int mode);

  pathname 文件

  mode

    R_OK

    W_OK

    X_OK

    F_OK

  返回值:如果有权限或者文件存在,对应返回0,失败返回-1,设置errno

>touch access.c

>vi access.c



1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main(int argc, char* argv[])
5 {
6 if(argc != 2)
7 {
8 printf("./a.out filename\n");
9 return -1;
10 }
11
12 if(access(argv[1],R_OK)==0) printf("%s read ok!\n",argv[1]);
13 if(access(argv[1],W_OK)==0) printf("%s write ok!\n",argv[1]);
14 if(access(argv[1],X_OK)==0) printf("%s exe ok!\n",argv[1]);
15 if(access(argv[1],F_OK)==0) printf("%s file exit!\n",argv[1]);
16
17 return 0;
18 }



>gcc access.c

>./a.out hello

>sudo ./a.out hello

注意:结果不同,说明针对使用用户不同,看到的结果不一样!

》truncate截断文件

man 2 truncate

int truncate(const char *path, off_t length);

  path 文件名

  length 长度,如果大于源文件,直接拓展,如果小于源文件,截断

  返回值:成功返回0,失败返回-1,设置errno

>touch truncate.c

>vi truncate.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4
5 int main()
6 {
7 truncate("hello",1024);
8
9 return 0;
10 }



>make

>./truncate

>ls -lrt

7、readlink、unlink

》link——创建硬链接

man 2 link

int link(const char *oldpath, const char *newpath);

  oldpath 源文件

  newpath 硬链接文件

  返回值:成功返回0,失败返回-1,设置errno

>touch link_symlink.c

>vi link_symlink.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4
5 int main()
6 {
7 link("hello", "hello.hard1");
8
9 return 0;
10 }



>make

>./link_symlink

>ls -lrt

》symlink——创建软链接

man 2 symlink

int symlink(const char *target, const char *linkpath);

  target 源文件

  linkpath 软链接文件

  返回值:成功返回0,失败返回-1,设置errno

>touch link_symlink.c

>vi link_symlink.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4
5 int main()
6 {
7 //link("hello", "hello.hard1");
8 link("hello", "hello.soft1");
9
10 return 0;
11 }



>make

>./link_symlink

>ls -lrt

》readlink——读取符号(软)链接本身内容,得到链接指向的文件名

man 2 readlink

ssize_t readlink(const char *path, char *buf, size_t bufsiz);

  pathname 链接名

  buf 缓冲区

  bufsiz 缓冲区大小

  返回值:成功返回buf填充的大小,失败返回-1,设置errno

>touch readlink_unlink.c

>vi readlink_unlink.c



1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 char buf[32]={0};
    //readlink("hello.hard1", buf, sizeof(buf));//硬链接不行
7 readlink("hello.soft1", buf, sizeof(buf));
8 printf("buf is %s\n", buf);
9 return 0;
10 }



>make

>./readlink_unlink

》unlink——删除符号(软)链接或者是硬链接计数

man 2 unlink

int unlink(const char *pathname);

  pathname 对应的链接名字,文件也可以

  返回值:成功返回0,失败返回-1,设置errno

>touch readlink_unlink.c

>vi readlink_unlink.c



1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 char buf[32]={0};
7 //readlink("hello.hard1", buf, sizeof(buf));//硬链接不行
8 readlink("hello.soft1", buf, sizeof(buf));
9 printf("buf is %s\n", buf);
10
11 unlink("hello.soft1");
12 unlink("hello.hard1");
13 return 0;
14 }



>make

>./readlink_unlink

8、unlink补充

如果文件后边需要用到,unlink先不删除,但是会写成功,进程结束后删除!

>touch unlink.c

>vi unlink.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7
8 int main(int argc, char* argv[])
9 {
10 int fd = open("world",O_WRONLY|O_CREAT,0666);
11
12 unlink("world");
13
14 int ret = write(fd,"hello", 5);
15 if(ret > 0){
16 printf("write ok!%d\n", ret);
17 }
18 if(ret < 0){
19 perror("write err");
20 }
21
22 close(fd);
23 return 0;
24 }



>make

>./unlink

9、chown与rename

》chown——改变用户和组

man 2 chown

int chown(const char *pathname, uid_t owner, gid_t group);

  pathname 文件名

  owner 用户ID,/etc/passwd

  group 组ID,/etc/group

》rename——重命名文件

man 2 rename

int rename(const char *oldpath, const char *newpath);

  oldpath 旧文件

  newpath 新文件

  返回值:成功返回0,失败返回-1,设置errno

>touch rename.c

>vi rename.c

>mkdir aaa



1 #include<stdio.h>
2
3 int main()
4 {
5 //改文件名
6 //rename("a.out", "a.new");
7 //改目录
8 rename("aaa","bbb")
9
10 return 0;
11 }



>make

>./rename

目录相关函数

10、chdir、getcwd切换目录和获得工作路径

 》getcwd——获得当前工作路径

man 2 getcwd

char *getcwd(char *buf, size_t size);

  buf 传出参数,路径

  size 缓冲区大小

  返回值:成功返回路径的指针,失败返回NULL

 》chdir——改变工作路径,注意属于进程独有的!

man 2 chdir

int chdir(const char *path);

  path 对应的目标工作路径

  返回值:成功返回0,失败返回-1,设置errno

>touch cwd_chdir.c

>vi cwd_chdir.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<sys/stat.h>
5 #include<fcntl.h>
6
7 int main(int argc, char* argv[])
8 {
9 //先切换工作目录
10 chdir("bbb");
11
12 //留下点痕迹
13 int fd = open("temp",O_WRONLY|O_CREAT,0666);
14 write(fd, "daociyiyou", 10);
15 close(fd);
16 //显示当前工作目录
17 char buf[256];
18 getcwd(buf, sizeof(buf));
19
20 printf("buf is [%s]\n", buf);
21 close(fd);
22 return 0;
23 }



>make

>./cwd_chdir

11、mkdir创建目录

》mkdir——创建目录

man 2 mkdir

int mkdir(const char *pathname, mode_t mode);

  pathname 路径

  mode mode & ~umask(0777)注意:权限问题,如果目录没有可执行权限,不可进入

  返回值:成功返回0,失败返回-1,设置errno

>touch mkdir.c

>vi mkdir.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4
5
6 int main(int argc, char* argv[])
7 {
8 if(argc != 2)
9 {
10 printf("./a.out filename\n");
11 return -1;
12 }
13
14 mkdir(argv[1],0777);
15 return 0;
16 }



>make

>./mkdir

12、读目录相关函数介绍

 》rmdir——删除空目录

man 2 rmdir

int rmdir(const char *pathname);

需求:统计一下指定目录下普通文件的个数,要求子目录递归

(shell计数:find ./ -type f | wc -l)

》opendir——打开目录

man 2 opendir

DIR *opendir(const char *name);

  name 打开的目录

  返回值:成功返回DIR*的指针,指向目录项的信息,失败返回NULL

》readdir——读目录

man 2 readdir

struct dirent *readdir(DIR *dirp);

  dirp 传入参数,opendir返回的指针

  返回值:成功为读到目录项的内容,读到末尾或者有错误返回NULL

》closedir——关闭目录

man 2 closedir

int closedir(DIR *dirp);

  dirp opendir得到的指针

13、递归子目录统计普通文件个数

>touch filecount.c

>vi filecount.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<dirent.h>
4 #include<sys/types.h>
5 #include<string.h>
6
7 int count = 0;//定义一个全局的计数
8
9 int DirCount(char *dirname)
10 {
11 printf("%s\n",dirname);
12 //打开目录
13 DIR *dirp = opendir(dirname);
14 if(dirp == NULL){
15 perror("opendir err");
16 return -1;
17 }
18 //循环读目录,如果是普通文件,count++,如果是目录,继续调用DirCount
19 struct dirent *dentp = NULL;
20 while((dentp = readdir(dirp))!= NULL){//如果为NULL,代表读到目录末尾
21 //printf("dirname:%s,dtype:%d\n",dentp->d_name,dentp->d_type);
22 if(dentp->d_type == DT_DIR){//如果是目录
23 if(strcmp(".",dentp->d_name)==0 || strcmp("..",dentp->d_name)==0){
24 continue;
25 }
26 //注意进程的工作路径,不能直接打开子目录
27 //使用dirname拼接下一级子目录
28 char newdirname[256]={0};
29 sprintf(newdirname,"%s/%s",dirname,dentp->d_name);
30 DirCount(newdirname);
31 }
32 if(dentp->d_type == DT_REG){
33 //普通文件,开始计数
34 count++;
35 printf("dname:%s\n",dentp->d_name);
36 }
37 }
38 //关闭目录
39 closedir(dirp);
40 return 0;
41 }
42
43 int main(int argc, char* argv[])
44 {
45 if(argc != 2)
46 {
47 printf("./a.out dirname\n");
48 return -1;
49 }
50
51 DirCount(argv[1]);
52 printf("count=%d\n",count);
53 //打开目录
54 struct DIR *dirp = opendir(argv[1]);
55 //循环读目录,判断如果是普通文件,计数++
56 readdir();
57 //关闭目录
58
59 return 0;
60 }



>make

>./filecount ./

>find ./ -type f | wc -l

(采用系统shell计数对比下二者计数是否相同)

14、errno说明

按全局变量理解,存储是错误信息

》查看vi /usr/include/asm-generic/errno.h

》查看vi /usr/include/asm-generic/errno-base.h

errno输出函数:可以用strerror打印出错误信息

man 2 strerror

char * strerror(int errnum);

15、dup2和dup说明

 》dup2——重定向

man 2 dup2

int dup2(int oldfd, int newfd);

  关闭newfd对应的文件描述符,将newfd重新指向为oldfd对应的文件

》dup——复制文件描述符

int dup(int oldfd);

  新返回一个文件描述符指向oldfd对应的文件

16、dup2和dup的使用

需求:在代码中执行2次print("hello world\n");前一次输出到hello文件中,后一次输出到屏幕上。

>touch dup2du.c

>vi dup2du.c



1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<sys/stat.h>
5 #include<fcntl.h>
6
7 int main()
8 {
9 //先备份现场
10 int outfd = dup(1);
11 //然后做重定向
12 int fd = open("world",O_WRONLY|O_CREAT,0666);
13 dup2(fd,1);//将标准输出重定向到fd对应的文件
14 printf("hello world\n");
15
16 //需要来一次刷新
17 fflush(stdout);
18
19 //需要恢复1重新对应标准输出
20 dup2(outfd,1);
21
22
23 printf("hello world\n");
24 close(fd);
25 return 0;
26 }



>make

>./dup2du

拓:fcntl也可以复制文件描述符。

在学习Linux命令基础总结了笔记,并分享出来。


标签:stat,dup2,int,readdir,char,sb,include,hello
From: https://blog.51cto.com/u_15405812/5834770

相关文章