07 管道重定向与命令组合
学习目标
- 能把一个命令的输出交给另一个命令。
- 能把输出保存到文件。
- 能根据前一个命令成功或失败决定是否继续执行。
- 能区分 stdin、stdout、stderr 与文件描述符,并验证 pipeline 中间失败。
命令总览
| 命令 | 用途 | 含义 | 基本用法 | 例子 |
|---|---|---|---|---|
| | 管道 | 把左侧命令的标准输出传给右侧命令 | 命令1 | 命令2 | ls -lah | grep -F '.log' |
> | 覆盖写入文件 | 将标准输出写入文件,原内容会被覆盖 | 命令 > 文件 | echo hello > a.txt |
>> | 追加写入文件 | 将标准输出追加到文件末尾 | 命令 >> 文件 | echo world >> a.txt |
< | 从文件读取输入 | 把文件内容作为命令输入 | 命令 < 文件 | sort < names.txt |
2> | 重定向错误输出 | 把标准错误写入文件 | 命令 2> 文件 | find . -name a 2> errors.txt |
&& | 成功后执行 | 左侧命令成功才执行右侧命令 | 命令1 && 命令2 | mkdir test && cd test |
|| | 失败后执行 | 左侧命令失败才执行右侧命令 | 命令1 || 命令2 | cd project || echo "目录不存在" |
tee | 同时显示并写文件 | 复制 stdin 到 stdout 和文件 | 命令 | tee 文件 | printf '%s\n' ok | tee result.txt |
常用场景
筛选命令输出:
ls -lah -- . | grep -F '.log'
pgrep -a -u "$(id -u)" -f 'python3'第一条只演示文本过滤;进程查找使用 pgrep,避免 ps | grep 把 grep 自己的命令行误判为目标进程。
保存输出到文件:
echo "hello" > message.txt
echo "world" >> message.txt把错误输出单独保存:
find . -name '*.conf' > find_results.txt 2> find_errors.txt只在成功后继续:
mkdir project && cd project失败时给出提示:
cd project || echo "project 目录不存在"新手注意
>会覆盖文件,想保留原内容就用>>。- 管道
|传递的是输出文本,不是文件本身。 2>只重定向错误输出,不影响正常输出。&&常用于防止前一步失败后继续执行后续命令。- 命令组合很强大,删除或覆盖文件前要先用无破坏命令预览结果。
三个标准流与重定向顺序
Linux 进程通常从文件描述符 0 读 stdin,向 1 写 stdout,向 2 写 stderr。重定向从左到右处理:
command_that_may_fail > combined.log 2>&1
command_that_may_fail 2>&1 > stdout-only.log两条不等价。第一条让 fd 2 跟随已经指向文件的 fd 1;第二条先让 fd 2 指向原终端,再单独移动 fd 1。示例命令名只是签名说明,不要原样执行。
重定向会先截断
sort data.txt > data.txt可能在sort读取前把输入文件截断为空。输出必须写到新文件,校验后再受控替换。
Pipeline 的退出状态
Bash 默认用最后一条命令的状态作为整条 pipeline 状态:
false | true
pipeline_rc=$?
printf 'pipeline_rc=%s\n' "$pipeline_rc"$? 的赋值也会覆盖 PIPESTATUS,所以查看分段结果时要重新运行并立即保存:
false | true
parts=("${PIPESTATUS[@]}")
printf 'left=%s right=%s\n' "${parts[0]}" "${parts[1]}"开启 Bash pipefail 后,pipeline 返回最右侧非零命令的状态;全部成功才为 0:
set -o pipefail
false | true
pipeline_rc=$?
printf 'pipeline_rc=%s\n' "$pipeline_rc"PIPESTATUS 与 pipefail 是 Bash 能力,不是所有 POSIX Shell 都有。脚本也不能只靠 set -e 代替明确错误处理,因为它在条件、子 Shell 和组合命令中的行为有语境差异。
受控练习
在实验目录创建 input.txt,分别把 stdout、stderr 和合并输出写入三个新文件;再构造 grep 'missing' input.txt | wc -l,比较默认状态、${PIPESTATUS[@]} 和 pipefail。报告中说明“0 行”为什么不能证明 grep 成功。