Bash: file descriptor & exec
彻底搞懂shell的高级I/O重定向 - 骏马金龙 - 博客园 (cnblogs.com)
- 软件设计认为,程序应该有一个数据来源、数据出口和报告错误的地方。在Linux系统中,它们分别使用描述符0、1、2来表示,这3个描述符默认的目标文件(设备)分别是/dev/stdin、/dev/stdout、/dev/stderr,它们分别是各个终端字符设备的软链接。
bash内部的exec命令允许我们操作文件描述符,如果在exec之后没有指定命令,则exec命令之后的重定向将更改当前shell的fd - exec创建一个只读fd
也可连接至 pipe socket
exec 4< zc
读完一次数据后,再读为空
能读取追加的新内容
其内部维护了文件指针的数据结构
上面我们是省略写法,默认输入输入重定向的fd为0,因此
cat <&4 == cat 0<&4
cat 默认读取文件,可以改写其stdin我们可以直接覆盖原有fd,相当于删除,新建
上面创建的是 r-x权限的 fd,向其写数据会发生什么?
stderr没有发生写错误,原因尚不清楚
-
exec 创建只写fd, 如果文件有内容会清空
exec 4> zc
读数据发生错误
写数据没有问题
fd没有 >> 追加操作, 只有文件有追加, fd内部有指针, 默认效果就是追加
- 创建可读可写fd, 不会清空文件
exec {fd#}<> file # 从10开始自动分配
exec 3<> file文件指针在最开始
- 关闭fd
exec fd<&- or exec fd>&-
关闭当前shell 的stdout后, 遇到输出到stdout的产生错误
- 将当前shell stdout 重定向至 zc文件
exec 1> zc
将当前shell stdout 重定向至 zc文件 (慎用)
exec 2> zc
-
转移fd,会关闭原fd, 与关闭一样 < > 都可以
exec 3<> v
exec 4<&3-
exec 5>&4-复制的时候并不改变原fd rwx属性, 不能使用<>
- 复制fd, 比move 少了-
Example:
-
exec {fd}<> file
- 利用变量关闭fd
eval "exec $fd>&-"
此处必须使用eval
- 利用fd读取文件
#!/bin/env bash if [ $# -ne 1 -o ! -f "$1" ];then echo "Usage: `basename $0` <file>" exit 6 fi exec {fd}<$1
head -n+3 <&$fd eval "exec ${fd1}<&-" -
#!/bin/sh exec {fd}> mmm cat mmm echo uoiopp >&$fd eval "exec $fd<&-"
- 重定向脚本所有输出
#!/bin/bash : redirect all output to file exec {fd}>&1 # duplicate stdout exec 1> mmm 2>&1 df date +%c eval "exec 1>&$fd $fd<&-"
- 生成测试文件
测试脚本
#!/bin/bash if [ $# -lt 1 ];then echo "Usage:`basename $0` file" exit 5 fi while read -r line;do echo $line read -p $'Press any key continue...\n' -n 1 done < $1
此时没有执行read命令,将指定的文件作为while循环的标准输入,read也继承了这个fd(标准输入)
因此,read从重定向后的标准输入读取,而不是从默认的标准输入(键盘)读取
改进思路,while后的read -u 从文件描述符中读取,命令中的read依旧从stdin读取
#!/bin/bash if [ $# -lt 1 ];then echo "Usage:`basename $0` file" exit 5 fi exec {fd}< $1 echo $fd ls -l /proc/self/fd while read -u $fd line;do echo $line read -p $'Press any key continue...\n' -n 1 done
可以看到fd 11 的权限为 r-x -
#!/bin/bash exec 3< /etc/resolv.conf exec 4> mm ls -l /proc/self/fd read -u 3 a b echo $a $b echo uiop $a >&4 echo vbnm $b >&4 exec 3<&- exec 4>&- ls -l /proc/self/fd
- /dev/tcp/host/port
{ printf >&3 'GET / HTTP/1.0\r\n\r\n' cat 0<&3 } 3<> /dev/tcp/baidu.com/80
exec 3> /dev/tcp/x.com/80 echo -e 'GET / HTTP/1.0\r\n\r\n' >&3 cat <&3
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律