跳到主要内容

重定向、管道与命令组合

本节目标

把固定的 data/access.log 转换为可验证的 output/summary.txt,理解 >>>2>|&& 分别如何控制数据流、失败诊断与后续执行。

开始前状态

你已完成上一节,dev-lab/data/access.log 保持其固定六行内容。这里所有新文件只会写到 dev-lab/output/,而且都是命令输出文件;不会改写原始日志、访问系统日志、连接网络或使用远程脚本。

必要原理

> 把 stdout 创建或覆盖到明确目标。本节会覆盖 output/summary.txt,因此只在确认它就是本节摘要时执行。>> 追加 stdout;这里只把它用于固定名称的临时观察文件,检查后按名称删除。2> 单独重定向 stderr,能把预期失败的诊断与正常数据输出分开。

管道 | 只把左侧命令的 stdout 传给右侧,stderr 不会自动进入管道。&& 有短路语义:左侧失败时右侧不会执行。每次写入输出后都立刻用 cat 检查文件,而不是依赖命令看起来没有报错。

动手完成

运行位置: dev-lab 根目录。预期输出: > 创建或覆盖的目标是 output/summary.txt,其内容精确为三行摘要。失败处理: 执行前先确认覆盖目标;若它不是本节摘要,停止,不要替换为不明文件名。

{
printf 'total requests: '
printf '%s\n' "$(wc -l < data/access.log | tr -d ' ')"
printf 'successful requests: '
grep -c ' 200$' data/access.log
printf 'not found: '
grep -c ' 404$' data/access.log
} > output/summary.txt
cat output/summary.txt

运行位置: 同一个目录。预期输出: stdout 经 cut | sort | uniq -c 得到方法计数;临时结果先写入、用 cat 检查,再明确删除。失败处理: 如果输出异常,先单独执行 cut;不要把 stderr 当作管道数据,也不要把观察文件留在 output/

cut -d ' ' -f 2 data/access.log | sort | uniq -c > output/request-methods.txt
cat output/request-methods.txt
rm output/request-methods.txt
cat output/summary.txt

运行位置: 同一个目录。预期输出: >> 只追加到临时的 output/pipeline-observation.txt,检查后按明确文件名清理。失败处理: 不要把 >> 用于摘要;摘要需要整份重新生成,避免运行两次时累积重复行。

printf '方法计数来自管道的 stdout。\n' >> output/pipeline-observation.txt
cat output/pipeline-observation.txt
rm output/pipeline-observation.txt
cat output/summary.txt

运行位置: 同一个目录。预期输出: 缺失文件的 stderr 独立写入诊断文件,stdout 文件为空;检查两者后明确清理。失败处理: 这是预期失败,不要创建缺失的数据文件;先用 cat 读取分开的输出,再删除这两个已知临时文件。

cat data/expected-missing.log > output/expected-failure-stdout.txt 2> output/expected-failure-stderr.txt
cat output/expected-failure-stdout.txt
cat output/expected-failure-stderr.txt
rm output/expected-failure-stdout.txt
rm output/expected-failure-stderr.txt
cat output/summary.txt

运行位置: 同一个目录。预期输出: 左侧检查失败,所以 && 右侧不会创建 output/should-not-exist.txt;观察结论写入临时文件、检查后清理。失败处理: 不要把 && 改成无条件执行;短路正是这里要观察的行为。

test -f data/expected-missing.log && printf '这行不应写入。\n' > output/should-not-exist.txt
test ! -e output/should-not-exist.txt
printf '前一步失败,&& 已短路,未创建 should-not-exist.txt。\n' >> output/pipeline-observation.txt
cat output/pipeline-observation.txt
rm output/pipeline-observation.txt
cat output/summary.txt

观察结果

output/summary.txt 的内容应精确为:

total requests: 6
successful requests: 4
not found: 2

最终摘要用数字计数,不把依赖 locale 的排序文本作为断言。管道示例中只有 stdout 经过 |;预期失败的 stderr 则由 2> 单独保存。&& 的右侧没有运行,证明短路不是静默成功。

常见问题

为什么摘要用 > 而不是 >> > 会明确重建并覆盖 output/summary.txt;重复练习仍得到相同三行,而不会累计旧结果。

为什么要保留一个刻意失败的命令? 它让你在安全的固定目标中看到 stderr 与 stdout 的分离。失败状态仍然存在,只是诊断被保存以便检查。

完成检查

  • data/access.log 的六行内容没有变化;
  • cat output/summary.txt 精确显示三行摘要;
  • 能说明 > 的覆盖目标、>> 的临时观察用途、2> 的 stderr 分离、| 的 stdout 流向和 && 的短路;
  • output/request-methods.txtoutput/pipeline-observation.txtoutput/expected-failure-stdout.txtoutput/expected-failure-stderr.txt 已按明确文件名删除,未创建 output/should-not-exist.txt

下一步

下一节学习历史记录、补全与用户级 Shell 配置;仍然先观察目标,再在隔离练习目录中验证结果。