LinuxNotes

第 13 章:环境变量

zjc 于 2026-01-13 发布

这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 环境变量影响命令查找、语言 locale、代理、密钥注入、运行时参数和容器配置。它也是生产问题的高发点:本机能跑、systemd 起不来;终端里有代理、服务里没有;CI 有变量、线上没有。本章讲清环境变量的作用域、加载顺序和治理方式。

13.1 基本操作

查看:

env
printenv
echo "$PATH"
echo "$HOME"
echo "$LANG"

设置:

export APP_ENV=production
export JAVA_OPTS="-Xms1g -Xmx1g"

仅当前命令生效:

APP_ENV=production ./server
LANG=C sort file.txt

删除:

unset APP_ENV

只对当前 Shell 生效。终端关闭后消失。

13.2 Shell 变量与环境变量

app=order
export app
env | grep '^app='

区别:

类型 当前 Shell 子进程
Shell 变量 可见 不可见
环境变量 可见 可见

查看进程环境:

tr '\0' '\n' < /proc/<pid>/environ

进程启动后修改 Shell 环境不会影响已启动进程。

13.3 PATH

查看:

echo "$PATH"
type java
which java
command -v java

临时添加:

export PATH="$PATH:/opt/app/bin"

优先级按目录顺序决定:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

安全原则:

  1. 不把 . 放入 PATH;
  2. 不把可写目录放在高优先级;
  3. 使用绝对路径执行关键命令;
  4. 检查命令别名;
  5. 不信任来路不明的 PATH。

检查别名:

alias
type -a ls

13.4 登录 Shell 加载顺序

Bash 常见顺序:

/etc/profile
  -> ~/.bash_profile 或 ~/.bash_login 或 ~/.profile
     -> interactive non-login 时读取 ~/.bashrc

常见文件:

文件 场景
/etc/profile 系统全局登录
/etc/profile.d/*.sh 软件包或团队全局配置
~/.bash_profile 用户登录
~/.profile 兼容登录
~/.bashrc 交互非登录

验证当前 Shell:

echo "$0"
shopt login_shell

SSH 登录、su、cron、systemd、容器入口的加载路径不同。服务变量应在服务配置中显式声明。

13.5 systemd 环境变量

方式一:

[Service]
Environment="APP_ENV=production"
Environment="JAVA_OPTS=-Xms1g -Xmx1g"

方式二:

[Service]
EnvironmentFile=/etc/order/env

文件格式:

APP_ENV=production
JAVA_OPTS=-Xms1g -Xmx1g
DB_PASSWORD_FILE=/run/secrets/db_password

查看:

systemctl show app -p Environment
sudo systemd-run --wait --property=EnvironmentFile=/etc/order/env env

修改后:

sudo systemctl daemon-reload
sudo systemctl restart app

13.6 cron 环境

cron 环境通常比登录 Shell 精简,PATH 和 Shell 可能不同。

导出任务环境:

crontab -l

示例:

SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""

30 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

脚本内部不要假设交互 Shell 环境,必要时显式 source 可信配置或直接写绝对路径。

13.7 容器环境变量

Docker:

docker run \
  --env APP_ENV=production \
  --env-file ./prod.env \
  my-app:1.0.0

查看:

docker inspect <container> \
  --format '{{range .Config.Env}}{{println .}}{{end}}'
docker exec <container> env

Kubernetes:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: order
          image: registry.example.internal/order:1.0.0
          env:
            - name: APP_ENV
              value: production
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: order-db
                  key: password

不要把数据库密码写进镜像层、Deployment YAML 或命令历史。

13.8 敏感信息治理

常见错误:

做法 风险
写入 Dockerfile ENV 进入镜像历史
写入 Git 明文配置 泄露和审计困难
写入命令行参数 进入进程列表和 Shell 历史
全局 export 影响范围过大
团队共享账号 无法追责

推荐:

  1. 使用 Secret Manager 或 Kubernetes Secret 加访问控制;
  2. 只注入需要的进程;
  3. 定期轮换;
  4. 审计访问;
  5. 日志脱敏;
  6. 本地开发使用独立示例配置。

13.9 locale 与时区

查看:

locale
timedatectl
date
cat /etc/timezone

设置:

sudo localectl set-locale LANG=en_US.UTF-8
sudo timedatectl set-timezone Asia/Shanghai

容器:

docker run --env TZ=Asia/Shanghai my-app:1.0.0

多语言和排序结果受 locale 影响。数据库、日志采集器和应用应统一字符集与时区。

13.10 代理变量

常见变量:

HTTP_PROXY=http://proxy.internal:3128
HTTPS_PROXY=http://proxy.internal:3128
NO_PROXY=.example.internal,127.0.0.1,10.0.0.0/8

使用:

export HTTPS_PROXY=http://proxy.internal:3128
curl -v https://example.com

取消:

unset HTTP_PROXY HTTPS_PROXY ALL_PROXY

代理配置只对尊重这些变量的工具生效。系统 DNS、某些运行时和数据库驱动可能需要单独配置。

13.11 排障案例

systemd 服务找不到命令

systemctl cat app
systemctl show app -p Environment
journalctl -u app -n 100
command -v java

修复:

[Service]
Environment="PATH=/opt/java/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/java/bin/java -jar /opt/app/app.jar

终端正常,cron 失败

grep -R 'PATH' /etc/crontab /var/spool/cron 2>/dev/null
bash -x /opt/scripts/job.sh

常见差异:

  1. PATH;
  2. HOME;
  3. LANG;
  4. TERM;
  5. 交互初始化文件;
  6. sudo 环境。

容器变量没有生效

docker inspect <container> --format '{{json .Config.Env}}' | jq .
kubectl get pod <pod> -o jsonpath='{.spec.containers[0].env}'
kubectl describe pod <pod>

检查:

  1. 变量名大小写;
  2. Pod 是否重建;
  3. ConfigMap 或 Secret 是否更新;
  4. 应用是否启动时读取;
  5. 挂载路径和 key 是否正确。

本章小结

环境变量有明确作用域:命令、Shell、用户、systemd、cron、容器和编排系统不同。生产服务应在 systemd unit、容器声明或 Secret Manager 中显式配置,不依赖登录 Shell。敏感变量要控制注入范围、轮换和审计。

思考题

  1. Shell 变量和环境变量的区别是什么?
  2. 为什么 systemd 服务不能依赖 ~/.bashrc
  3. cron 任务为什么常常因 PATH 失败?
  4. 容器 ENV 为什么不适合保存数据库密码?
  5. 设计一个服务的配置与环境变量分层方案。