Linux(CentOS)系统管理入门笔记(第六期)——Shell 交互核心:重定向、管道、变量与环境配置
Linux系统管理入门系列其他文章欢迎访问:Linux入门——系统管理1
我的主页:AOwhisky,这里有更多运维系统性知识整理和其他有趣内容,欢迎与我一起探讨学习~
引言:让命令行“流动”起来——输入、输出与变量
前五期我们学会了在 Linux 文件系统中“行走”、操作文件、查阅文档和编辑文本。但你有没有注意到一个现象:每次执行命令,结果都直接“喷”到屏幕上。如果我想把结果保存下来呢?如果我只想看成功的输出、忽略错误信息呢?如果我想把命令 A 的输出直接喂给命令 B 处理呢?
这就是本期要解决的三个核心问题——重定向(Redirection) 控制数据流向,管道(Pipe) 让命令串联协作,变量(Variable) 让命令行变得更智能、更可复用。
想象一下:你是一家快递分拣中心的调度员。包裹(数据)从各个入口涌进来。你可以决定:
- 把某些包裹送去仓库 A(
>输出到文件) - 把某些包裹直接扔进碎纸机(
2>/dev/null丢弃错误) - 把包裹从传送带 A 直接搬到传送带 B(
|管道传递) - 甚至给每个包裹贴上一个标签(变量存储),方便后续识别和处理
本期我们将系统学习:
- 标准输出与错误输出重定向(
>、>>、2>、&>) - 管道
|与tee命令——一边输出一边保存 - 标准输入重定向(
<和<<) - Shell 变量的定义、引用、作用域
- 环境变量(
PATH、PS1、LANG、EDITOR)的配置与持久化 - 命令替换(
$()和反引号)与引号/转义的精确控制
读完这一期,你将真正理解 Shell 的“数据流哲学”——让命令不再是孤立的工具,而是一个可组合、可编程的工作流系统。
目录
- 标准输出重定向:
>与>> - 标准错误重定向:
2>与合并重定向 - 管道
|:命令协作的“传送带” - tee:分流输出到文件与屏幕
- 标准输入重定向:
<与<< - Shell 变量:定义、引用与作用域
- 环境变量:系统的“全局配置”
- 命令替换与引号控制
- 总结与速查手册
1. 标准输出重定向:> 与 >>
1.1 三个标准数据流
Linux 中每个进程启动时,系统会自动为其打开三个数据通道:
| 通道 | 文件描述符 | 默认去向 | 用途 |
|---|---|---|---|
| 标准输入(stdin) | 0 | 键盘 | 程序读取输入数据 |
| 标准输出(stdout) | 1 | 屏幕 | 程序输出正常结果 |
| 标准错误(stderr) | 2 | 屏幕 | 程序输出错误信息 |
重定向的本质:将某个数据流从默认位置(屏幕/键盘)改道到文件或其他地方。
1.2 > —— 覆盖写入
# 查找 /etc 下所有名为 passwd 的文件
[whisky@centos7 ~]$ find /etc -name 'passwd'
find: ‘/etc/pki/CA/private’: 权限不够
find: ‘/etc/pki/rsyslog’: 权限不够
/etc/pam.d/passwd
/etc/passwd
find: ‘/etc/dhcp’: 权限不够
...
# 将标准输出(正确结果)重定向到文件
[whisky@centos7 ~]$ find /etc -name 'passwd' > passwd.list
find: ‘/etc/pki/CA/private’: 权限不够 # 错误信息仍显示在屏幕
...
[whisky@centos7 ~]$ cat passwd.list
/etc/pam.d/passwd
/etc/passwd
基本用法
# 1> 可简写为 >
# 注意:1 和 > 之间不能有空格
[whisky@centos7 ~]$ find /etc -name 'passwd' 1> passwd.list # 等价于 > passwd.list
# 将多个文件内容合并为一个文件
[whisky@centos7 ~]$ cat /etc/fstab /etc/hosts > allinone
[whisky@centos7 ~]$ cat allinone
# 包含 fstab 和 hosts 的全部内容
1.3 >> —— 追加写入
> 会覆盖目标文件,>> 则追加到文件末尾:
[whisky@centos7 ~]$ echo "第一次写入" > test.log
[whisky@centos7 ~]$ cat test.log
第一次写入
[whisky@centos7 ~]$ echo "第二次写入" >> test.log
[whisky@centos7 ~]$ cat test.log
第一次写入
第二次写入
# 再次执行 > 会覆盖原有内容
[whisky@centos7 ~]$ echo "覆盖写入" > test.log
[whisky@centos7 ~]$ cat test.log
覆盖写入
1.4 创建空文件或清空文件
# 用 > 创建空文件(文件不存在则创建,存在则清空)
[whisky@centos7 ~]$ > empty.log
[whisky@centos7 ~]$ ls -l empty.log
-rw-rw-r--. 1 whisky whisky 0 7月 13 15:30 empty.log
# >> 也可以创建空文件(但不如 > 直观)
[whisky@centos7 ~]$ >> empty2.log
💡 最佳实践:用
> /path/to/file清空日志文件比rm后重建更安全——文件权限和所有者保持不变。
2. 标准错误重定向:2> 与合并重定向
2.1 2> —— 重定向错误信息
上面的 find 示例中,权限错误信息依然显示在屏幕上。用 2> 可以将错误单独存放:
# 将错误信息写入 err.log,标准输出仍显示在屏幕
[whisky@centos7 ~]$ find /etc -name 'passwd' 2> passwd.err
/etc/pam.d/passwd
/etc/passwd
[whisky@centos7 ~]$ cat passwd.err
find: ‘/etc/pki/CA/private’: 权限不够
find: ‘/etc/pki/rsyslog’: 权限不够
find: ‘/etc/grub.d’: 权限不够
...
2.2 输出与错误分开存放
# 标准输出 → passwd.list,标准错误 → passwd.err
[whisky@centos7 ~]$ find /etc -name 'passwd' > passwd.list 2> passwd.err
[whisky@centos7 ~]$ cat passwd.list
/etc/pam.d/passwd
/etc/passwd
[whisky@centos7 ~]$ cat passwd.err
find: ‘/etc/pki/CA/private’: 权限不够
find: ‘/etc/pki/rsyslog’: 权限不够
...
2.3 丢弃错误信息:2>/dev/null
/dev/null 是 Linux 的“黑洞”——任何写入它的数据都会被丢弃。这在生产环境中非常实用:
# 只显示正确结果,隐藏所有错误
[whisky@centos7 ~]$ find /etc -name 'passwd' 2>/dev/null
/etc/pam.d/passwd
/etc/passwd
# 什么也不显示(正确结果和错误都丢弃)
[whisky@centos7 ~]$ find /etc -name 'passwd' >/dev/null 2>&1
# 无输出(稍后解释 2>&1)
⚠️ 常见误区:
2>/dev/null不是“没有错误”,而是“错误被扔掉了”。调试时慎用,建议先用2> err.log查看错误内容,确定无影响再丢弃。
2.4 合并重定向:&> 与 2>&1
将标准输出和标准错误合并到同一个文件:
# 方法一:&>(简洁写法,推荐)
[whisky@centos7 ~]$ find /etc -name 'passwd' &> passwd.all
[whisky@centos7 ~]$ cat passwd.all
/etc/pam.d/passwd
/etc/passwd
find: ‘/etc/pki/CA/private’: 权限不够
...
# 方法二:2>&1(经典写法,兼容性更好)
[whisky@centos7 ~]$ find /etc -name 'passwd' > passwd.all 2>&1
# 效果同上
# 追加模式
[whisky@centos7 ~]$ find /etc -name 'passwd' &>> passwd.all
# 或
[whisky@centos7 ~]$ find /etc -name 'passwd' >> passwd.all 2>&1
💡 理解
2>&1:2>&1的意思是“将文件描述符 2(标准错误)重定向到文件描述符 1(标准输出)当前指向的位置”。必须先有>或>>确定了标准输出的去向,2>&1才能跟随。
2.5 重定向操作符速查表
| 操作符 | 含义 | 示例 |
|---|---|---|
> 或 1> | 覆盖标准输出到文件 | ls > list.txt |
>> 或 1>> | 追加标准输出到文件 | ls >> list.txt |
2> | 覆盖标准错误到文件 | cmd 2> err.log |
2>> | 追加标准错误到文件 | cmd 2>> err.log |
&> | 合并输出和错误(覆盖) | cmd &> all.log |
&>> | 合并输出和错误(追加) | cmd &>> all.log |
2>&1 | 将错误重定向到输出的去向 | cmd > out 2>&1 |
>/dev/null 2>&1 | 丢弃所有输出 | 后台静默运行 |
3. 管道 |:命令协作的“传送带”
3.1 管道的基本概念
管道符 | 的作用是:将前一个命令的标准输出,作为后一个命令的标准输入。
cmd1 | cmd2 | cmd3
数据流向:cmd1 的屏幕输出 → cmd2 的键盘输入 → cmd2 的输出 → cmd3 的输入
3.2 基础示例
# 查找 ext4 相关的 man 手册,然后筛选出包含 "resizer" 的行
[whisky@centos7 ~]$ man -k ext4 | grep resizer
resize2fs (8) - ext2/ext3/ext4 file system resizer
# 查看系统进程,筛选出 bash 相关
[whisky@centos7 ~]$ ps -ef | grep bash
whisky 2843 2840 0 10:16 pts/1 00:00:00 -bash
whisky 3356 3348 0 10:36 tty2 00:00:00 /bin/bash
root 4820 2816 0 11:23 pts/0 00:00:00 grep --color=auto bash
# 统计 /etc 目录下有多少个文件
[whisky@centos7 ~]$ ls /etc | wc -l
256
# 找出当前目录下最大的 5 个文件
[whisky@centos7 ~]$ ls -lS | head -5
3.3 管道与重定向的组合
# 将搜索到的 ext4 手册保存到文件,同时筛选
[whisky@centos7 ~]$ man -k ext4 > ext4.man
[whisky@centos7 ~]$ grep resizer ext4.man
# 等价写法(管道 + 重定向)
[whisky@centos7 ~]$ man -k ext4 | grep resizer > result.txt
3.4 ⚠️ 管道的常见误区
并非所有命令都能接收管道输入。 管道传递的是标准输入(stdin),但有些命令(如 ls、rm、cp)不读取标准输入,它们从命令行参数获取目标。
# ❌ 错误:ls 不读取 stdin,管道数据被忽略
[whisky@centos7 ~]$ echo /etc | ls -l
# 等价于 ls -l,显示当前目录内容
# ✅ 正确:xargs 将 stdin 转换为命令行参数
[whisky@centos7 ~]$ echo /etc | xargs ls -l
# 显示 /etc 目录的内容
# 常用组合:find + xargs 处理大量文件
[whisky@centos7 ~]$ find . -name "*.log" | xargs rm -f
3.5 |&:同时传递错误和输出
|& 是将标准错误也一并传递给下一个命令(类似于 2>&1 |):
# 只有标准输出能通过管道
[whisky@centos7 ~]$ ls -l file-{01..06} | grep file-06
ls: cannot access 'file-04': No such file or directory
ls: cannot access 'file-05': No such file or directory
ls: cannot access 'file-06': No such file or directory
# grep 没有匹配(因为它收到的输入中不包含错误信息)
# |& 将错误也传递给 grep
[whisky@centos7 ~]$ ls -l file-{01..06} |& grep file-06
ls: cannot access 'file-06': No such file or directory
4. tee:分流输出到文件与屏幕
4.1 为什么需要 tee?
管道让命令串联,但如果同时想在屏幕上看到输出,又保存到文件呢?单纯用 > 重定向会看不到屏幕输出,单纯用 | 传递给下一个命令也看不到中间结果。
tee 命令解决了这个问题——它从标准输入读取数据,然后同时输出到标准输出(屏幕)和文件。
4.2 基本用法
# 查找 passwd 文件,同时显示在屏幕并保存到文件
[whisky@centos7 ~]$ find /etc -name 'passwd' 2>/dev/null | tee passwd.list
/etc/pam.d/passwd # ← 显示在屏幕
/etc/passwd # ← 显示在屏幕
[whisky@centos7 ~]$ cat passwd.list
/etc/pam.d/passwd
/etc/passwd
4.3 追加模式:-a
# 第一次执行,覆盖写入
[whisky@centos7 ~]$ find /etc -name 'passwd' 2>/dev/null | tee passwd.list
/etc/pam.d/passwd
/etc/passwd
# 第二次执行,追加写入(-a)
[whisky@centos7 ~]$ find /etc -name 'passwd' 2>/dev/null | tee -a passwd.list
/etc/pam.d/passwd
/etc/passwd
[whisky@centos7 ~]$ cat passwd.list
/etc/pam.d/passwd
/etc/passwd
/etc/pam.d/passwd
/etc/passwd
4.4 tee 在管道链中的位置
tee 可以放在管道链的中间,既保存中间结果,又继续向下传递:
# 查找 passwd 相关手册 → 保存到文件 → 同时过滤出 "passwd" 行
[whisky@centos7 ~]$ man -k passwd | tee passwd.man | grep passwd
# 屏幕显示的是过滤后的结果
# passwd.man 保存了完整的 man -k 输出
4.5 tee 典型应用场景
| 场景 | 示例 |
|---|---|
| 安装日志留存 | `yum install httpd |
| 调试管道链 | `cmd1 |
| 脚本执行记录 | `./deploy.sh 2>&1 |
5. 标准输入重定向:< 与 <<
5.1 < —— 从文件读取输入
默认情况下,命令从键盘(标准输入)读取数据。用 < 可以从文件读取:
# cat 默认从键盘读取输入(按 Ctrl+D 结束)
[whisky@centos7 ~]$ cat
hello
hello
world
world
# 按 Ctrl+D 退出
# 用 < 从文件读取输入
[whisky@centos7 ~]$ cat < /etc/hosts
127.0.0.1 localhost localhost.localdomain ...
::1 localhost localhost.localdomain ...
# 效果与 cat /etc/hosts 相同(但机制不同)
区别:
cat /etc/hosts:/etc/hosts是命令行参数,cat 主动打开文件cat < /etc/hosts:Shell 打开文件,将内容作为标准输入传给 cat
对于 cat,两者效果相同。但测试一个命令是否接收标准输入,可以用 < 验证:
# ls 不接收标准输入,输入重定向无效
[whisky@centos7 ~]$ ls < /etc/hosts
# 仍然显示当前目录内容
# wc 接收标准输入
[whisky@centos7 ~]$ wc -l < /etc/hosts
3
5.2 << —— Here Document(内联输入)
<< 允许在命令行中直接指定多行输入,以特定字符串(如 EOF)结束:
# 基本语法:cat << EOF
[whisky@centos7 ~]$ cat << EOF
> 第一行
> 第二行
> 第三行
> EOF
第一行
第二行
第三行
5.3 实战:一次性写入多行内容到文件
# 方法一:用 echo 加引号(简单场景)
[whisky@centos7 ~]$ echo '第一行
> 第二行
> 第三行' > multi.txt
# 方法二:用 cat + Here Document(推荐,更清晰)
[whisky@centos7 ~]$ cat > config.conf << EOF
# 这是配置文件
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATABASE_USER=admin
EOF
[whisky@centos7 ~]$ cat config.conf
# 这是配置文件
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATABASE_USER=admin
💡 最佳实践:在 Shell 脚本中用 Here Document 生成配置文件,代码清晰且易于维护。
5.4 输入重定向操作符速查
| 操作符 | 名称 | 作用 |
|---|---|---|
< | 输入重定向 | 从文件读取输入 |
<< | Here Document | 从命令行内联读取多行输入 |
<<< | Here String | 从字符串读取输入(Bash 扩展) |
# <<< 示例(将字符串作为标准输入)
[whisky@centos7 ~]$ wc -w <<< "hello world"
2
6. Shell 变量:定义、引用与作用域
6.1 变量的定义与命名
Shell 变量是存储在内存中的键值对,用于保存临时数据。
变量名规则:
- 只能包含字母、数字、下划线
- 不能以数字开头
- 区分大小写(
name≠NAME)
# 定义变量(等号两边不能有空格!)
[whisky@centos7 ~]$ username=facai
[whisky@centos7 ~]$ first_name=zhang
[whisky@centos7 ~]$ var1=hello123
# ❌ 错误示例
[whisky@centos7 ~]$ 1var=hello # 不能以数字开头
[whisky@centos7 ~]$ user name=facai # 不能有空格
[whisky@centos7 ~]$ user-name=facai # 不能有连字符
6.2 引用变量值:$
[whisky@centos7 ~]$ first_name=zhang
[whisky@centos7 ~]$ last_name=facai
# 引用变量
[whisky@centos7 ~]$ echo $last_name $first_name
zhang facai
# 字符串拼接
[whisky@centos7 ~]$ echo $last_name-$first_name
zhang-facai
6.3 变量边界:${}
当变量名与其他字符连在一起时,用 ${} 明确边界:
[whisky@centos7 ~]$ last_name=zhang
[whisky@centos7 ~]$ first_name=facai
# 错误:Shell 会寻找变量 last_name_(不存在)
[whisky@centos7 ~]$ echo $last_name_$first_name
facai
# 正确:用 {} 明确边界
[whisky@centos7 ~]$ echo ${last_name}_$first_name
zhang_facai
6.4 查看与删除变量
# set 显示所有变量(包括环境变量和函数)
[whisky@centos7 ~]$ set | grep first_name
first_name=facai
# unset 删除变量
[whisky@centos7 ~]$ unset first_name
[whisky@centos7 ~]$ echo $first_name
# 无输出
6.5 变量作用域:export
变量默认是局部变量,只在当前 Shell 中有效。子 Shell(如执行 bash 后)无法看到父 Shell 的局部变量:
[whisky@centos7 ~]$ username=tom
[whisky@centos7 ~]$ echo $username
tom
[whisky@centos7 ~]$ bash # 进入子 Shell
[whisky@centos7 ~]$ echo $username
# 无输出(局部变量不可见)
[whisky@centos7 ~]$ exit # 退出子 Shell
# 使用 export 将变量提升为全局(环境变量)
[whisky@centos7 ~]$ export username=tom
# 或分两步
[whisky@centos7 ~]$ username=tom
[whisky@centos7 ~]$ export username
[whisky@centos7 ~]$ bash # 进入子 Shell
[whisky@centos7 ~]$ echo $username
tom # 现在可见了
6.6 变量类型修饰(declare)
# declare 显式声明变量
[whisky@centos7 ~]$ declare var1=key1
# -l:强制转为小写
[whisky@centos7 ~]$ declare -l name=James
[whisky@centos7 ~]$ echo $name
james
# -u:强制转为大写
[whisky@centos7 ~]$ declare -u name=James
[whisky@centos7 ~]$ echo $name
JAMES
# -i:声明为整数
[whisky@centos7 ~]$ declare -i num=10+5
[whisky@centos7 ~]$ echo $num
15
7. 环境变量:系统的“全局配置”
7.1 什么是环境变量
环境变量是系统预设或用户设置的全局变量,影响 Shell 的行为和程序的运行环境。用 env 或 printenv 查看所有环境变量:
[whisky@centos7 ~]$ env
USER=whisky
HOME=/home/whisky
SHELL=/bin/bash
LANG=zh_CN.utf8
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/whisky/.local/bin:/home/whisky/bin
PWD=/home/whisky
...
7.2 核心环境变量详解
PATH —— 命令搜索路径
PATH 决定了输入命令时,Shell 去哪些目录查找可执行文件:
[whisky@centos7 ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/whisky/.local/bin:/home/whisky/bin
# 查找命令位置
[whisky@centos7 ~]$ which ls
alias ls='ls --color=auto'
/usr/bin/ls
修改 PATH(临时):
# 追加一个目录到 PATH 末尾
[whisky@centos7 ~]$ export PATH=$PATH:/home/whisky/bin
# 添加一个目录到 PATH 开头(优先级更高)
[whisky@centos7 ~]$ export PATH=/home/whisky/bin:$PATH
⚠️ 常见问题:执行自己写的脚本报
command not found,原因往往是脚本目录不在PATH中。解决方案:用绝对路径执行(/home/user/script.sh),或将脚本目录加入PATH。
LANG —— 系统语言
[whisky@centos7 ~]$ echo $LANG
zh_CN.utf8
[whisky@centos7 ~]$ date
2026年 7月 13日 星期一 15:30:00 CST
# 临时切换语言
[whisky@centos7 ~]$ export LANG=en_US.utf8
[whisky@centos7 ~]$ date
Mon Jul 13 15:30:05 CST 2026
| 语言代码 | 含义 |
|---|---|
en_US.utf8 | 英语(美国),UTF-8 编码 |
zh_CN.utf8 | 简体中文,UTF-8 编码 |
zh_TW.utf8 | 繁体中文,UTF-8 编码 |
EDITOR —— 默认编辑器
许多命令(如 visudo、crontab -e)会使用 EDITOR 环境变量指定的编辑器:
[root@centos7 ~]# visudo
# 默认使用 vi
[root@centos7 ~]# export EDITOR=/bin/vim
[root@centos7 ~]# visudo
# 现在使用 vim(有语法高亮)
PS1 —— 命令提示符
PS1 定义了命令提示符的样式:
[whisky@centos7 ~]$ echo $PS1
[\u@\h \W]\$
# 修改提示符
[whisky@centos7 ~]$ PS1='HELLO > '
HELLO > echo hello
hello
# 恢复默认
[whisky@centos7 ~]$ PS1='[\u@\h \W]\$ '
PS1 常用转义字符:
| 转义 | 含义 |
|---|---|
\u | 当前用户名 |
\h | 主机名(第一个 . 之前) |
\H | 完整主机名 |
\w | 完整工作目录 |
\W | 工作目录的基名(最后一层) |
\t | 当前时间(24 小时制 HH:MM:SS) |
\$ | #(root)或 $(普通用户) |
彩色提示符示例:
# 绿色用户名 + 青色目录
[whisky@centos7 ~]$ PS1='\[\e[0;32m\]\u\[\e[0m\]@\[\e[0;32m\]\h\[\e[0m\]:\[\e[0;34m\]\W\[\e[0m\]\$ '
# 效果:绿色用户名@绿色主机名:蓝色目录$
7.3 环境变量持久化
临时用 export 设置的变量只在当前会话有效。重启或新开终端后失效。
要让变量永久生效,需写入配置文件:
| 配置文件 | 作用范围 | 加载时机 | 用途 |
|---|---|---|---|
/etc/profile | 所有用户 | 登录 Shell 启动时 | 系统级全局配置 |
~/.bash_profile | 当前用户 | 登录 Shell 启动时 | 用户个人配置 |
~/.bashrc | 当前用户 | 非登录 Shell 启动时 | 用户个人配置(别名、函数) |
/etc/bashrc | 所有用户 | 非登录 Shell 启动时 | 系统级 Shell 配置 |
# 示例:为所有用户设置英文环境
[root@centos7 ~]# echo 'export LANG=en_US.utf8' >> /etc/profile
# 示例:为当前用户设置 EDITOR
[whisky@centos7 ~]$ echo 'export EDITOR=vim' >> ~/.bashrc
# 示例:添加自定义脚本目录到 PATH
[whisky@centos7 ~]$ echo 'export PATH=$PATH:/home/whisky/scripts' >> ~/.bash_profile
7.4 环境变量速查表
| 变量 | 含义 | 常见值 |
|---|---|---|
PATH | 命令搜索路径 | 冒号分隔的目录列表 |
HOME | 当前用户家目录 | /home/username |
USER | 当前用户名 | whisky |
SHELL | 当前 Shell 路径 | /bin/bash |
PWD | 当前工作目录 | /home/whisky |
LANG | 系统语言 | zh_CN.utf8 / en_US.utf8 |
EDITOR | 默认编辑器 | vim / nano |
PS1 | 命令提示符样式 | [\u@\h \W]\$ |
HISTFILE | 历史文件路径 | ~/.bash_history |
HISTSIZE | 历史命令条数 | 1000 |
8. 命令替换与引号控制
8.1 命令替换:$() 与反引号
命令替换允许将命令的输出作为另一个命令的参数或赋值给变量。
# 两种语法
$(COMMAND) # 推荐(可嵌套)
`COMMAND` # 旧语法(不推荐嵌套)
# 示例:用 date 生成文件名
[whisky@centos7 ~]$ touch file-$(date +%Y%m%d).txt
[whisky@centos7 ~]$ ls file-*
file-20260713.txt
# 示例:将命令结果赋值给变量
[whisky@centos7 ~]$ today=$(date +%A)
[whisky@centos7 ~]$ echo "今天星期 $today"
今天星期一
# 示例:嵌套命令替换($() 支持嵌套)
[whisky@centos7 ~]$ echo "当前目录有 $(ls | wc -l) 个文件"
当前目录有 42 个文件
# 反引号不支持嵌套(容易混淆)
[whisky@centos7 ~]$ echo `echo \`date\`` # 复杂且易错
8.2 引号与转义:保留字符的字面含义
许多字符在 Shell 中有特殊含义(如 $ 表示变量、* 表示通配符、空格分隔参数)。用引号和转义可以取消这些特殊含义。
| 方式 | 作用范围 | 是否展开变量 | 是否展开命令替换 |
|---|---|---|---|
反斜杠 \ | 仅下一个字符 | ❌ | ❌ |
双引号 "" | 整个字符串 | ✅ | ✅ |
单引号 '' | 整个字符串 | ❌ | ❌ |
\ —— 转义单个字符
[whisky@centos7 ~]$ echo \$PATH
$PATH
[whisky@centos7 ~]$ echo "文件名是: file\ with\ space.txt"
文件名是: file with space.txt
"" —— 弱引用(保留变量和命令替换)
[whisky@centos7 ~]$ username=alice
[whisky@centos7 ~]$ echo "欢迎 $username,今天是 $(date +%F)"
欢迎 alice,今天是 2026-07-13
# 特殊字符如 $ 仍需转义
[whisky@centos7 ~]$ echo "价格是 \$100"
价格是 $100
'' —— 强引用(完全字面量)
[whisky@centos7 ~]$ username=alice
[whisky@centos7 ~]$ echo '欢迎 $username,今天是 $(date +%F)'
欢迎 $username,今天是 $(date +%F)
# 变量和命令替换都没有展开!
# 单引号内不能包含单引号
[whisky@centos7 ~]$ echo 'Let\'s go'
> # 错误!需要用双引号或转义
[whisky@centos7 ~]$ echo "Let's go"
Let's go
8.3 保留空白字符
Shell 默认将多个空格、Tab 压缩为单个空格分隔符。用引号可以保留:
[whisky@centos7 ~]$ echo hello world
hello world
[whisky@centos7 ~]$ echo "hello world"
hello world
8.4 引号与转义实战总结
| 场景 | 写法 | 说明 |
|---|---|---|
| 文件名有空格 | cd "My Documents" | 双引号包裹 |
| 变量值中有特殊字符 | echo "$USER" | 双引号保留变量展开 |
输出纯文本中的 $ | echo '价格是 $100' | 单引号让 $ 失去特殊含义 |
| 输出包含单引号 | echo "It's OK" | 双引号内含单引号 |
| 在变量中等号后有空格 | msg="hello world" | 不加引号会报错 |
| 命令替换 | file-$(date +%Y%m%d) | 推荐 $() |
9. 总结与速查手册
9.1 核心知识点一览
| 主题 | 关键点 |
|---|---|
| 标准输出重定向 | > 覆盖,>> 追加 |
| 标准错误重定向 | 2> 单独重定向错误,2>&1 合并 |
| 丢弃输出 | 2>/dev/null 丢弃错误,&>/dev/null 全部丢弃 |
| **管道 ` | `** |
| tee | 同时输出到屏幕和文件(-a 追加) |
| 标准输入重定向 | < 从文件读,<< Here Document |
| 变量 | 变量名=值,$变量名 引用,export 提升为环境变量 |
| 环境变量 | PATH(命令路径)、LANG(语言)、PS1(提示符) |
| 命令替换 | $(command) 或反引号 |
| 引号 | \ 转义单字符,"" 保留变量展开,'' 完全字面 |
9.2 重定向速查表
| 操作符 | 含义 |
|---|---|
> | 标准输出覆盖到文件 |
>> | 标准输出追加到文件 |
2> | 标准错误覆盖到文件 |
2>> | 标准错误追加到文件 |
&> | 覆盖合并输出和错误 |
&>> | 追加合并输出和错误 |
2>&1 | 将错误重定向到标准输出 |
> file 2>&1 | 合并输出和错误到 file |
2>/dev/null | 丢弃错误信息 |
9.3 管道与 tee 速查表
| 操作符 | 作用 |
|---|---|
| `cmd1 | cmd2` |
| `cmd1 | & cmd2` |
| `cmd | tee file` |
| `cmd | tee -a file` |
9.4 变量与环境变量速查表
| 操作 | 语法 |
|---|---|
| 定义变量 | var=value(等号两边无空格) |
| 引用变量 | $var 或 ${var} |
| 查看所有变量 | set |
| 删除变量 | unset var |
| 提升为环境变量 | export var 或 export var=value |
| 查看环境变量 | env 或 printenv |
| 修改 PATH | export PATH=$PATH:/新/目录 |
9.5 命令替换与引号速查表
| 操作 | 语法 |
|---|---|
| 命令替换 | $(command) 或 command |
| 转义单字符 | \ |
| 弱引用(展开变量) | "字符串" |
| 强引用(不展开) | '字符串' |
9.6 常见错误排查指南
| 错误现象 | 原因 | 解决方案 |
|---|---|---|
command not found | 命令不在 PATH 中 | 用绝对路径执行,或将目录加入 PATH |
> file 后屏幕还在输出 | 是错误信息(stderr) | 用 2> 或 &> 合并重定向 |
变量赋值报错 command not found | 等号两边有空格 | 移除空格:var=value |
echo $var 显示为空 | 变量未定义或作用域不对 | 用 `set |
echo $PATH 后目录重复 | 重复追加 PATH | 检查 .bashrc 中是否有重复的 export |
| 单引号内无法展开变量 | 单引号不展开任何内容 | 改用双引号 "$var" |
| 文件名含空格无法操作 | 未加引号 | 用引号包裹:"file name.txt" |
cat << EOF 报错 | EOF 前有空格或 Tab | EOF 必须顶格写(行首) |
9.7 综合实战:数据流组合拳
场景:统计 /var/log 目录下所有 .log 文件中包含 “ERROR” 的行数,并将结果保存到报告文件,同时显示在屏幕。
# 逐步拆解
[whisky@centos7 ~]$ grep -r "ERROR" /var/log/*.log 2>/dev/null | wc -l | tee error-count.txt
42
[whisky@centos7 ~]$ cat error-count.txt
42
# 更进一步:生成带时间戳的报告
[whisky@centos7 ~]$ echo "=== 错误统计报告 $(date +%F %T) ===" > report.txt
[whisky@centos7 ~]$ grep -r "ERROR" /var/log/*.log 2>/dev/null | wc -l | tee -a report.txt
9.8 思考与拓展(原课后作业转化)
- 为什么需要
2>&1,而不是直接2>1?
→2>1会被解析为“将错误重定向到名为1的文件”,而不是“重定向到文件描述符 1”。2>&1中的&表示“这是一个文件描述符”。 > file 2>&1和2>&1 > file效果一样吗?
→ 不一样。2>&1必须放在>之后,因为它的意思是“将错误重定向到标准输出当前指向的位置”。如果放在前面,此时标准输出还指向屏幕,错误也会输出到屏幕。- 什么情况下用
nohup command &而不是command &?
→command &将进程放入后台,但终端关闭时进程会收到SIGHUP信号而终止。nohup command &让进程忽略SIGHUP,终端关闭后继续运行。 set和env的输出有什么区别?
→set显示所有变量(包括局部变量、环境变量和函数);env只显示环境变量(已export的变量)。- 单引号和双引号的根本区别是什么?
→ 双引号是“弱引用”,会展开变量($var)和命令替换($(cmd));单引号是“强引用”,所有内容原样输出,不做任何展开。
9.9 生产环境最佳实践
| 场景 | 建议 |
|---|---|
| 脚本输出日志 | `./script.sh 2>&1 |
| 静默执行 | ./script.sh >/dev/null 2>&1(丢弃所有输出) |
| 调试管道链 | 在关键节点插入 tee stepN.log 保存中间结果 |
| PATH 管理 | 在 ~/.bashrc 中统一管理,避免重复追加 |
| 敏感信息 | 不要用 export 暴露密码等敏感信息(用 read -s 或配置文件) |
| 长命令可读性 | 用反斜杠 \ 换行: `find /etc -name “*.conf” |
下期预告:从数据流和变量,我们接下来进入 Linux 的用户与权限体系——这是系统安全的核心。每一期我们将学习 用户账户管理(useradd/usermod/userdel)、组管理(groupadd/groupmod/groupdel)、密码策略(/etc/shadow 与 chage),以及如何通过
/etc/passwd、/etc/group、/etc/shadow三个核心文件理解整个账户系统。学会这些,你就能像真正的系统管理员一样“管人”了。敬请期待第七期!
系统管理入门笔记(第六期)——Shell 交互核心:重定向、管道、变量与环境配置&spm=1001.2101.3001.5002&articleId=162851679&d=1&t=3&u=d4540b2e14da43d69b331842256a6905)
713

被折叠的 条评论
为什么被折叠?



