深入 Linux I/O 重定向
一个文件描述符说白了就是文件系统为了跟踪这个打开的文件而分配给它的一个数字,也可以的将其理解为文件指针的一个简单版本,与C语言中文件句柄的概念很相似。
Linux 中默认情况下始终有 3 个“文件”处于打开状态,stdin(键盘)、 stdout(屏幕)和 stderr(错误消息输出到屏幕上)。这 3 个文件和其他打开的文件都可以被重定向。重定向,简单的说就是捕捉一个文件、命令、程序、脚本,或者是脚本中的代码块的输出,然后将这些输出作为输入发送到另一个文件、命令、程序或脚本中。
每个打开的文件都会被分配一个文件描述符。stdin、stdout 和 stderr 的文件描述符分别是 0、1 和 2。除了这 3 个文件,对于其它那些需要打开的文件,保留了文件描述符 3 到 9。在某些情况下,将这些额外的文件描述符分配给 stdin、stdout 或 stderr 作为临时的副本链接是非常有用的。在经过复杂的重定向和刷新之后需要把它们恢复成正常状态。
file将 stdout 重定向到一个文件。如果这个文件不存在,那就创建,否则就覆盖。
创建一个包含目录树列表的文件:
ls -lR dir-tree.list
清空文件:
: file
这是一个 操作,将会把文件 file 变为一个空文件(就是 size 为 0)。如果文件不存在,那么就创建一个 0 长度的文件(与touch 的效果相同)。: 是一个占位符,不产生任何输出。
也可以省略 : 占位符:
file
与上边的 : 效果相同, 但是某些 shell (比如 bash)可能不支持这种形式。
file将 stdout 重定向到一个文件。如果文件不存在,那么就创建它,如果存在,那么就追加到文件后边。
script.sh 1 filename # 重定向 stdout 到文件"filename". script.sh 1 filename # 重定向并追加 stdout 到文件"filename". script.sh 2 filename # 重定向 stderr 到文件"filename". script.sh 2 filename # 重定向并追加 stderr 到文件"filename". file
将 stdout 和 stderr 都重定向到文件:
script.sh /dev/null m file
m 是一个文件描述符,如果没有明确指定的话默认为 1。
file 是一个文件名。文件描述符 m 被重定向到文件 file。
script.sh 2 error.log
m 是一个文件描述符,如果没有明确指定的话默认为 1。
n 是另一个文件描述符。
script.sh 2 1
重定向 stderr 到 stdout。将错误消息的输出,发送到与标准输出所指向的地方。
exec 6 File
script.sh 6
默认的,重定向文件描述符 1(stdout)到 6。所有传递到 stdout 的输出都送到 6 中去。
file从文件中接受输入。与 是成对命令,并且通常都是结合使用。0 file 或 file,前面的标准输入 stdin 0 可以省略。
grep search-word filename j file
为了读写 file,把文件 file 打开,并且将文件描述符 j 分配给它。
如果文件 file 不存在,那么就创建它。如果文件描述符 j 没指定,那默认是标准输入 stdin 0 。
echo 1234567890 File ### 写字符串到 File . exec 3 File ### 打开 File 并且将 fd 3 分配给它. read -n 4 3 ### 只读取4个字符. echo -n . 3 ### 写一个小数点. exec 3 - ### 关闭fd 3. cat File ### == 1234.67890
(注:上述命令的输出结果和原文不同,原因未知。)
管道与 很相似,但是实际上更通用。对于想将命令、脚本、文件和程序串连起来的时候很有用。
cat *.txt | sort | uniq result-file
上述命令对所有 .txt 文件的输出进行排序,并且删除重复行。最后将结果保存到 result-file 中。
可以将输入输出重定向和/或管道的多个实例结合到一起写在同一行上:
command input-file output-file
等价于:
input-file command output-file
但是这种写法不标准,有的 shell 可能不支持。
可以将多个输出流重定向到一个文件上:
ls -yz command.log 2 1
将错误选项 yz 的结果放到文件 command.log 中。因为 stderr 被重定向到这个文件中,所以所有的错误消息也就都指向那里了。
注意,下边这个例子就不会给出相同的结果:
ls -yz 2 1 command.log
输出一个错误消息,但是并不写到文件中。命令的输出(如果有的话)写入到文件 command.log。
如果同时将 stdout 和 stderr 都重定向,命令的顺序不同会带来不同的结果。
关闭文件描述符n - 关闭输入文件描述符 n。
0 - 或 - 关闭 stdin。
n - 关闭输出文件描述符 n。
1 - 或 - 关闭 stdout。
子进程继承了打开的文件描述符。这就是为什么管道可以工作的原因。如果想阻止文件描述符被继承,那么可以关掉它。
只将 stderr 重定到一个管道。
exec 3 1 ### 保存当前 stdout 的"值"(将 fd3 指向 fd0 相同目标) ls -l 2 1 3 3 - | grep bad 3 - ### 对grep关闭 fd 3 ### ^^^^ ^^^^ ###(但不关闭ls,正常输出内容不受grep影响) ls -l 2 1 3 | grep bad ### 这样输出内容被转到了 fd3,也不会受 grep 影响 ls badabc -l 2 1 3 |grep bad ### stderr 通过 fd1 输出,会受 grep 影响 exec 3 - ### 对于剩余的脚本来说,关闭它
使用文件描述符 5 可能会引起问题。当 Bash 使用 exec 创建一个子进程的时候,子进程会继承文件描述符 5 (参考 Chet Ramey 的归档 e-mail: RE: File descriptor 5 is held open)。 最好还是不要去招惹这个特定的文件描述符 5 。
原文发布时间为:2017-01-19
本文来自云栖社区合作伙伴“Linux中国”
相关文章
- 数据库学习之数据库增删改查(另外解决Mysql在linux下不能插入中文的问题)(二)
- [Linux] linux文件系统学习
- 实现一个跨平台的mysock库(windows、linux)
- linux里source、sh、bash、./有什么区别(转)
- Linux基础之重定向stdout/stderr
- Linux基础之测试域名IP端口连通性
- linux下性能分析命令[总结]
- Linux性能监控文章参考
- L85.linux命令每日一练 -- 第12章 Linux系统常用内置命令(一)
- L65.linux命令每日一练 -- 第十章 Linux网络管理命令 -- ifdown和route
- L48.linux命令每日一练 -- 第七章 Linux用户管理及用户信息查询命令 -- last、lastb和lastlog
- 嵌入式Linux开发,Ubuntu22下交叉编译报错:arch64-linux-gnu-gcc: error while loading shared libraries: libstdc++.so.
- 嵌入式linux开发,telnet,telnetd服务移植
- linux查看标准错误码工具
- 【测试入门百科】1000字Linux 环境变量配置总结
- 74:应急响应-win&linux分析后门&勒索病毒&攻击 ==》暴力破解攻击成功的在4624的eventID里!PChunter可查看非系统的可疑启动项/服务/定时任务,还是很直观的!Linux下gscan也不错,EDR可参考。
- Linux查找文件和目录,重定向输出 ,系统默认运行级别的查看和设置理论和练习
- 【日常工作所需,零锁整理一】Linux时间同步配置:chrony和ntpd服务