资讯动态

Linux 进阶必会:一文彻底搞懂 Shell 变量与环境变量(定义、作用域、持久化、命令替换全实战)

发布时间:2026/9/12 19:33:48 来源:尧图企业网站定制
变量能不能被子脚本继承export到底干什么为什么改完配置重开 bash 又不生效本文从变量定义讲到作用域、环境变量、持久化、命令替换与引号转义每个知识点配「用法速查表」和可复制的实战命令。一、Shell 变量定义与查看Linux 用变量保存临时的字符串值。变量值存在当前会话内存中退出 shell 即失效。变量命名规范只能包含字母、数字、下划线且不能以数字开头变量类型一般无需显式声明。用法速查表命令作用说明变量名值定义变量等号两边不能有空格declare 变量名值标准定义显式声明方式$变量名/${变量名}引用变量${}可限定变量名边界set查看所有变量同时会显示函数unset 变量名取消变量删除变量定义declare -l 变量转小写定义时自动转换为小写declare -u 变量转大写定义时自动转换为大写变量名$(命令)存命令结果把命令输出赋值给变量readonly 变量名值只读变量定义后不可修改、不可 unsetdeclare -r 变量名值只读变量作用同readonlydeclare -i 变量整型变量声明为整数自动做算术运算# 变量定义等号两边不能有空格[zhbzhb-m1 ~]$var1key1[zhbzhb-m1 ~]$declarevar1key1# 标准格式# 使用 $ 引用变量值[zhbzhb-m1 ~]$echo$var1key1# 多个变量[zhbzhb-m1 ~]$first_namefacai[zhbzhb-m1 ~]$last_namezhang[zhbzhb-m1 ~]$echo$last_name$first_namezhang facai# 引号可保留多个空格不加引号会被压缩成一个[zhbzhb-m1 ~]$echo$first_name$last_namefacai zhang# 用 {} 限定变量名边界避免和下划线粘连[zhbzhb-m1 ~]$echo${last_name}_$first_namezhang_facai# 查看变量[zhbzhb-m1 ~]$set|grepfirst_namefirst_namefacai# 取消变量定义[zhbzhb-m1 ~]$unsetfirst_name# 定义时转换大小写[zhbzhb-m1 ~]$declare-lnameJamesecho$namejames[zhbzhb-m1 ~]$declare-unameJamesecho$nameJAMES易错点不加{}时$last_name_$first_name里的last_name_会被整体当成变量名该变量不存在值为空结果只剩facai。拼接变量记得用${}。二、变量作用范围局部变量与全局变量局部变量只在当前 shell 中生效。全局变量在当前 shell 及其子 shell 中都生效。用法速查表命令作用说明变量名值定义局部变量只在当前 shell 生效export 变量名值定义全局变量子 shell 也可见变量名值; export 变量名两步导出先定义再导出效果同上export -n 变量名取消导出把已导出的变量降回局部env查看环境变量只显示已 export 的变量不含普通变量export -p列出所有导出变量查看当前导出了哪些变量declare -x 变量名值定义并导出变量顶层 shell 中等价于export见第三章函数内要加-g才等价# 定义局部变量[zhbzhb-m1 ~]$usernametom[zhbzhb-m1 ~]$echo$usernametom# 进入子 shell 后局部变量不生效[zhbzhb-m1 ~]$bash[zhbzhb-m1 ~]$echo$username# 用 export 提升为全局子 shell 也可见[zhbzhb-m1 ~]$exportusernametom# 或者分两步[zhbzhb-m1 ~]$usernametom;exportusername[zhbzhb-m1 ~]$bash[zhbzhb-m1 ~]$echo$usernametom核心区别只有export之后的变量才会被子 shell 继承。三、环境变量环境变量是 shell 内置的、用于设置运行环境的变量与用户自定义变量相对。常见的环境变量名作用EDITOR默认编辑器HISTFILE历史文件位置HISTFILESIZE历史命令个数HISTTIMEFORMAT历史命令时间格式PS1命令行提示符LANGshell 环境语言PATH命令搜索路径HOME当前用户家目录USER当前用户PWD当前 shell 路径完整的 shell 环境变量见bash(1)手册。env查看与临时调整环境变量env既能查看环境变量也能在不改动当前 shell 的前提下临时改。用法速查表命令作用说明env列出所有环境变量只显示已 export的不含普通变量env | grep 关键字过滤查看最常用如env | grep PATHprintenv 变量名查看单个变量的值等效echo $变量名env 变量值 命令临时设置变量后执行命令只对该命令生效不污染当前 shellenv -u 变量 命令临时取消某变量后执行命令用于临时屏蔽干扰变量env -i 命令以空环境执行命令清空所有环境变量排查环境依赖问题env -i PATH.. HOME.. 命令指定一个干净的最小环境模拟 cron / systemd 的运行环境# 列出所有环境变量[zhbzhb-m1 ~]$envLANGzh_CN.utf8USERzhbHOME/home/zhbPATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zhb/.local/bin:/home/zhb/bin...# 查看单个变量的值输出即上面那行 PATH[zhbzhb-m1 ~]$printenvPATH# 临时改变量执行命令用 C 排序规则不影响当前 shell[zhbzhb-m1 ~]$envLC_ALLCsortnames.txt[zhbzhb-m1 ~]$echo$LC_ALL# 当前 shell 中仍是原值未被改动# 临时屏蔽某个变量再执行[zhbzhb-m1 ~]$env-uhttp_proxycurlhttps://example.com# 以干净环境运行命令常用于复现 cron 里执行失败的脚本[zhbzhb-m1 ~]$env-iPATH/usr/bin:/binHOME/home/zhbbash-cecho $PATH/usr/bin:/binenv的三个层次查看env、printenv→ 临时改env VARval cmd→ 清空环境env -i。其中env -i是排查「命令行能跑、放进 crontab 就失败」的利器cron 给脚本的 PATH 常常只有/usr/bin:/bin用env -i在本机就能复现。set与env的区别一个看全部一个只看导出的命令显示范围含普通变量含函数能临时改环境跑命令set当前 shell 的全部变量✅✅❌它是 shell 内建用来设置 shell 选项env仅环境变量已 export 的❌❌✅env VARval cmdprintenv仅环境变量❌❌❌只能查看export -p仅已导出的变量带declare -x前缀❌❌❌declare -p全部变量并显示类型属性-x/-i/-r✅❌❌compgen -v只列变量名不含值✅❌❌实战同一变量在set/env里的可见性# 普通变量未导出[zhbzhb-m1 ~]$myvarhello# set 看得到[zhbzhb-m1 ~]$set|grepmyvarmyvarhello# env 看不到还不是环境变量[zhbzhb-m1 ~]$env|grepmyvar 无输出# export 后再查[zhbzhb-m1 ~]$exportmyvar[zhbzhb-m1 ~]$env|grepmyvarmyvarhello# declare -p 看属性导出后多了 -x[zhbzhb-m1 ~]$declare-pmyvardeclare-xmyvarhello一句话记忆set看全部env看导出的。要确认某个变量有没有 export 出去用env | grep 变量名或declare -p 变量名看属性里带不带-x。这也解答了另一个常见困惑为什么「命令行里echo $myvar有值写进脚本就没了」脚本是子 shell只有 export 过的变量才会被继承见第二章。declare -x与export顶层等价函数内要加-gdeclare -p输出开头的-x是「已导出」属性标记x export。顶层 shell 里declare -x就是export的另一种写法脚本和/etc/profile里随处可见看到就当export读写法顶层 shell等价写法作用declare -x VARexport VAR把已有变量标记为环境变量导出declare -x VAR值export VAR值定义并直接导出declare x VARexport -n VAR取消导出属性降回普通变量# declare -x 就是 export[zhbzhb-m1 ~]$declare-xFOObar[zhbzhb-m1 ~]$bash-cecho $FOO# 子 shell 能看到说明已导出bar[zhbzhb-m1 ~]$export-nFOO# 收回导出属性[zhbzhb-m1 ~]$declare-pFOOdeclare--FOObar# 前缀变成 declare --无 -x子 shell 不再可见⚠️ 关键坑函数里declare -x不等于exportdeclare/typeset/local在函数内部默认创建局部变量只在函数体内有效而export永远作用于当前作用域。所以函数里写declare -x VARVAR 只是函数局部变量外面看不到而export VAR会直接改全局 VAR。要让二者等价必须加-gglobal位置写法等价于全局效果说明函数内declare -x VAR—仅函数局部导出创建了局部变量外面看不到函数内declare -xg VARexport VAR加-g才作用于全局等价于export函数内export VARexport VARexport本身始终全局无需-g# 演示函数里 declare -x 默认是局部的[zhbzhb-m1 ~]$demo_local(){declare-xINNERlocal_val# 局部 导出echo函数内:$INNER}[zhbzhb-m1 ~]$ demo_local 函数内: local_val[zhbzhb-m1 ~]$echo函数外:$INNER# 空局部变量已随函数退出销毁函数外:# 演示函数里加 -g 才等价于 export[zhbzhb-m1 ~]$demo_global(){declare-xgGLOBAL_VALglobal_val# -g 作用于全局}[zhbzhb-m1 ~]$ demo_global[zhbzhb-m1 ~]$echo函数外:$GLOBAL_VAL# 有值等价于 export函数外: global_val[zhbzhb-m1 ~]$bash-cecho $GLOBAL_VAL# 子 shell 也能看到确认是环境变量global_val记忆点顶层 shell 里exportdeclare -x进了函数declare -x VAR是局部的declare -xg VAR才等于export。EDITOR指定默认编辑器# 默认用 vi 编辑 /etc/sudoers不显示语法高亮[rootzhb-m1 ~]# visudo# 指定 vim 后再次编辑就有语法高亮了[rootzhb-m1 ~]# export EDITOR/bin/vim[rootzhb-m1 ~]# visudoLANG设置 shell 语言# 默认是中文环境[rootzhb-m1 ~]# date2022年11月 07日 星期一13:38:31 CST# 切换为英文[rootzhb-m1 ~]# export LANGen_US.utf8[rootzhb-m1 ~]# dateMon Nov713:38:55 CST2022# 切回中文[rootzhb-m1 ~]# export LANGzh_CN.utf8[rootzhb-m1 ~]# date2022年11月 07日 星期一13:40:49 CST常见 LANG 代码英语en_US.utf8、简体中文zh_CN.utf8、繁体中文zh_TW.utf8。为什么有时不加export也生效LANG、PATH这类变量在登录时已被 export而「已导出」属性是打在变量上的后续重新赋值只改值、不丢属性所以对子进程依然有效。自己新建的普通变量想给子进程用就必须显式export。PATH命令搜索路径[rootzhb-m1 ~]# echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin# 演示把 ls 移出 PATH命令就找不到了[rootzhb-m1 ~]# mv /usr/bin/ls .[rootzhb-m1 ~]# lsbash: ls:commandnot found...# 将 /root 追加到 PATH重新找回 ls[rootzhb-m1 ~]# export PATH$PATH:/root[rootzhb-m1 ~]# which ls/root/ls# 还原现场[rootzhb-m1 ~]# mv ./ls /usr/bin查找顺序shell 按 PATH 中从左到右查找命中即停。想让自装程序优先于系统命令就把路径放前面export PATH/新路径:$PATH。避坑PATH 追加必须带上原值。PATH是冒号分隔的搜索路径写成PATH/root会清掉/usr/bin、/usr/sbinls、vim全部失效正确写法是PATH$PATH:/root。万一覆盖且当前 shell 还没关可写回默认值救回PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin。PS1定制命令行提示符[zhbzhb-m1 ~]$echo$PS1[\u\h\W]\$# man bash 中搜索 PROMPTING 可查看完整说明# 常用转义符# \h 主机名第一个 . 之前的部分# \H 完整主机名# \n 新行符# \t 当前时间24 小时制 HH:MM:SS# \T 当前时间12 小时制 HH:MM:SS# \ 当前时间12 小时制 am/pm# \A 当前时间24 小时制 am/pm# \u 当前用户的用户名# \w 当前工作目录完整路径 使用命令dirnamebasename即可查看# \W 当前工作目录的基本部分 basename查看# \$ 有效 UID 为 0 显示 #否则显示 $# 提示符变为 HELLO [zhbzhb-m1 ~]$PS1HELLO HELLOechohello world hello world# 提示符带时间[zhbzhb-m1 ~]$PS1[\u\h \W \t]\$ [zhbzhb-m1 ~13:52:08]$# 显示完整工作目录[zhbzhb-m1 ~13:52:08]$PS1[\u\h \w \t]\$ [zhbzhb-m1 ~13:52:56]$cd/usr/share/doc[zhbzhb-m1 /usr/share/doc13:53:04]$彩色提示符颜色代码格式\[\e[0;3Xm\]X取1红 /2绿 /3黄 /4蓝 /5紫 /6青 /7白\[\e[0m\]恢复默认首位3换成99X是对应的高亮/灰色系如90灰、92亮绿加1;是粗体如\[\e[92;1m\]。\e也可写成\033两者等价。# 示例1\e 写法用户名红色、 黄色、主机名加粗亮绿、目录亮蓝、时间紫色PS1[\[\e[91m\]\u\[\e[0m\]\[\e[93m\]\[\e[0m\]\[\e[92;1m\]\h\[\e[0m\]\[\e[94m\] \W\[\e[0m\] \[\e[35m\]\t\[\e[0m\]]\[\e[93m\]\$\[\e[0m\] # 示例2\033 写法用户名青色、 灰色、主机名加粗绿色、目录蓝色、时间灰色、$ 青色PS1[\[\033[36m\]\u\[\033[90m\]\[\033[32;1m\]\h\[\033[0m\] \[\033[34m\]\W\[\033[0m\] \[\033[90m\]\t\[\033[0m\]]\[\033[36m\]\$ \[\033[0m\] # 效果[zhbzhb-m1 ~ 14:20:30]$# 写入 /etc/bashrc 永久生效也可用 echo 追加注意 \\\$ 需要双重转义echoPS1...\\\$.../etc/bashrc注意\[和\]必须包住颜色代码告诉 bash 这部分不占显示宽度否则命令过长换行时会错位。HISTTIMEFORMAT历史命令时间格式设置该变量后history会显示每条历史命令的执行时间。# 显示年月日时分秒如 2024-10-24 15:30:45exportHISTTIMEFORMAT%F %T # 效果history 输出类似 1000 2024-10-24 15:30:45 ls -l# 显示更简洁的时间格式如 10-24 15:30exportHISTTIMEFORMAT%m-%d %H:%M 常用格式符%F完整日期2024-10-24、%T完整时间15:30:45、%m-%d月日、%H:%M时分与date命令的格式符一致man strftime查看全部。四、变量持久化保存变量只在当前会话有效要「开机 / 登录即生效」需写入配置文件。不同 shell 类型加载顺序不同login shell按顺序加载/etc/profile—— 对所有用户生效设置操作系统级别。~/.bash_profile—— 仅对特定用户生效。~/.bashrc—— 仅对特定用户生效。/etc/bashrc—— 对所有用户生效。non-login shell按顺序加载~/.bashrc—— 仅对特定用户生效例如/home/zhb/.bashrc。/etc/bashrc—— 对所有用户生效。# login shell 示例写入 /etc/profile重新登录后生效[rootzhb-m1 ~]# echo export LANGen_US.utf8 /etc/profile# 重新 ssh 登录后验证[zhbzhb-m1 ~]$sshzhb10.1.8.88[zhbzhb-m1 ~]$dateMon Nov714:20:42 CST2022# 已是英文格式说明已生效# non-login shell 示例写入 /etc/bashrc新开 bash 后生效[rootzhb-m1 ~]# echo export EDITORvim /etc/bashrc# 新开一个 bash 验证[zhbzhb-m1 ~]$bash[zhbzhb-m1 ~]$echo$EDITORvim速查想立刻在当前 shell 用上新配置而不用重新登录可source 配置文件或. 配置文件如source /etc/bashrc。五、命令替换把命令的执行结果替换到命令行中有两种写法$(COMMAND)推荐支持嵌套与COMMAND反引号旧式。用法速查表格式作用示例$(命令)命令替换推荐touch file-$(date %Y%m%d)命令命令替换反引号touch file-date %Y%m%d变量名$(命令)存命令结果today$(date %F)$(( 算术式 ))算术运算echo $(( 123 ))$[ 算术式 ]算术运算旧式echo $[ 123 ][zhbzhb-m1 ~]$echoToday is$(date%A)Today is Monday# 用日期给文件命名[zhbzhb-m1 ~]$touchfile-$(date%Y%m%d)# 或者[zhbzhb-m1 ~]$touchfile-date%Y%m%d[zhbzhb-m1 ~]$lsfile-20221107实战计算 12…99100# 生成序列并用 tr 把空格换成 再用算术展开求和[zhbzhb-m1 ~]$echo{1..100}|tr 123...100[zhbzhb-m1 ~]$echo$[$(echo{1..100}|tr )]5050六、保留字符的字面含义许多字符在 bash 中有特殊含义要忽略这些含义可用引号和转义字符用法速查表符号作用变量替换命令替换转义字符\取消单个字符特殊含义———双引号压缩 shell 扩展✅ 保留✅ 保留✅ 保留单引号压缩所有字符含义❌ 关闭❌ 关闭❌ 关闭# \ 示例\$ 让 $ 失去取值含义[zhbzhb-m1 ~]$echo$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zhb/.local/bin:/home/zhb/bin[zhbzhb-m1 ~]$echo\$PATH$PATH# 示例变量和命令替换会展开* 通配符不展开[zhbzhb-m1 ~]$usernameXieBaiQi[zhbzhb-m1 ~]$echoWelcome$username, today is$(date%F)Welcome XieBaiQi, today is2025-07-23# \ 和 组合\$ 转义后变量不展开但命令替换仍生效[zhbzhb-m1 ~]$echoWelcome \$username, today is$(date%F)Welcome$username, today is2025-07-23# 示例内部所有字符都失去特殊含义[zhbzhb-m1 ~]$echoWelcome $username, today is $(date %F)Welcome$username, today is$(date%F)记忆口诀双引号「半屏蔽」——变量和命令照常展开只挡住通配符和空格压缩单引号「全屏蔽」——里面写啥就是啥。 参考资料官方文档 · 中英双语英文原版man7.orgBash 参考手册bash 命令与变量/export/declare/source 全部内建命令的权威说明environ(7)环境变量通用说明中文版export 命令中文说明菜鸟教程env 命令中文说明菜鸟教程set 命令中文说明菜鸟教程本文梳理了 Shell 变量的完整体系定义与查看 → 作用域 → 环境变量 → 持久化 → 命令替换 → 引号转义。掌握后你就能自如管理变量的作用域与生命周期为后续 Shell 脚本编程打好地基。觉得有帮助欢迎点赞收藏也欢迎在评论区交流你的疑问。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价