Linux: 环境变量与 PATH——配置开发环境
环境变量是操作系统用来存储配置信息的键值对。它们决定了 Shell 去哪找命令(PATH)、用什么语言(LANG)、编辑器是什么(EDITOR)。
📋 前置知识:需要先掌握以下内容
- 第9课:用户与组管理
1. 你将学到
- 环境变量的作用
- PATH 的工作原理
- export 和 unset 操作
- Shell 配置文件的加载顺序
- 添加新工具到 PATH
2. 一个 "command not found" 的故事
(1) 痛点:明明装了程序却找不到
小明用 pip install --user 安装了 Python 工具 httpie,但输入 http 时提示:
http example.com
# Command 'http' not found
小明很困惑:"我明明装好了,为什么系统说没找到?"
(2) PATH —— 告诉 Shell 去哪找程序
Bob 解释:"程序已经装好了,但 Shell 不知道去哪找它。PATH 环境变量就是 Shell 的'寻宝地图'。"
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# ~/.local/bin 不在 PATH 中,所以 Shell 找不到 http
ls ~/.local/bin/http*
# /home/charlie/.local/bin/http
# 将 ~/.local/bin 加入 PATH
export PATH="$PATH:$HOME/.local/bin"
http example.com # 这次能用了
(3) 收益:理解了一切背后的机制
小明知道了 export PATH="$PATH:~/bin" 放在 .bashrc 中就能永久生效。后来他每次安装新工具,都知道去检查 PATH 是否包含了安装目录。
3. 知识点讲解
(1) 什么是环境变量
环境变量是存储在操作系统中的键值对,所有子进程都会继承它们。
# 查看所有环境变量
printenv
# 查看单个变量
echo $HOME
echo $USER
echo $SHELL
echo $LANG
echo $PWD
常见环境变量:
| 变量 | 含义 | 典型值 |
|---|---|---|
HOME |
当前用户的家目录 | /home/alice |
USER |
当前用户名 | alice |
SHELL |
当前 Shell 路径 | /bin/bash |
PATH |
命令搜索路径 | /usr/bin:/bin:/usr/local/bin |
LANG |
语言和编码 | zh_CN.UTF-8 |
PWD |
当前工作目录 | /home/alice/projects |
OLDPWD |
上一个工作目录 | /etc |
EDITOR |
默认编辑器 | vim |
(2) PATH——命令搜索路径
当你输入 ls 时,Shell 会依次在 PATH 列出的每个目录中查找 ls 程序。找到就执行,找不到就报 command not found。
# 查看当前 PATH
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 查看某个命令在哪个目录
which ls
# /usr/bin/ls
# 查看命令的所有可能位置(包括别名、函数)
type ls
# ls is aliased to `ls --color=auto'
(3) 设置和取消环境变量
# 临时设置(仅在当前 Shell 生效)
MY_VAR="hello"
# 导出为环境变量(子进程也能访问)
export MY_VAR="hello"
# 一条命令完成设置和导出
export MY_VAR="hello"
# 取消环境变量
unset MY_VAR
# 在一行命令中临时设置(不污染当前环境)
LANG=ja_JP.UTF-8 date
(4) Shell 配置文件加载顺序
理解配置文件加载顺序很重要——知道为什么有时修改 ~/.bashrc 没有效果:
登录 Shell(SSH 登录、tty 登录):
/etc/profile
~/.bash_profile (如果存在,跳过下面两个)
~/.bash_login
~/.profile
非登录 Shell(打开新的终端):
/etc/bash.bashrc
~/.bashrc
ℹ️ 说明:
.bashrc和.profile的加载时机不同——SSH 登录时加载.profile,打开新终端窗口时加载.bashrc。最佳实践是在.profile中加source ~/.bashrc,然后所有配置都写在.bashrc中,这样无论哪种方式登录都能生效。
最佳实践: 在 .bash_profile 中添加:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
然后所有自定义配置都写在 .bashrc 中。
▶ 示例:查看和设置环境变量
# 查看环境变量
echo "我的家目录是: $HOME"
echo "当前用户: $USER"
echo "我的 Shell: $SHELL"
# 设置临时变量
export GREETING="Hello from Linux"
echo $GREETING
# 新开一个终端窗口看看 $GREETING 还在吗?
# 答案:不在——因为临时变量只在当前 Shell 有效
输出:
TEXT 📖 仅展示我的家目录是: /home/alice 当前用户: alice 我的 Shell: /bin/bash Hello from Linux
▶ 示例:理解 PATH
# 查看当前 PATH
echo $PATH | tr ':' '\n' # 每行显示一个路径
# 查看 ls 命令从哪个目录加载
which ls
# /usr/bin/ls
# 如果 PATH 错了会怎样?
PATH="" # 清空 PATH(危险!)
ls
# bash: ls: No such file or directory
# 恢复 PATH
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
输出:
TEXT 📖 仅展示/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/bin/ls
▶ 示例:将 ~/scripts 加入 PATH(永久)
# 创建自己的脚本目录
mkdir -p ~/scripts
# 将 ~/scripts 加入 PATH(写入 .bashrc)
echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
> 💡 **提示**:想让环境变量永久生效,必须将 `export` 命令写入 `~/.bashrc`(或 `~/.profile`)。修改后执行 `source ~/.bashrc` 立即生效,否则只在新打开的终端中才会加载新配置。
# 重新加载
source ~/.bashrc
# 验证
echo $PATH | tr ':' '\n' | grep scripts
# /home/alice/scripts
输出:
TEXT 📖 仅展示/home/alice/scripts
▶ 示例:常用开发环境变量配置
# 在 ~/.bashrc 中添加以下内容
# 默认编辑器
export EDITOR=vim
# 语言环境
export LANG=zh_CN.UTF-8
# Python 开发
export PYTHONSTARTUP=~/.pythonrc # Python 交互式启动脚本
export PIP_REQUIRE_VIRTUALENV=true # pip 要求虚拟环境
# Node.js 开发
export NODE_ENV=development
export npm_config_prefix=~/.npm-global
# Go 开发
export GOPATH=$HOME/go
export PATH="$PATH:$GOPATH/bin"
# 自己的脚本
export PATH="$PATH:$HOME/scripts"
export PATH="$PATH:$HOME/.local/bin"
输出:
TEXT 📖 仅展示EDITOR=vim LANG=zh_CN.UTF-8 PYTHONSTARTUP=/home/alice/.pythonrc PIP_REQUIRE_VIRTUALENV=true NODE_ENV=development GOPATH=/home/alice/go
▶ 示例:检查命令是否可以找到
# 用 which 查看命令路径
which python3
# /usr/bin/python3
# 用 type 查看命令类型(别名/函数/内建/外部命令)
type ls
# ls 是 `ls --color=auto' 的别名
type cd
# cd 是 shell 内建
type node
# node 是 /usr/bin/node
# 用 command -v(最可靠的方式)
command -v python3
# /usr/bin/python3
输出:
TEXT 📖 仅展示/usr/bin/python3 ls 是 `ls --color=auto' 的别名 cd 是 shell 内建 node 是 /usr/bin/node /usr/bin/python3
▶ 综合示例:排查 "command not found" 问题
#!/bin/bash
# debug-path.sh - 排查命令找不到的问题
CMD="${1:-http}"
echo "=== 1. 命令是什么 ==="
type "$CMD" 2>/dev/null || echo "type: 未找到 $CMD"
echo ""
echo "=== 2. 哪些 PATH 目录包含这个命令 ==="|
IFS=':' read -ra PATHS <<< "$PATH"
for dir in "${PATHS[@]}"; do
if [ -f "$dir/$CMD" ]; then
echo "找到: $dir/$CMD"
fi
done
echo ""
echo "=== 3. 用 find 全局搜索 ==="
find /usr /opt $HOME -name "$CMD" -type f 2>/dev/null | head -5
echo ""
echo "=== 4. 如果找到但没在 PATH 中 ==="
echo "执行: export PATH=\"\$PATH:/找到的目录\""
❓ 常见问题
Q: PATH 的顺序重要吗? A: 非常重要!Shell 按顺序搜索 PATH 中的目录,找到第一个匹配就停止。如果
/usr/local/bin在前,它会优先于/usr/bin。这就是为什么新安装的程序有时还是运行了旧版本——检查 PATH 顺序。
Q: 环境变量重启后会消失吗? A: 临时用
export设置的会在重启后消失。要想持久化,必须将export命令写入 Shell 配置文件(~/.bashrc或~/.bash_profile)。
Q:
.bashrc和.bash_profile哪个先执行? A: 登录 Shell:/etc/profile→~/.bash_profile→~/.bash_login→~/.profile(如果前序文件不存在)。非登录 Shell:/etc/bash.bashrc→~/.bashrc。
Q: 怎么设置全局环境变量(所有用户生效)? A: 写入
/etc/environment(简单键值对,不支持脚本)或/etc/profile.d/custom.sh(支持 Shell 语法,需要 root 权限)。
Q:
printenv和set有什么区别? A:printenv只显示环境变量(export 的变量)。set显示所有变量,包括 Shell 局部变量和函数。想看完整的环境用printenv,想调试脚本用set。
📖 小节
- 环境变量是操作系统级键值对,子进程继承父进程环境变量
export VAR=value设置并导出,unset VAR取消- PATH 定义命令搜索路径,顺序决定了优先使用哪个版本
which cmd/type cmd查看命令位置- 配置写入
~/.bashrc(非登录 Shell)或~/.profile(登录 Shell) - 修改配置文件后执行
source ~/.bashrc立即生效
📝 作业
- 基础题(难度⭐):查看当前 PATH(用
tr ':' '\n'分行显示更清晰),并用which python3和type cd理解命令类型 - 进阶题(难度⭐⭐):创建一个
~/scripts目录,写一个简单的hello.sh脚本,将其加入 PATH 并直接运行;在.bashrc中设置EDITOR=vim(或nano)并source验证 - 挑战题(难度⭐⭐⭐):写一个
debug-path.sh脚本,接收一个命令名参数,自动排查该命令是否在 PATH 中、哪个目录包含它、如果不在 PATH 中则给出修复建议