当前位置:首页>Linux>Linux 从0到1 : 08 Shell 变量与环境

Linux 从0到1 : 08 Shell 变量与环境

  • 2026-10-11 06:05:14
Linux 从0到1 : 08 Shell 变量与环境
     欢迎来到罐子的实验室
    今天来学习Shell 变量与环境  

    本次目标

    学会用变量存储和复用值,让命令「记住」东西;理解什么是环境变量,怎么把变量传给子进程。

学完你能做什么:

  • 读取、设置、引用 Shell 变量
  • 理解 $ 触发的「变量展开」
  • 用引号处理含空格的值
  • 用 export 把变量变成环境变量
  • 用 $() 把命令输出存进变量
  • 用 read 从输入或文件读值

1. 为什么需要变量

你写过 cd ~/Documents/work/2024/q1/reports 这种长路径吗?每次都打一遍很烦。如果给这串路径起个名字 REPORTS,以后只要 cd $REPORTS 就行——这就是变量。

变量 = 给某个值起个名字,方便复用、修改。Shell 本身就是个迷你编程语言,变量是它的基础。


2. 读取变量:$

Shell 里有些预定义变量,比如 PWD 始终存着当前目录:

user@host:~$ echo $PWD/home/user

注意那个 $:变量名字是 PWD,要读取它的值就在前面加 $。这个「加 $ 取值」的动作叫变量展开(expansion)。

动手练习 1:看看常见变量

任务:打印这几个预定义变量的值:$USER(用户名)、$HOME(家目录)、$SHELL(当前 Shell)。

思路引导:echo $变量名。

参考答案:

user@host:~$ echo $USERuseruser@host:~$ echo $HOME/home/useruser@host:~$ echo $SHELL/bin/bash

常见错误:写 echo USER(少了 $)——打印的是字面的 "USER" 而不是用户名。


3. 设置变量:=

自己创建变量用等号赋值:

user@host:~$ GREETING=”hello world”user@host:~$ echo $GREETINGhello world

三条铁律

  1. 等号两边不能有空格
    !VAR=1 对,VAR = 1 错(Shell 会以为你要运行一个叫 VAR 的命令)。
  2. 赋值时不加 $
    ,只有读取时才加:VAR=1 而非 $VAR=1。
  3. 值含空格要用引号
    :VAR="hello world"。
user@host:~$ NAME=Aliceuser@host:~$ echo $NAMEAliceuser@host:~$ NAME = Alice# ❌ 等号有空格NAME: command not found# Shell 把 NAME 当成命令了

动手练习 2:设个常用路径

任务:把变量 WORK 设成你的工作目录路径(如 ~/linux-practice),然后用 cd $WORK 切过去。

参考答案:

user@host:~$ WORK=~/linux-practiceuser@host:~$ cd $WORKuser@host:~/linux-practice$ pwd/home/user/linux-practice

常见错误:

  • ❌ WORK = ~/...(等号空格)→ 报错。
  • ❌ $WORK=~/...(赋值加 $)→ 语法错误。

4. 引号:单引号 vs 双引号

值里有空格必须加引号。但单引号和双引号不一样:

引号
行为
"双引号"
里面的 $变量、`命令`、\ 会展开/转义
'单引号'
里面一切按字面,啥都不展开
user@host:~$ NAME=Aliceuser@host:~$ echo ”Hello $NAME”# 双引号:$NAME 被替换Hello Aliceuser@host:~$ echo 'Hello $NAME'# 单引号:原样输出Hello $NAME

经验法则:

  • 想让变量展开 → 用双引号。
  • 想让内容完全照搬(如正则、含 $ 的字面文本)→ 用单引号。
  • 任何时候,变量引用都建议加双引号
    :"$VAR",防止值含空格时被拆词。

动手练习 3:体会引号

任务:

  1. NAME=Alice
    ,分别用双引号和单引号打印 I am $NAME,对比结果。

参考答案:

user@host:~$ NAME=Aliceuser@host:~$ echo ”I am $NAME”I am Aliceuser@host:~$ echo 'I am $NAME'I am $NAME

常见错误:echo $NAME is here 看似没事,但若 NAME="Alice Bob",Shell 会把 Alice 和 Bob 当两个词处理(词拆分)。安全写法:echo "$NAME is here"。


5. export:变成环境变量

你设的变量默认只在当前 Shell 进程里可见,启动的子进程继承不到:

user@host:~$ VAR=hellouser@host:~$ echo $VARhellouser@host:~$ bash# 启动一个子 Shelluser@host:~$ echo $VAR# 子 Shell 里看不到user@host:~$ exit# 退回原 Shelluser@host:~$ echo $VARhello

要让子进程也看到,必须 export(导出):

user@host:~$ VAR=hellouser@host:~$ export VAR# 或一步到位:export VAR=hellouser@host:~$ bashuser@host:~$ echo $VARhello# 子进程拿到了!

被导出的变量叫环境变量,它们构成了进程的「环境」。很多程序靠读环境变量来配置自己,比如:

  • PATH
     —— Shell 找命令的目录列表(→ 详见《模块 13》)
  • HOME
     —— 家目录
  • LANG
     —— 语言/编码
  • EDITOR
     —— 默认编辑器

查看所有环境变量

user@host:~$ env# 列出所有已导出的环境变量user@host:~$ printenv PATH# 查看单个变量(不展开,更可靠)

动手练习 4:导出并验证

任务:

  1. 设 MY_VAR=secret。
  2. 不导出
    ,启动 bash,确认子 Shell 里 $MY_VAR 为空。
  3. 退回,export MY_VAR,再进 bash 验证能看到。

参考答案:

user@host:~$ MY_VAR=secretuser@host:~$ bash -c 'echo ”[$MY_VAR]”'# 子进程里[]user@host:~$ export MY_VARuser@host:~$ bash -c 'echo ”[$MY_VAR]”'[secret]

(用 bash -c '命令' 在子进程跑一条命令,省得手动进/退子 Shell。)


6. 命令替换:$()

把命令的输出赋给变量,用 $(命令):

user@host:~$ TODAY=$(date +%Y-%m-%d)user@host:~$ echo $TODAY2024-06-30user@host:~$ FILES=$(ls /etc | wc -l)user@host:~$ echo ”etc 下有 $FILES 项”etc 下有 243 项

$(...) 会先运行里面的命令,把输出塞回到当前位置。

💡 老式写法是反引号 `命令`,比如 TODAY=`date`。但反引号不能嵌套、转义麻烦,现代一律推荐 $()。

动手练习 5:备份文件名带日期

任务:把 todo.txt 复制成 todo-YYYYMMDD.txt(带今天日期)。

思路引导:先用 $(date +%Y%m%d) 拿到日期串,再拼进文件名。

参考答案:

user@host:~$ cp todo.txt ”todo-$(date +%Y%m%d).txt”user@host:~$ ls todo*todo-20240630.txt todo.txt

常见错误:cp todo.txt todo-$(date).txt——date 不带格式参数会输出带空格的串(Sun Jun 30 ...),文件名里有空格是大麻烦。加 +%Y%m%d 指定格式。


7. read:从输入读值

read 把一行输入读进变量。配合 -p 还能显示提示:

user@host:~$ read -p ”请输入你的名字: ” NAME请输入你的名字: Alice# 这行是你输入的user@host:~$ echo ”你好, $NAME”你好, Alice

read 默认从 stdin 读,所以可以配合输入重定向读文件:

user@host:~$ echo ”first line” > data.txtuser@host:~$ read LINE < data.txtuser@host:~$ echo ”$LINE”first line

注意 read 只读一行,要逐行处理整个文件得用循环(→ 详见《模块 11》)。

💡 read 是 Shell 内建命令(不是外部程序),所以它不受 PATH 影响——这点在《模块 13》和《模块 14》很有用。

动手练习 6:交互式输入

任务:写一行命令,提示用户输入年龄,然后输出「你 X 岁了」。

参考答案:

user@host:~$ read -p ”年龄: ” AGE && echo ”你 $AGE 岁了”年龄: 25你 25 岁了

(&& 表示前一条成功才执行后一条,详见《模块 11》。)

常见错误:read NAME 不加提示,用户不知道在等输入——养成用 -p 的习惯。


8. 特殊变量速览

Shell 有些「自带」的特殊变量,名字是符号:

变量
含义
$?
上一条命令的退出码(0=成功,非0=失败,→ 详见《模块 09》)
$$
当前 Shell 的 PID
$!
最近一个后台进程的 PID
$0
脚本/Shell 的名字
$1
–$9
脚本的位置参数(→ 详见《模块 11》)
$#
位置参数的个数
$@
所有位置参数
user@host:~$ ls /不存在ls: cannot access '/不存在': No such file or directoryuser@host:~$ echo $?2# 失败,退出码非 0user@host:~$ echo hellohellouser@host:~$ echo $?0# 成功

本模块速查表

操作
语法
读取变量
echo $VAR
 或 echo "$VAR"
设置变量
VAR=value
(等号无空格)
设含空格的值
VAR="a b c"
导出为环境变量
export VAR
 或 export VAR=val
命令输出赋值
VAR=$(命令)
查看所有环境变量
env
 / printenv
交互读取输入
read -p "提示" VAR
从文件读一行
read VAR < 文件

引号对比

引号
$VAR
 会展开吗
用途
"双引号"
✅ 会
大多数情况,安全
'单引号'
❌ 不会
字面文本、正则
无引号
✅ 会
简单无空格值,不推荐

特殊变量

变量
含义
$?
上条命令退出码
$$
当前 PID
$1 $2 ...
脚本参数

下一步

变量让命令能「记」值了。但每条命令都是一次性的——你想让命令长期运行、随时控制、按需停止,这就涉及进程管理。

最新文章

随机文章