简介
程序通常需要一些小型配置,例如主目录、语言、搜索路径或应用设置。Linux 进程通过环境接收其中许多值。环境是一组带名称的字符串。
本实验将分层构建这些概念。你将先创建一个只属于当前 Shell 的变量,然后将变量导出到子进程,查看标准变量,扩展 PATH,最后让设置出现在未来的 Zsh 会话中。每个步骤都会留下可观察的文件或命令结果,帮助你验证 Shell 实际执行了什么。
创建并展开 Shell 变量
在此步骤中,你将创建一个 Shell 变量,并观察引号如何影响变量展开。
Shell 变量会在当前 Shell 中将名称与值关联起来。赋值语法中的 = 两侧不能有空格。为值加引号可以保留其中的空格:
cd /home/labex/project/environment-lab
course_name="Linux for Noobs"
在名称前加上 $,Shell 就会将其展开为对应的值:
echo "$course_name"
双引号允许变量展开,并将展开结果保留为一个参数。单引号会按字面保留美元符号。对比下面两条命令:
printf 'double: %s\n' "$course_name"
printf 'single: %s\n' '$course_name'
将展开后的值保存为可观察的结果:
printf 'course=%s\n' "$course_name" > shell-variable.txt
cat shell-variable.txt
除非导出,否则这个变量只存在于当前 Shell 中。
观察子进程继承
在此步骤中,你将比较普通 Shell 变量和导出变量在子进程中的表现。
每条命令都在某个进程中运行。子进程会从父进程接收已导出的环境变量,但不会接收普通 Shell 变量。
返回工作区,并分别创建这两类变量:
cd /home/labex/project/environment-lab
local_message="visible only in this shell"
export SHARED_MESSAGE="visible in child processes"
创建一个小型 Bash 子进程,同时打印这两个名称。带引号的 heredoc 标记会阻止当前 Shell 在写入脚本时展开变量:
cat > inspect-child.sh <<'EOF'
#!/bin/bash
printf 'local=%s\n' "${local_message:-<missing>}"
printf 'shared=%s\n' "${SHARED_MESSAGE:-<missing>}"
EOF
chmod +x inspect-child.sh
运行该脚本,将输出重定向到文件,然后显示文件内容。将这两个动作分成单独的命令,可以清楚地区分哪个动作运行子进程,哪个动作查看保存的结果:
./inspect-child.sh > child-environment.txt
cat child-environment.txt
普通变量应显示为 <missing>,而 SHARED_MESSAGE 会被继承。确认导出的名称存在于环境中:
env | grep '^SHARED_MESSAGE='
查看标准环境变量
在此步骤中,你将查看用于描述账户、工作目录、终端和命令搜索路径的标准变量。
Linux Shell 通常会提供以下有用的标准变量:
HOME表示你的主目录。USER表示你的账户名称。SHELL表示已配置的登录 Shell。PWD跟踪当前工作目录。PATH列出命令搜索目录,各目录之间用冒号分隔。TERM向交互式程序描述终端功能。
使用 printenv 按名称显示选定的值。该命令读取已导出的变量:
printenv HOME USER SHELL PWD TERM
将 PATH 按每行一个条目显示更容易阅读。通过 tr 传递该值,将每个冒号替换为换行符:
printf '%s\n' "$PATH" | tr ':' '\n'
根据本实验中预期值已知的变量创建一份稳定的报告:
cd /home/labex/project/environment-lab
printf 'HOME=%s\nUSER=%s\n' "$HOME" "$USER" > standard-environment.txt
cat standard-environment.txt
使用个人命令扩展 PATH
在此步骤中,你将把个人可执行文件目录添加到 PATH,然后从另一个目录按名称运行命令。
当你输入的命令不包含斜杠时,Shell 会按照从左到右的顺序搜索 PATH 中的目录。你可以添加个人可执行文件目录,而不替换现有的搜索路径。
创建名为 course-status 的命令:
mkdir -p "$HOME/bin"
cat > "$HOME/bin/course-status" <<'EOF'
#!/bin/bash
echo "Linux learning environment is ready"
EOF
chmod +x "$HOME/bin/course-status"
将该目录追加到当前 PATH。保留 $PATH 可以继续访问标准命令:
export PATH="$PATH:$HOME/bin"
让 Shell 告诉你将执行哪个文件,然后从另一个目录运行该命令:
command -v course-status
cd /tmp
course-status
将命令输出保存到实验工作区:
course-status > /home/labex/project/environment-lab/path-command.txt
为未来的 Zsh 会话持久化设置
在此步骤中,你将配置未来的 Zsh 会话,并区分持久化配置与当前 Shell 状态。
导出变量会修改当前进程及其未来的子进程,但不会编辑配置文件。只有当启动文件重新创建某个设置时,该设置才会出现在后续终端中。LabEx Terminal 使用 Zsh,其交互式启动文件是 ~/.zshrc。
追加一个带有清晰标记的代码块。每条 export 命令都会在新的交互式 Zsh 启动时重新创建一个环境设置。这个面向初学者的版本特意保持启动文件直接明了:保留现有的 PATH,然后在末尾添加个人目录。
cat >> "$HOME/.zshrc" <<'EOF'
## LABEX_ENV_LAB_START
export PROJECT_DIR="$HOME/project"
export PATH="$PATH:$HOME/bin"
## LABEX_ENV_LAB_END
EOF
source 命令会在当前 Shell 中读取文件。现在重新加载 .zshrc,这样无需关闭 Terminal 就能使用其中的设置:
source "$HOME/.zshrc"
确认重新加载的变量可用:
printf 'PROJECT_DIR=%s\n' "$PROJECT_DIR"
你应该看到 PROJECT_DIR=/home/labex/project。你还可以启动一个新的 Zsh 进程,证明未来的会话会加载相同的设置。在 zsh -ic 中,-i 请求启动交互式 Shell,以便读取 .zshrc;-c 提供该 Shell 要执行的命令。将它输出的两行重定向到 future-shell.txt,然后查看文件:
zsh -ic 'printf "PROJECT_DIR=%s\n" "$PROJECT_DIR"; command -v course-status' > /home/labex/project/environment-lab/future-shell.txt
cat /home/labex/project/environment-lab/future-shell.txt
第一行应显示 /home/labex/project;第二行应显示 /home/labex/bin/course-status。
最后,了解当前状态与持久化配置之间的区别。创建并删除一个临时环境变量:
export TEMP_NOTE="remove me"
printenv TEMP_NOTE
unset TEMP_NOTE
printenv TEMP_NOTE
最后一条 printenv 不会产生输出,并会返回非零状态,因为该名称已经不存在。unset 会从当前 Shell 中删除该名称。如果某个名称仍在启动文件中定义,未来的 Shell 仍会重新创建它,直到删除对应的配置行。
总结
你观察了三个经常被混淆的机制:Shell 变量属于单个 Shell,export 会将值传递给子进程,而启动文件会在未来的 Shell 中重新创建设置。你还查看了标准环境变量,在不丢失现有条目的情况下扩展了 PATH,验证了命令查找,并使用 unset 删除了临时状态。



