Shell脚本实现环境变量与配置文件应用指南
作者:鸽芷咕
前言
在Shell脚本编程的世界里,环境变量与配置文件是实现脚本灵活性、可移植性的核心组件。无论是开发自动化部署脚本,还是编写多环境适配的工具,掌握这两项技能都能让你的脚本从“单一场景工具”升级为“通用解决方案”。今天,我们就从基础概念到实战案例,全面拆解环境变量与配置文件的应用逻辑。
一、环境变量:Shell脚本的“全局通行证”
环境变量是Shell中用于存储系统状态、用户偏好、路径信息的“全局变量”,它可以在父进程与子进程之间传递,是脚本与操作系统、不同程序间交互的重要桥梁。
1. 环境变量的核心作用
- 路径导航:最典型的
PATH变量,定义了系统执行命令时的搜索路径。例如/usr/local/bin加入PATH后,脚本中直接输入docker即可调用命令,无需写全路径。 - 身份标识:
USER(当前用户名)、HOME(用户主目录)、HOSTNAME(主机名)等变量,帮助脚本识别运行环境身份,比如判断当前是否为root用户执行脚本。 - 状态配置:
LANG(语言编码)、TZ(时区)等变量控制程序的运行状态,脚本可根据这些变量调整输出格式(如中文/英文日志)。 - 自定义参数:开发者可定义业务相关的环境变量,如
APP_ENV(区分开发/测试/生产环境)、DB_PORT(数据库端口),让脚本通过变量切换配置。
2. 环境变量的查看与分类
在终端中,通过以下命令可查看环境变量:
env:列出所有环境变量(可被子进程继承);set:列出所有Shell变量(包括环境变量和局部变量,局部变量仅当前Shell有效);echo $变量名:查看单个变量值,例如echo $PATH。
环境变量主要分为两类:
- 系统级环境变量:由操作系统初始化,对所有用户生效,配置文件通常在
/etc/profile、/etc/environment(Ubuntu); - 用户级环境变量:仅当前用户生效,配置文件在
~/.bashrc(bash Shell)、~/.zshrc(zsh Shell)。
3. 环境变量的设置与生效
根据变量的生效范围,设置方式分为三种场景:
(1)临时生效(当前Shell会话)
直接在终端或脚本中执行赋值命令,关闭Shell后变量消失:
# 格式:变量名=值(等号前后无空格) export APP_ENV=production # export关键字将变量标记为环境变量(可被子进程继承) echo $APP_ENV # 输出:production
(2)用户级永久生效(仅当前用户)
将变量配置写入用户级配置文件(如~/.bashrc),需重新加载配置或重启Shell生效:
# 1. 编辑配置文件 vim ~/.bashrc # 2. 在文件末尾添加变量(无需export,.bashrc加载时会自动处理) APP_ENV=development DB_HOST=localhost # 3. 重新加载配置(无需重启Shell) source ~/.bashrc # 或 . ~/.bashrc # 4. 验证 echo $DB_HOST # 输出:localhost
(3)系统级永久生效(所有用户)
需管理员权限,配置写入/etc/profile,对所有用户生效:
# 1. 编辑系统配置文件(需sudo) sudo vim /etc/profile # 2. 添加变量 export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 export PATH=$PATH:$JAVA_HOME/bin # 将Java路径追加到PATH # 3. 重新加载配置(所有用户需重新登录生效) source /etc/profile # 4. 验证 echo $JAVA_HOME # 输出:/usr/lib/jvm/java-11-openjdk-amd64 java -version # 正常显示Java版本,说明PATH配置生效
注意:修改系统级配置文件时需谨慎,错误配置可能导致系统命令失效(如PATH设置错误)。建议先在终端测试命令,确认无误后再写入配置文件。
二、配置文件:让脚本“按需加载”配置
当脚本需要大量参数(如数据库账号、API密钥、路径配置)时,直接写死在脚本中会导致维护困难——修改配置需修改脚本本身,且无法适配多环境。此时,将配置单独放在配置文件中,让脚本“按需读取”,是更优雅的解决方案。
1. 配置文件的常见格式
Shell脚本常用的配置文件格式为“键值对”,简单易懂且易于解析,示例(app.conf):
# 这是注释行(以#开头) # 数据库配置 DB_HOST=192.168.1.100 DB_PORT=3306 DB_USER=root DB_PASS=123456 # 生产环境需避免明文存储,可结合加密工具 # 应用配置 APP_NAME="MyShellApp" LOG_PATH="/var/log/myapp" DEBUG=true # 布尔值用true/false标记
2. 脚本读取配置文件的3种方法
(1)source命令加载(最简单)
source命令可将配置文件中的变量直接加载到当前Shell环境,脚本中可直接使用变量名调用,适用于信任的配置文件(无恶意代码):
#!/bin/bash
# 脚本名:load_config.sh
# 1. 检查配置文件是否存在
CONFIG_FILE="./app.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "错误:配置文件 $CONFIG_FILE 不存在!"
exit 1 # 退出脚本,状态码1表示错误
fi
# 2. 加载配置文件(变量直接生效)
source "$CONFIG_FILE"
# 3. 使用配置变量
echo "应用名称:$APP_NAME"
echo "数据库地址:$DB_HOST:$DB_PORT"
echo "日志路径:$LOG_PATH"
# 4. 条件判断(基于配置)
if [ "$DEBUG" = "true" ]; then
echo "调试模式已开启,日志将输出详细信息"
else
echo "生产模式,日志仅记录错误信息"
fi
执行脚本:
bash load_config.sh
# 输出:
# 应用名称:MyShellApp
# 数据库地址:192.168.1.100:3306
# 日志路径:/var/log/myapp
# 调试模式已开启,日志将输出详细信息
(2)awk解析(适合复杂配置)
若配置文件包含注释、空行,或需要筛选特定字段,可使用awk工具解析,避免加载无用变量:
#!/bin/bash
# 脚本名:parse_config.sh
CONFIG_FILE="./app.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "错误:配置文件 $CONFIG_FILE 不存在!"
exit 1
fi
# 使用awk提取键值对(忽略注释和空行)
# NF>0:非空行;$1!~/^#/:行首不是#(非注释)
DB_HOST=$(awk -F '=' '/^DB_HOST/ && NF>0 && $1!~/^#/ {gsub(/"/,"",$2); print $2}' "$CONFIG_FILE")
LOG_PATH=$(awk -F '=' '/^LOG_PATH/ && NF>0 && $1!~/^#/ {gsub(/"/,"",$2); print $2}' "$CONFIG_FILE")
# 输出解析结果
echo "解析到的数据库地址:$DB_HOST"
echo "解析到的日志路径:$LOG_PATH"
执行脚本:
bash parse_config.sh
# 输出:
# 解析到的数据库地址:192.168.1.100
# 解析到的日志路径:/var/log/myapp
(3)while循环逐行读取(灵活可控)
通过while read循环逐行处理配置文件,可自定义解析逻辑(如处理变量引用、多值配置):
#!/bin/bash
# 脚本名:read_config.sh
CONFIG_FILE="./app.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "错误:配置文件 $CONFIG_FILE 不存在!"
exit 1
fi
# 逐行读取配置文件(IFS=保持行内空格,-r避免转义字符生效)
while IFS= read -r line; do
# 跳过注释和空行
[[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
# 分割键值对(等号前后允许空格)
key=$(echo "$line" | awk -F '=' '{gsub(/[ \t]+/,"",$1); print $1}')
value=$(echo "$line" | awk -F '=' '{gsub(/[ \t]+|"|\047/,"",$2); print $2}') # 去除空格、引号
# 将键值对设置为脚本局部变量(避免污染全局环境)
declare "$key=$value"
done < "$CONFIG_FILE"
# 使用变量
echo "数据库用户:$DB_USER"
echo "调试模式:$DEBUG"
执行脚本:
bash read_config.sh
# 输出:
# 数据库用户:root
# 调试模式:true
3. 脚本修改配置文件(动态更新)
除了读取配置,脚本还可动态修改配置文件中的值(如通过脚本切换环境、更新密码),核心是使用sed工具替换文本:
#!/bin/bash
# 脚本名:update_config.sh
CONFIG_FILE="./app.conf"
TARGET_KEY="DB_PASS"
NEW_VALUE="abc67890" # 新的数据库密码
# 检查配置项是否存在
if ! grep -q "^$TARGET_KEY=" "$CONFIG_FILE"; then
echo "警告:配置项 $TARGET_KEY 不存在,将追加到配置文件"
echo "$TARGET_KEY=$NEW_VALUE" >> "$CONFIG_FILE"
else
# 替换配置项的值(sed:行首匹配TARGET_KEY=,替换等号后的内容)
sed -i "s/^$TARGET_KEY=.*/$TARGET_KEY=$NEW_VALUE/" "$CONFIG_FILE"
echo "已更新 $TARGET_KEY 的值为:$NEW_VALUE"
fi
# 验证修改结果
grep "^$TARGET_KEY=" "$CONFIG_FILE"
执行脚本:
bash update_config.sh
# 输出:
# 已更新 DB_PASS 的值为:abc67890
# DB_PASS=abc67890
注意:sed -i在Linux(GNU sed)中直接修改文件,在macOS(BSD sed)中需加空参数(sed -i ''),跨平台脚本可使用sed -i.bak(生成备份文件,再删除备份)。
三、实战:多环境适配的部署脚本
结合环境变量与配置文件,我们编写一个支持“开发/测试/生产”三环境的应用部署脚本,实现“一套脚本,多环境复用”。
1. 目录结构
deploy/
├── deploy.sh # 部署脚本
├── config/
│ ├── dev.conf # 开发环境配置
│ ├── test.conf # 测试环境配置
│ └── prod.conf # 生产环境配置
└── logs/ # 日志目录
2. 配置文件示例(prod.conf)
# 生产环境配置 APP_PORT=8080 DB_HOST=prod-db.example.com DB_PORT=3306 DB_USER=prod_user LOG_PATH="./logs/prod.log" DEPLOY_PATH="/opt/myapp"
3. 部署脚本(deploy.sh)
#!/bin/bash
set -e # 脚本出错时立即退出(避免继续执行)
# 1. 检查环境变量(指定部署环境)
if [ -z "$APP_ENV" ]; then
echo "请通过环境变量 APP_ENV 指定部署环境(dev/test/prod)"
echo "示例:APP_ENV=prod bash deploy.sh"
exit 1
fi
# 2. 加载对应环境的配置文件
CONFIG_FILE="./config/$APP_ENV.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "错误:环境 $APP_ENV 的配置文件 $CONFIG_FILE 不存在!"
exit 1
fi
source "$CONFIG_FILE"
echo "=== 加载 $APP_ENV 环境配置完成 ==="
# 3. 环境检查(如生产环境需验证DB地址)
if [ "$APP_ENV" = "prod" ]; then
echo "=== 生产环境前置检查 ==="
# 检查数据库连接(需安装mysql-client)
if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p -e "SELECT 1" > /dev/null 2>&1; then
echo "错误:无法连接生产数据库,请检查配置!"
exit 1
fi
echo "数据库连接正常"
fi
# 4. 部署步骤(示例:创建目录、启动应用)
echo "=== 开始部署 $APP_NAME ==="
# 创建部署目录
mkdir -p "$DEPLOY_PATH" "$(dirname "$LOG_PATH")"
# 模拟应用启动(实际场景替换为真实启动命令)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 应用启动成功,端口:$APP_PORT" >> "$LOG_PATH"
echo "部署完成!日志路径:$LOG_PATH"
# 5. 输出部署信息
echo -e "\n=== 部署信息汇总 ==="
echo "环境:$APP_ENV"
echo "应用端口:$APP_PORT"
echo "部署路径:$DEPLOY_PATH"
echo "数据库地址:$DB_HOST:$DB_PORT"
4. 执行部署脚本
# 部署生产环境(通过环境变量指定环境) APP_ENV=prod bash deploy.sh # 输出: # === 加载 prod 环境配置完成 === # === 生产环境前置检查 === # Enter password: (输入数据库密码) # 数据库连接正常 # === 开始部署 MyShellApp === # 部署完成!日志路径:./logs/prod.log # # === 部署信息汇总 === # 环境:prod # 应用端口:8080 # 部署路径:/opt/myapp # 数据库地址:prod-db.example.com:3306
通过环境变量APP_ENV切换环境,脚本自动加载对应配置,实现了“无修改适配多环境”,极大降低了维护成本。
四、避坑指南与最佳实践
- 环境变量与局部变量区分:脚本中未用
export的变量为局部变量,子进程无法访问;若需在ssh远程执行中使用变量,需先export或直接在命令中传递(如ssh user@host "APP_ENV=prod bash deploy.sh")。 - 配置文件安全:生产环境的配置文件(含密码、密钥)需限制权限,避免其他用户读取:
chmod 600 app.conf(仅所有者可读写)。 - 变量引用规范:所有变量引用建议加双引号(如
"$LOG_PATH"),避免变量值含空格时被解析为多个参数(例如LOG_PATH="/var/log/my app",不加引号会被拆分为/var/log/my和app)。 - 跨Shell兼容性:
bash特有的语法(如[[ ]]条件判断)在sh(POSIX Shell)中不生效,若需跨Shell兼容,建议使用[ ]和POSIX标准语法。 - 配置备份:修改配置文件前建议备份,例如
cp app.conf app.conf.bak,避免误操作导致配置丢失。
总结
环境变量是Shell脚本的“全局参数池”,配置文件是“场景化配置库”,两者结合是实现脚本灵活性的核心。从临时调试的变量设置,到多环境部署的配置加载,掌握这些技能能让你的Shell脚本从“一次性工具”升级为“可复用、可维护的工程化解决方案”。
到此这篇关于Shell脚本实现环境变量与配置文件应用指南的文章就介绍到这了,更多相关Shell脚本环境变量与配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
