linux文件描述符和重定向的理解

1.1文件描述符分配规则

在进程的task_struct找到指针files,通过指针找到files_struct结构体对象,接着访问nd_array,找到数组内没有被分配&&最小的数组下标fd,会为新打开的文件建立一个struct file结构体对象(直接或间接包含文件属性),用新打开文件的属性初始化这一对象,接着把对象的地址填入nd_array[fd]

测试


我们看到关闭文件描述符1指向的文件,接着printf的内容都打印到了在之后第一个打开的文件log.txt(也就是文件描述符1分配给了log.txt),因为printf打印到stdout,stdout的FILE只认文件描述符1

输出重定向的做法,1.打开并清空文件 (2.向文件写入)

下图测试是只打开并清空文件,log.txt被清空

上面👆的测试我们可以看到,把文件描述符0指向的文件关了,在之后打开新文件,文件描述符0被分配了新文件,有没有什么办法在文件打开之后,把别的文件描述符指定分配给文件呢?下面我们介绍dup2

1.2 dup2

系统调用会把task_struct中struct files_struct* files中的nd_array数组下标fd的数组元素拷贝到1下标的内容,所以nd_array[newfd]=nd_array[oldfd]

如果newfd非空,那dup2会首先关闭newfd指向的文件,释放指向的struct file



因为标准输入/输出/错误的FILE封装的fd分别是0,1,2,在调用库函数比如fgets从标准输入读,进行系统调用,只认文件描述符0,而nd_array[0]的内容是什么,是否发生改变,语言层是不知道的,重定向的本质就是把nd_array的内容改了,就可以实现重定向

1.3 自定义shell的重定向

自定义shell主要处理的还是字符串用户输入的字符串,处理干净之后,进行差错处理,让子进程来执行或者父进程本身来执行

而重定向,把输入的字符串比如"ls -a -l > log.txt"切割为三部分,1.命令 2.重定向方式 3.文件名filename 这样在子进程exec前把stdout或者stdin的文件描述符替换为文件filename的fd,输入/追加/输出的区别就是打开文件的选项不同


由上面操作可以看到,在进程替换后,之前进行的重定向依然有效,进程替换的是代码和数据,与打开的文件无关

理解一切皆文件

小试牛刀

  1. Linux下两个进程可以同时打开同一个文件,这时如下描述错误的是()
    A.两个进程中分别产生生成两个独立的fd
    B.两个进程可以任意对文件进行读写操作,操作系统并不保证写的原子性
    C.进程可以通过系统调用对文件加锁,从而实现对文件内容的保护
    D.任何一个进程删除该文件时,另外一个进程会立即出现读写失败
    E.两个进程可以分别读取文件的不同部分而不会相互影响
    F.一个进程对文件长度和内容的修改另外一个进程可以立即感知

D

  1. 以下关于标准输入输出错误的描述正确的是()
    A.在文件描述符中0表示标准输出,1表示标准错误,2表示标准输入
    B.在文件描述符中0表示标准错误,1表示标准输出,2表示标准输入
    C.在文件描述符中0表示标准输入,1表示标准输出,2表示标准错误
    D.在文件描述符中0表示标准输出,1表示标准输入,2表示标准错误

C

  1. 以下描述正确的是()
    A.文件描述符和文件流指针没有任何关系
    B.文件流指针结构中封装了文件描述符
    C.通过open打开文件返回的FILE *fp可以直接使用read读取数据
    D.通过open打开文件返回的FILE *fp可以直接使用fread读取数据

B

C/D linux的open系统调用返回的是文件描述符(是一个整数)

  1. 以下描述正确的是 [多选]()
    A.程序中打开文件所返回的文件描述符, 本质上在PCB中是文件描述符表的下标
    B.多个文件描述符可以通过dup2函数进行重定向后操作同一个文件
    C.在进程中多次打开同一个文件返回的文件描述符是一致的
    D.文件流指针就是struct _IO_FILE结构体, 该结构体当中的int _fileno 保存的文件描述符, 是一对一的关系

ABD

C选项测试如下

  1. 在bash中,在一条命令后加入"1>&2"意味着()
    A.标准输出重定向到标准错误输出
    B.标准输入重定向到标准错误输出
    C.标准输出重定向到标准输入
    D.标准错误输出重定向到标准输入

A

1>&2,其中&2指向数字对应的文件描述符,如果是1>2,2也就是单独的数字表示文件名,echo 3>log.txt如果log.txt不存在,会新建

如果是1>3,3会被当做文件名,echo "测试" 1>3如果3不存在,会新建

  1. bash中,需要将脚本demo.sh的标准输出和标准错误输出重定向至文件demo.log,以下哪些用法是正确的 [多选]()
    A.bash demo.sh &>demo.log
    B.bash demo.sh >&demo.log
    C.bash demo.sh >demo.log 2>&1
    D.bash demo.sh 2>demo.log 1>demo.log

ABC

A/B 文件1 &> 文件2文件1 >& 文件2 都是把文件1的stdout和stderr重定向到文件2

C demo.sh > demo.log是把文件demo.sh的标准输出重定向到文件demo.log,接着2>&1把demo.sh的标准错误重定向到标准输出

D 分前后两部分理解,demo.sh 2>demo.log,打开并清空文件demo.log(输出重定向的前置操作),将demo.sh的标准错误绑定到文件demo.log,接着打开并清空demo.log,将demo.log的标准输出绑定到demo.log,首先第二次打开的时候导致demo.sh的标准错误信息丢失,其次,把一个文件的标准输出重定向到文件自身的意义何在

  1. 以下对int dup2(int oldfd, int newfd);接口描述错误的是: [多选]()
    A.重定向后,oldfd和newfd都会操作oldfd所操作的文件
    B.重定向后,oldfd和newfd都会操作newfd所操作的文件
    C.重定向前,若newfd已经有打开的文件,则会关闭
    D.重定向前,若oldfd已经有打开的文件,则会关闭

AC

  1. 以下代码的功结果是
    A.将hello bit打印到终端显示
    B.将hello bit 写入到tmp.txt中
    C.将hello bit 打印到终端显示并且写入tmp.txt文件中
    D.既不打印,也没有写入到文件中
c 复制代码
 void func() {
 	int fd = open("./tmp.txt", O_RDWR|O_CREAT, 0664);
	if (fd < 0) {
	return -1;
	}
	dup2(fd, 1);
	printf("hello bit");
	return 0;
}

B

系统调用会把task_struct中struct files_struct* files中的nd_array数组下标fd的数组元素拷贝到1下标的内容,而printf是往stdout写的,FILE内部封装了fd,stdout标准输出对应的文件描述符是1,所以往stdout写就是往文件描述符1指向的文件写,现在1下标写的是tmp.txt对应的struct file结构体对象的地址,所以printf写到了tmp.txt

相关推荐
Anjgst1 小时前
宝塔面板命令行
linux·运维·服务器·笔记
深邃-1 小时前
【Web安全】-计算机网络协议(1):IP协议详解,HTTP协议介绍
linux·tcp/ip·计算机网络·安全·web安全·http·网络安全
C.咖.1 小时前
Linux 基础指令详解 —— 从入门到熟练
linux·服务器·指令·linux指令
minji...1 小时前
Linux 网络基础(五)守护进程化,前后台进程组,作业,会话,setsid(),daemon(),端口号频繁更换问题
linux·运维·服务器·网络·c++·tcp/ip
剑神一笑1 小时前
Linux du 命令深度解析:从磁盘占用统计到目录空间分析
linux·运维·前端
AOwhisky1 小时前
Docker 学习笔记:从生态系统到镜像构建
linux·运维·笔记·学习·docker·容器
CoderMeijun1 小时前
Linux 进程间通信:共享内存详解
linux·共享内存·进程间通信·ipc·shmget
坚持就完事了1 小时前
Ubuntu和Centos中安装软件的命令
linux·ubuntu·centos
程序猿编码1 小时前
Linux 高负载场景下 Web 服务访问日志极速定位工具实现解析(C/C++代码实现)
linux·服务器·c语言·前端·c++