Bash 自动分配文件描述符:重定向命令已经结束,为什么通道还可以继续写
普通命令的重定向通常跟着该命令结束,Bash 的 {变量名} 重定向却允许另一种生命周期:让 shell 自动挑选一个可用文件描述符,把编号存进变量,并在命令结束后继续保留它。于是仅执行一次冒号命令,也能为后续多次写入准备通道。
下面在 GNU Bash 5.2.37 上实跑,需要 Bash以及常见的mktemp、cat、rm命令。保存为 demo.sh,运行 bash --noprofile --norc demo.sh。程序只在新建临时目录中创建两个演示文件,退出时清理该目录。不要 source 到当前shell,因为它会调整本次shell的选项与描述符。
AI模型生成概念示意:上方通道连续并带开锁符号,下方通道断开并带闭锁符号;锁仅比喻通道开闭,不代表文件权限、安全加密或真实终端截图。
完整实验
#!/usr/bin/env bash
set -eu
work=$(mktemp -d)
trap 'rm -rf -- "$work"' EXIT
shopt -u varredir_close
: {channel}>"$work/persistent.txt"
printf 'first\n' >&"$channel"
printf 'second\n' >&"$channel"
exec {channel}>&-
printf 'persistent-file:\n'
cat -- "$work/persistent.txt"
if printf 'late\n' >&"$channel"; then
printf 'closed-write=unexpected-success\n'
else
printf 'closed-write=failed\n'
fi
printf 'variable-still-set=%s\n' "${channel+yes}"
unset channel
shopt -s varredir_close
: {automatic}>"$work/automatic.txt"
if printf 'late\n' >&"$automatic"; then
printf 'automatic-write=unexpected-success\n'
else
printf 'automatic-write=failed\n'
fi
if [[ ! -s "$work/automatic.txt" ]]; then
printf 'automatic-file=empty\n'
fi
unset automatic本地实际输出
persistent-file: first second closed-write=failed variable-still-set=yes automatic-write=failed automatic-file=empty
关闭 varredir_close 后,冒号命令旁的 {channel} 会申请编号不小于10的描述符,并把它写入 channel。冒号本身没有输出,随后两个 printf 都通过该编号写入同一文件,所以 persistent-file 下出现 first、second 两行。程序没有假定具体编号一定是10,避免与已经打开的描述符冲突。
exec {channel}>&- 根据变量中的编号关闭通道。紧接着的写入失败,因此 closed-write 输出 failed。variable-still-set 却仍然是 yes:关闭描述符不会自动删除保存编号的变量。随后 unset 只是清掉变量,不能用它替代关闭通道。
打开 varredir_close 后,第二个冒号命令一结束,自动分配的描述符就被关闭。后续写入同样失败,automatic.txt 保持空文件。这里的两个 if 是有意捕获失败路径,使错误可以观察,脚本仍能继续核对文件并正常退出。
边界与使用约定
本地标准错误还包含下面两条诊断,属于预期的关闭后写入实验。文件名、行号或错误文字可能随运行路径和语言设置改变;核心判断是写入命令失败,以及文件没有出现那行 late。
demo.sh: line 14: "$channel": Bad file descriptor demo.sh: line 24: "$automatic": Bad file descriptor
变量里保留一个数字,既不能证明描述符仍打开,也不能证明它仍指向原来的文件。关闭后这个编号可能被后续操作重新利用,因此不要把旧编号长期保存后再试着写入。把打开、使用、关闭安排在清楚的范围内,关闭后及时取消变量,才能降低误用可能。
如果要让一个复杂任务长期持有通道,需要同时安排异常退出时的关闭与临时文件清理。本例的进程退出会收回仍打开的描述符,EXIT清理只负责新建的临时目录。扩展为长期运行的shell函数时,应主动关闭自己申请的资源,不能依赖函数返回自动完成这一步。
参考资料
官方资料核验日期:2026-10-02。


