readonly 是 bash 内建硬性保护机制,用于锁定关键环境变量防止覆盖;适用于服务配置、路径常量、版本标识及已导出变量,需赋值后立即锁定,仅作用于当前 shell 且不可撤销。

在 Linux 运维中,用 readonly 锁定关键环境变量是防止脚本意外或恶意覆盖的最直接手段。它不是语法修饰,而是 Bash 内建的硬性保护机制——一旦设置,当前 shell 及其子 shell 中任何赋值或 unset 操作都会被拒绝,报错明确(如 bash: VARNAME: readonly variable),无需额外工具或权限。
哪些环境变量值得设为只读
优先锁定那些参与核心逻辑、路径固定、不应被运行时覆盖的变量:
-
服务配置类:如
DB_HOST、API_ENDPOINT、CONFIG_DIR—— 它们通常由部署脚本或配置文件加载,后续流程依赖其稳定性 -
路径常量类:如
LOG_PATH="$(realpath /var/log/myapp)"、BIN_DIR="/opt/myapp/bin"—— 避免因临时cd或路径拼接错误导致后续命令失效 -
版本与标识类:如
APP_VERSION="3.2.0"、ENVIRONMENT="prod"—— 防止条件判断逻辑被绕过 -
已导出的关键环境变量:例如
export PATH后再readonly PATH,可阻止脚本擅自追加危险路径(如PATH="/tmp:$PATH")
正确设置只读变量的两种方式
必须在变量有确定值之后立即锁定,否则等于没锁:
-
一步到位(推荐):声明即锁定,语义清晰且不易遗漏
readonly DB_PORT=5432 LOG_LEVEL="warn" MAX_CONNS=100 -
两步操作(适用于已有变量):先赋值,再锁定
CONFIG_FILE="/etc/myapp/config.yaml"<br> readonly CONFIG_FILE
注意:readonly $VARNAME 无效——必须写变量名本身,不能间接引用;也不支持 readonly ${VAR} 这类展开。
验证是否真正生效
别只信“写了”,要验证是否真的锁住了:
- 查看所有只读项:
readonly -p(输出带declare -r前缀的变量列表) - 检查单个变量:
declare -p DB_PORT 2>/dev/null | grep '^declare -r',返回 0 表示已锁定 - 主动测试修改:
DB_PORT=6543应立刻报错bash: DB_PORT: readonly variable—— 这是预期行为,不是故障 - 尝试清除:
unset DB_PORT会提示cannot unset: readonly variable
关键限制与注意事项
readonly 是强约束,但作用范围有限,需清楚边界:
- 只对当前 shell 进程及其派生的子 shell有效,不影响父进程、其他终端会话或系统级环境
- 无法撤销:Bash 没有
readonly -u或declare +r等解锁机制;唯一退出方式是结束当前 shell - 数组和函数需显式指定选项:
readonly -a myarray、readonly -f myfunc - 不保护环境变量的“继承性”:子进程仍能读取该变量,但若子进程自己重新定义同名变量(非 export 覆盖),不影响父进程只读状态











