重定向、管道与命令组合
本节目标
把固定的 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.txt、output/pipeline-observation.txt、output/expected-failure-stdout.txt和output/expected-failure-stderr.txt已按明确文件名删除,未创建output/should-not-exist.txt。
下一步
下一节学习历史记录、补全与用户级 Shell 配置;仍然先观察目标,再在隔离练习目录中验证结果。