ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Shell重定向与文件描述符高级用法详解

Shell重定向与文件描述符高级用法详解 重定向是 Shell 里最容易绕晕的一块。、、21、、exec 3这些写法看着都是把输出导到文件差别却很大。搞不清文件描述符脚本一上线就出问题日志文件是空的、错误全跑屏上、该抓的错误没抓到。这一篇把文件描述符和重定向一次讲透。一、三个标准文件描述符每个进程一启动内核就帮它打开三个文件描述符file descriptor简称 FDFD名字方向默认指向0stdin 标准输入读键盘1stdout 标准输出写终端2stderr 标准错误写终端程序里printf出来的正常内容走 1报错信息走 2。很多人以为 stderr 是错误的输出流其实它就是第二条输出通道专门放诊断信息——这样你把正常结果重定向到文件时报错还能留在屏幕上不会被一起埋掉。二、基本重定向输出重定向写法作用cmd file标准输出覆盖写进 file截断原有内容cmd file追加cmd 2 file只把标准错误写进 filecmd file标准输出和标准错误都写进 filecmd file两者都追加前面省略了 1 file等价于1 file。输入重定向写法作用cmd file把 file 当标准输入cmd EOF ... EOFheredoc把多行内容喂进标准输入cmd 字符串here-string把一个字符串喂进去heredoc 实例直接生成一个配置文件catconfig.txtEOF host127.0.0.1 port8080 EOF预期config.txt内容host127.0.0.1 port8080EOF加了引号里面的$不会被展开不加引号host$HOST这行会先做变量替换。写配置文件时这个区别经常踩。结束标记 EOF 必须顶格写前后不能有空格否则 shell 认不出结束位置。here-string 只喂一小段比 heredoc 短grep-o127[0-9.]*server ip 192.168.1.1 and 127.0.0.1预期输出127.0.0.1不用先建临时文件脚本里做小测试很顺手。三、21顺序是核心这是整个重定向里最容易写错的一句。commandfile21意思是先把 1 指向 file再让 2 复制 1 的指向。结果 1 和 2 都写到 file。反过来写command21file意思是先让 2 复制当时 1 的指向终端再把 1 改指向 file。结果错误还打在屏幕上file 里只有正常输出。记住这条就够n是复制现在 n 指向哪里从左到右算。想把错误也收进文件21必须放在 file后面。写法stdout 去哪stderr 去哪cmd f 21ffcmd 21 ff终端cmd f 2 f2ff2cmd fff四、n、n- 与 exec自己玩文件描述符Shell 允许你借用 3、4、5 这些高位 FD。exec不带命令时只改当前 shell 的重定向不启动新进程。exec3/tmp/debug.logecho调试信息3exec3-3打开一个 FD3往这个 FD 写3-关闭。读方向一样exec4/etc/hostsreadline4echo$lineexec4-这种写法在脚本里常见的用途先把原来的 1 备份出来干一堆重定向的活最后恢复。exec31# 备份原 stdout 到 3exec/tmp/all.log# 之后所有 echo 都进日志echo脚本开始exec3# 恢复 stdoutexec3-五、/dev/null 与 tee/dev/null是个黑洞写进去什么都不剩读出来永远是空。丢弃输出用它rm-f*.tmp2/dev/null这样没有匹配文件时的报错不会刷屏。tee一分为二既打到屏幕又写文件make21|teebuild.log编译日志既能实时看到又留一份存档。想追加到已有文件加-a。六、进程替换把输出伪装成文件有些命令只接受文件路径当参数不读标准输入比如diff、comm。进程替换(...)把一个命令的输出挂成/dev/fd/63这样的临时路径骗命令以为它在看文件diff(ls/var/log)(ls/tmp)两个ls的结果直接比不用先落临时文件。批量对比两份配置文件的差异这招最省事。反向(...)把输入伪装成文件路径少见知道有这东西就行。一个常用组合脚本既打屏又落盘#!/bin/bashexec(tee/tmp/run.log)21echo开始ls/no-such-direcho结束预期输出开始 ls: cannot access /no-such-dir: No such file or directory 结束屏幕上能看到全过程/tmp/run.log里也留一份。第一行的意思把标准输出接到tee的输入再用21把错误也送进去。这种写法比每个命令后面都加| tee干净。七、⚠️ 常见错误 file 21写成21 file错误全跑屏上日志里只剩正常输出。heredoc 结束标记 EOF 顶格、前后无空格否则认不出。重定向是每个命令独立计算的cmd1 out | cmd2里 cmd2 读不到 out 文件内容它读的是 cmd1 的标准输出。cmd file是覆盖写脚本中断重跑会把上次日志清掉要保留历史用。两个独立的a 2a不带1写同一个文件stdout 和 stderr 各开一份输出会互相覆盖交错。常见写法速查目的写法丢弃所有输出cmd /dev/null只丢错误正常输出还要cmd 2 /dev/null正常和错误都进日志cmd app.log 21错误进日志正常打屏cmd 2 app.log读文件当输入cmd file同时打屏和写文件cmd八、知识扩展文件描述符怎么被子进程继承fork 出来的子进程会把父进程打开的文件描述符表整个复制一份。这就是重定向能工作的底层原因你在 shell 里exec 3file再./script.sh脚本里的echo 3照样能写进去——它继承了 3。这条规则反过来解释了21的顺序。重定向在命令启动前由 shell 从左到右准备好每个n都是在当时的快照上复制。21 file里 2 先复制的是1 当前指向终端这个事实之后 1 再改指文件2 不会跟着变。文件描述符在系统里只是个小整数内核用一张FD 号 → 打开文件描述file description的表来记。m复制的不是那个整数是那条 file description 的引用——两个 FD 指向同一个打开文件读写位置共享。所以cmd a 21里标准输出和错误交错写不会互相覆盖因为它们共用同一个文件偏移量。这也是为什么两个独立a 2a时输出会打架两个打开的文件描述各自维护偏移都截断、都从 0 写内容自然互相踩。
返回列表