直接运行env可查看当前shell已导出的环境变量,但无法显示未export的变量或子shell中定义的变量;printenv适合查单个变量,set/declare -p可查看所有变量(含未导出项),需过滤噪音。

直接运行 env 就能看到当前 shell 会话中所有已导出的环境变量——但这是最常被误用的命令,因为它根本看不到你“以为存在”的那些变量。
为什么 env 看不到你刚 export 的变量?
典型现象:在脚本里写了 export MYVAR=123,紧接着 env | grep MYVAR 却没输出。这不是命令坏了,而是变量压根没生效。
- 确认脚本开头用了
#!/bin/bash—— 如果是#!/bin/sh(比如 dash),export VAR=val语法可能不被识别 - 检查是否在子 shell 中执行:
( export X=1; env )里的export只影响括号内进程,对外层无效 -
env显示的是当前进程的环境快照,不是“脚本里写过的变量”,必须实际执行并成功导出才存在 - 最可靠验证方式:脚本末尾加
printenv MYVAR和echo "MYVAR=$MYVAR"对照看
printenv 和 env 到底该用哪个?
功能高度重叠,但行为细节决定选谁:
- 查单个变量时必须用
printenv PATH——env PATH在多数系统上会尝试启动一个叫PATH的程序,报错或静默失败 -
printenv是 POSIX 标准命令,在 Alpine 等精简系统中更可能预装;env在某些嵌入式环境里反而缺失 - 两者都不显示未导出的变量,也不显示 bash 内置变量(如
BASH_VERSION) - 无参数时输出顺序一致,但新版 GNU
printenv默认按字母排序,env保持声明顺序
怎么看到包括未导出的自定义变量?
用 set 或 declare -p,但得过滤掉噪音:
-
set输出全部:变量 + 函数 + shell 内部状态,函数体可能占几百行 - 安全过滤写法:
set | grep '^[a-zA-Z_][a-zA-Z0-9_]*='—— 只留合法变量名开头的赋值行 -
declare -p更精准:declare -p | grep '^declare -x'等价于env,declare -p | grep -v '^declare -x'才是未导出的自定义变量 - 注意:
set对含换行符的变量值会自动加单引号包裹,比echo $VAR更可靠
排查程序实际收到的环境变量该看哪?
别信 shell 里跑的 env,要看进程启动时内核给它的原始环境:
- 当前 shell 的真实环境:
tr '\0' '\n' - 某子进程(如 nginx)的环境:
tr '\0' '\n' - 这个文件内容和
env输出完全一致,但绕过了 shell 层解析——如果发现两者不一致,说明 shell 启动后手动修改过环境,而该进程没继承这些改动 - 不能直接
cat /proc/*/environ,因为 null 字符会让终端显示混乱,tr转换必不可少
真正麻烦的不是命令记不住,而是变量作用域和 shell 类型混在一起时,同一个 export 在不同上下文里表现完全不同——比如在 .bashrc 里 export 的变量,在非登录 shell(如 cron job)里根本不存在。


















