覆盖写入,>> 追加写入;2>&1 复制描述符而非合并流;exec 重定向持久生效;管道默认不传 stderr。
重定向符号搞混了:> 和 >> 的实际行为差异
是覆盖写入,
是追加写入——但很多人没意识到,它们在打开文件时的底层动作完全不同。比如
会先清空目标文件(哪怕写入失败),而
总是在末尾 seek,不破坏原有内容。
如果脚本里反复用
写同一个日志文件,旧日志必然丢失,不是“没写进去”,是被主动截断了
在 NFS 或某些只读挂载下可能报
,因为追加需要写权限+执行权限(用于判断目录是否可写)
某些 shell(如 dash)对
的原子性支持较弱,高并发写同一文件时可能出现行交错,别指望它替代日志轮转工具
2>&1 不等于 “把所有输出都扔进一个地方”
只是把 stderr 的文件描述符复制成和 stdout 一样,
不是合并流内容
。如果 stdout 被重定向到文件,stderr 就跟着去那个文件;但如果 stdout 是终端,stderr 也还是终端——前提是没被提前改过。
错误写法:
—— 这里
发生在
之前,所以 stderr 指向的是原始 stdout(通常是终端),结果只有 stdout 进文件,stderr 还在屏幕上
正确顺序:
,或更清晰的
(bash/zsh 支持,dash 不支持)
如果要分别捕获又想按时间顺序看,
比单纯重定向更可控
exec 重定向会持续影响后续命令
对文件描述符的操作是进程级的,一旦执行,整个 shell 环境的 stdin/stdout/stderr 都会被改写,不只是当前命令。
CentOS Linux 7.9.2009
CentOS Linux 7.9.2009是传统CentOS Linux 7的最后主要版本,也是很多企业历史服务器中仍可能遇到的系统版本。它以稳定、兼容RHEL 7生态、文档丰富和软件支持广泛著称,曾长期用于Web服务、数据库、虚拟化节点和企业内部业务系统。不过CentOS Linux 7已于2024年6月30日停止维护,现在继续使用会面临安全补丁缺失风险。该版本更适合旧业务迁移、历史环境恢复或离线兼容性测试。
下载
开了个新 fd 3,安全;但
之后,所有没显式指定输出的命令(包括
、
、甚至 for 循环里的变量打印)都会进
恢复原始 stdout?不能靠
硬切,因为终端可能不是
;稳妥做法是提前备份:
在脚本里滥用
容易导致调试时“什么都没输出”,还以为命令没跑,其实是全写进文件了却忘了查
管道 + 重定向组合时,stderr 去哪了
管道默认只传 stdout,stderr 默认仍走终端。但很多人以为
会过滤掉所有输出,结果错误信息还是刷屏。
才能把 stderr 也送进管道;但注意,grep 只处理行,而 stderr 可能是无换行的进度条或二进制乱码
如果只想静默错误:
,别写成
(空格会让 shell 把
当作命令参数)
某些命令(如
)会检测 stdout 是否为终端,自动切换输出格式;重定向后可能丢失颜色或进度条,这不是 bug,是设计行为
事情说清了就结束。重定向看着简单,但 fd 层面的细节一错,输出就不可控——尤其在脚本里嵌套多次重定向时,建议用
实时看当前 shell 的 fd 映射。
>>>>>>>>>Permission denied>>echo "start" > log.txt
echo "done" >> log.txt # 这行才真正在末尾加内容2>&1cmd 2>&1 >out.log2>&1>out.logcmd >out.log 2>&1cmd &>out.logscript -qec 'cmd' /dev/null |& grep --line-buffered "error"execexec 3>tmpfileexec >log.txtecholslog.txtexec > /dev/tty/dev/ttyexec 3>&1; ...; exec 1>&3 3>&-exec >...cmd | grep "foo"cmd 2>&1 | grep "foo"cmd 2>/dev/nullcmd 2> /dev/null/dev/nullmakels -l /proc/$$/fd