5月29日 01:18
Shell 重定向和管道的工作原理是什么?
Shell 通过文件描述符(FD)管理数据流:stdin(0) 读入、stdout(1) 正常输出、stderr(2) 错误输出。重定向改变数据流向,> 覆盖写、>> 追加写,2> 重定向错误,2>&1 将 stderr 合并到 stdout,&> 是 Bash 4+ 的简写。管道 | 将左侧 stdout 传给右侧 stdin,但 stderr 不经过管道——需先用 2>&1 转换。/dev/null 是黑洞设备,丢弃输出用 > /dev/null 2>&1。Here Document(<<) 和 Here String(<<<) 用于内联输入,进程替换 <() 让两个命令的输出直接比较而无需临时文件。
追问
管道为什么只传 stdout?如何让 stderr 也通过管道?
管道连接的是 FD1→FD0,stderr 走 FD2 所以被丢弃。用 cmd 2>&1 | grep err 先将 FD2 合并到 FD1 即可。
set -o pipefail 有什么用? 默认管道返回最后一个命令的退出码,中间命令失败会被忽略。pipefail 使管道任一命令失败就返回非零,适合脚本严格错误检查。
进程替换 <() 和管道有什么区别?
管道是进程间 stdin/stdout 直连,只能单流向;<() 将命令输出映射为临时文件路径,支持多个输入源同时使用,如 diff <(cmd1) <(cmd2)。
exec 3> file.txt 是什么用法? exec 打开自定义 FD,后续通过 >&3 写入、<&3 读取,用完 exec 3>&- 关闭。适合脚本中多次读写同一文件避免反复打开。
写段代码
bash# 分别记录输出和错误,同时用管道过滤错误 ./deploy.sh 1>deploy.log 2>&1 | grep -i "error" # 进程替换对比两个目录 if ! diff <(ls dir1) <(ls dir2); then echo "目录内容有差异" fi