Linux命令-readonly(Bash 内建设置只读变量)

Linux命令-readonly(Bash 内建设置只读变量)

    • 命令语法
    • 常用选项
    • 场景化实例
      • [1. 基本使用:设置只读变量](#1. 基本使用:设置只读变量)
      • [2. 声明并赋值同时进行](#2. 声明并赋值同时进行)
      • [3. 查看系统已定义的只读变量](#3. 查看系统已定义的只读变量)
      • [4. 保护函数不被重新定义](#4. 保护函数不被重新定义)
      • [5. 脚本中使用只读变量防止错误](#5. 脚本中使用只读变量防止错误)
      • [6. 检测变量是否已设置为只读](#6. 检测变量是否已设置为只读)
      • [7. 数组只读](#7. 数组只读)
      • [8. 实际脚本:环境配置保护](#8. 实际脚本:环境配置保护)
    • 常用系统只读变量
    • 最佳实践

快速参考readonly 是 Bash 内建命令,用于将 shell 变量或函数标记为只读属性,设置为只读后变量不能被修改或取消,在脚本中用于保护关键常量,防止意外覆盖。

提示readonly 定义的变量在当前 shell 会话中永久生效,子进程不会继承只读属性。退出会话或其他脚本中不受影响。

命令语法

bash 复制代码
readonly [选项] [变量名[=值]] ...
readonly -f [函数名 ...]
readonly -p          # 显示所有只读变量

常用选项

选项 说明
-p 显示当前 Shell 中所有只读变量
-f 将指定的函数设置为只读
-a 引用索引数组(配合 -p)
-A 引用关联数组(配合 -p)

场景化实例

1. 基本使用:设置只读变量

bash 复制代码
#!/bin/bash
# 设置常量
readonly APP_NAME="MyApplication"
readonly APP_VERSION="3.2.1"

echo "应用: $APP_NAME v$APP_VERSION"

# 尝试修改会报错
APP_NAME="NewName"  # bash: APP_NAME: readonly variable

2. 声明并赋值同时进行

bash 复制代码
#!/bin/bash
# 两种方式等价
readonly PI=3.14159
readonly MAX_CONNECTIONS=100
declare -r MIN_THRESHOLD=10

echo "PI=$PI MAX=$MAX_CONNECTIONS MIN=$MIN_THRESHOLD"

# 后续代码中无法修改
# PI=3.14  # 报错!

3. 查看系统已定义的只读变量

bash 复制代码
#!/bin/bash
# 查看所有只读变量
echo "===== 系统只读变量 ====="
readonly -p

# 过滤特定只读变量
echo "===== 包含 EUID 的变量 ====="
readonly -p | grep EUID

# 输出示例:
# declare -ir BASHPID
# declare -ir EUID="500"
# declare -ir PPID="12345"
# declare -r BASH_COMPLETION_VERSINFO="2.12"

4. 保护函数不被重新定义

bash 复制代码
#!/bin/bash
# 定义关键函数并设为只读
log_error() {
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
}

readonly -f log_error

# 尝试重定义
log_error() { echo "hijacked!"; }

# bash: log_error: readonly function

5. 脚本中使用只读变量防止错误

bash 复制代码
#!/bin/bash
# 配置管理脚本
CONFIG_FILE="/etc/myapp/config.yaml"
readonly CONFIG_FILE
readonly BACKUP_DIR="/var/backup/myapp"
readonly LOG_DIR="/var/log/myapp"

# 保护备份脚本不被注入
backup_config() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    cp "$CONFIG_FILE" "$BACKUP_DIR/config_$timestamp.yaml"
    echo "备份完成: $BACKUP_DIR/config_$timestamp.yaml"
}

readonly -f backup_config

6. 检测变量是否已设置为只读

bash 复制代码
#!/bin/bash
# 检测只读属性
is_readonly() {
    local var_name="$1"
    readonly -p | grep -q "declare -.*r.* $var_name="
    return $?
}

export MY_EXPORT_VAR="hello"
readonly MY_READONLY_VAR="world"

is_readonly MY_EXPORT_VAR && echo "MY_EXPORT_VAR 只读" || echo "MY_EXPORT_VAR 可写"
is_readonly MY_READONLY_VAR && echo "MY_READONLY_VAR 只读" || echo "MY_READONLY_VAR 可写"

# 输出:MY_EXPORT_VAR 可写
#       MY_READONLY_VAR 只读

7. 数组只读

bash 复制代码
#!/bin/bash
# 设置只读数组
ALLOWED_HOSTS=("192.168.1.100" "192.168.1.101" "10.0.0.1")
readonly -a ALLOWED_HOSTS

echo "允许的主机:"
for host in "${ALLOWED_HOSTS[@]}"; do
    echo "  - $host"
done

# ALLOWED_HOSTS+=("192.168.1.102")  # 报错!

# 关联数组
declare -A PORT_MAP=([http]=80 [https]=443 [ssh]=22)
readonly -A PORT_MAP
echo "HTTPS 端口: ${PORT_MAP[https]}"

8. 实际脚本:环境配置保护

bash 复制代码
#!/bin/bash
# 生产环境部署脚本
set -euo pipefail

# 定义只读常量
readonly DEPLOY_ROOT="/opt/application"
readonly RELEASE_DIR="$DEPLOY_ROOT/releases"
readonly CURRENT_LINK="$DEPLOY_ROOT/current"
readonly MAX_RELEASES=5

deploy() {
    local version="$1"

    echo "部署版本: $version"
    mkdir -p "$RELEASE_DIR"

    local release_path="$RELEASE_DIR/$version"
    mkdir -p "$release_path"

    # 创建当前版本的符号链接
    ln -sfn "$release_path" "$CURRENT_LINK"
    echo "部署完成: $CURRENT_LINK -> $release_path"

    # 清理旧版本
    cleanup_old_releases
}

cleanup_old_releases() {
    local count=$(ls -1 "$RELEASE_DIR" | wc -l)
    if [ "$count" -gt "$MAX_RELEASES" ]; then
        echo "清理旧版本..."
        ls -1t "$RELEASE_DIR" | tail -n +$((MAX_RELEASES + 1)) | while read dir; do
            rm -rf "$RELEASE_DIR/$dir"
            echo "  已删除: $dir"
        done
    fi
}

readonly -f deploy cleanup_old_releases
deploy "v2.5.0"

常用系统只读变量

bash 复制代码
# Bash 内置只读变量
echo "UID=$UID EID=$EUID"
echo "PPID=$PPID BASHPID=$BASHPID"
echo "BASH_VERSION=$BASH_VERSION"

# 输出示例:
# UID=1000 EID=1000
# PPID=4521 BASHPID=5823
# BASH_VERSION=5.1.16(1)-release

最佳实践

常量用大写命名 ,集中在脚本开头定义;关键函数加 readonly -f 防止注入。只读变量需在子 shell 中重新声明。

bash 复制代码
#!/bin/bash
# 推荐模式:脚本开头集中定义
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
readonly TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
相关推荐
FlightYe2 小时前
FFmpeg移动端硬解机制
linux·网络·ffmpeg·音视频·实时音视频·视频编解码
笨笨没好名字3 小时前
Leetcode刷题python3版第一周(下)
linux·算法·leetcode
潘正翔3 小时前
docker基础_镜像使用
linux·运维·服务器·docker·容器·centos·devops
24计网1王仔寿4 小时前
Linux运维与云计算全栈系统化学习指南(Shell+虚拟化+OpenStack+Docker+公私云实战)
linux·课程设计·数据库开发·微信公众平台·neo4j·命令模式·sequoiadb
DB哥讲数据库4 小时前
rocky linux安装教程:VMware虚拟机图文讲解部署Rocky Linux 9(附镜像包)
linux·运维·服务器
未*望4 小时前
【Linux入坑(二)—全志T133开发板适配USB-电容屏触摸屏驱动(多点触控) 】
linux·运维·服务器
懒鸟一枚4 小时前
为什么 useradd -rs /bin/false service 创建的用户无法用 su 切换?
linux·服务器·数据库
學點4 小时前
Linux ubuntu安装redis
linux·redis·ubuntu
天空'之城5 小时前
Linux 系统编程 10:线程同步
linux·开发语言·系统编程·线程同步