未记录事实核验 · 状态:现行内容
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用边界与维护说明
本文适合在 GNU/Linux 与 Bash 环境中学习标准数据流、管道和重定向,并使用自建文件练习,不是可直接部署的生产日志处理方案。基础文件筛选用find匹配.csv文件;访问日志统计限定为第一列IP、第五列状态码的简化布局。tee 在管道中把输出传给下一命令,不一定直接显示到终端。实战流水线需满足正文指定的字段格式、输入文件可读和报告目录可写等条件,且未检查各步失败,末尾的完成提示不能作为成功依据。删除、原地修改及截断操作应先检查范围并备份;现有空字符分隔的 xargs 示例已处理文件名分隔问题。本文仅作结构审阅,未执行命令或进行外部事实、链接核验。
管道与重定向 - 组合命令的威力
abstract 本文概要
- 管道
|:把命令串联起来 - 输出重定向
>和>>:把输出保存到文件 - 输入重定向
<:从文件读取输入 - 错误重定向
2>&1:捕获错误信息 - 实际数据处理组合技
理解 Linux 的数据流
Linux 命令有三个标准数据流:
标准输入 stdin (0):命令从哪里读取输入(默认:键盘)
标准输出 stdout (1):命令把结果输出到哪里(默认:终端屏幕)
标准错误 stderr (2):命令把错误信息输出到哪里(默认:终端屏幕)
管道和重定向,就是重新配置这三个数据流的流向。
管道 |:把命令串联
管道(pipe)把前一个命令的标准输出,接到后一个命令的标准输入。
命令 A | 命令 B | 命令 C
│ ↑ ↑
└─stdout──┘ │
└─stdout─┘
基础示例
# 按文件名匹配当前目录中的普通CSV文件(独立find示例)
find . -maxdepth 1 -type f -name '*.csv' -print
# 查看日志,过滤错误行,再统计数量
cat app.log | grep "ERROR" | wc -l
# 简化写法(cat + grep 可以直接用 grep):
grep -c "ERROR" app.log
# 查看进程,过滤特定程序
ps aux | grep "python"
# 列出目录,排序,查看最大的几个
du -sh /data/* | sort -rh | head -10
多命令串联
管道可以无限串联,每个命令只负责一件事:
# 分析访问日志:找错误 → 提取 IP → 排序 → 去重统计 → 取 TOP 10
# 简化日志字段:IP 时间戳 请求方法 URL 状态码 响应大小(字段均不含空格)
# 示例:192.168.1.1 2026-03-18T09:30:00 GET /api/user 500 1024
# 仅适用于上述第一列为IP、第五列为状态码的布局
awk '$5 == 500 {print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 拆解理解:
# 1. awk检查第五列状态码为500并输出第一列IP(须符合指定日志布局)
# awk同时完成筛选状态码与提取IP,不是两个独立管道阶段
# 3. sort → 排序,让相同值相邻,以便 uniq 汇总全文件中的重复值
# 4. uniq -c → 去重并统计每个 IP 出现次数
# 5. sort -rn → 按数量从大到小排序
# 6. head -10 → 取前 10 行
tip 管道的威力
Linux 的设计哲学:每个命令只做一件事,但做好。组合起来就能完成复杂任务。 上面这个 6 层管道展示了日志筛选与聚合的组合方式。若将“10GB 日志几秒完成、Python 实现至少 20 行”作为比较假设,需要给出测试环境、日志特征和具体实现;这里不能据此作性能或代码量保证。
常用管道组合
# 去重统计(排序 + 去重统计 + 按数量排序)
sort | uniq -c | sort -rn
# 找出文件中重复的行
sort data.txt | uniq -d
# 找出文件中唯一的行(只出现一次)
sort data.txt | uniq -u
# 统计文件中不重复的行数
sort data.txt | uniq | wc -l
# 把结果分页显示(避免刷屏)
ls -la /data/ | less
# 实时过滤日志
tail -f app.log | grep "ERROR"
# 查找并处理(xargs 把管道结果转换为命令参数)
# 先检查匹配范围;以下命令会删除匹配文件,建议在测试目录练习
find /tmp -type f -name "*.tmp" -print0 | xargs -0 -r rm -f --
# GNU/Linux 示例:先确认匹配文件并备份;命令会原地修改 /etc 下的匹配文件
grep -rlZ "old_config" /etc/ | xargs -0 -r sed -i.bak 's/old_config/new_config/g' --
输出重定向 > 和 >>
把命令的输出保存到文件,而不是打印到终端。
> 覆盖写入
# 把 ls 的输出保存到文件(会覆盖已有内容)
ls -la > file_list.txt
# 把 grep 的结果保存到文件
grep "ERROR" app.log > errors.txt
# 把统计结果保存
wc -l /data/*.csv > line_counts.txt
# 清空文件(用 > 重定向空内容)
> old_file.txt
# 等效于
cat /dev/null > old_file.txt
warning `>` 会覆盖文件
如果目标文件已存在,> 会清空它再写入。要追加而不是覆盖,用 >>。
>> 追加写入
# 把结果追加到文件末尾(不覆盖)
echo "2026-03-18: 处理完成" >> process.log
# 把多个文件的内容合并
cat file1.csv >> merged.csv
cat file2.csv >> merged.csv
# 日志记录(常用在 Shell 脚本中)
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: 开始处理数据" >> etl.log
组合示例
# 提取错误日志并保存,同时显示行数
grep "ERROR" app.log | tee errors.txt | wc -l
# tee写入errors.txt,并把错误行传给wc -l;终端显示wc统计的行数
# 每天的统计结果追加到月度报告
date_str=$(date +%Y-%m-%d)
echo "=== $date_str ===" >> monthly_stats.txt
awk -F',' '{ sum += $5 } END { print "总金额:", sum }' orders_${date_str}.csv >> monthly_stats.txt
输入重定向 <
把文件内容作为命令的输入。
# 基本用法(效果等同于 cat file | command)
sort < unsorted.txt
wc -l < data.csv
# 向数据库导入 SQL 文件(非常常用!)
mysql -u alice -p mydb < import.sql
psql -U alice -d mydb < import.sql
# 使用 Here Document(往命令里传多行文本)
cat << EOF > config.properties
host=10.0.0.100
port=3306
database=mydb
EOF
# << EOF 到 EOF 之间的内容,作为 cat 的输入,再通过 > 写入文件
# 更常见的 Here Document 用法:
mysql -u alice -p mydb << EOF
SELECT COUNT(*) FROM users;
SELECT SUM(amount) FROM orders WHERE date='2026-03-18';
EOF
tip Here Document 在 Shell 脚本中的应用
#!/bin/bash
# 脚本中执行多条 SQL
mysql -u alice -p"${DB_PASS}" ${DB_NAME} << EOF
INSERT INTO etl_log (date, status, rows) VALUES ('$(date +%Y-%m-%d)', 'success', $(wc -l < data.csv));
UPDATE job_config SET last_run='$(date)' WHERE job_name='daily_etl';
EOF
错误重定向 2> 和 2>&1
基础错误重定向
# 把错误信息重定向到文件(2 是 stderr 的文件描述符)
ls /nonexistent 2> error.log
# 把错误信息丢弃(重定向到 /dev/null,Linux 的"黑洞")
ls /nonexistent 2>/dev/null
# 同时保存标准输出和错误输出到不同文件
command > output.log 2> error.log
2>&1 合并输出和错误
# 把 stderr 合并到 stdout(最终都输出到同一个地方)
command > all_output.log 2>&1
# 含义:
# > all_output.log → stdout 重定向到文件
# 2>&1 → stderr (2) 重定向到 stdout (1) 的目标,即也到文件
# 常见写法:把所有输出(含错误)保存到文件
python etl.py > run.log 2>&1
# 新版 bash 的简化写法(等效于上面)
python etl.py &> run.log
# 实时查看输出的同时保存到文件
python etl.py 2>&1 | tee run.log
note 数据工作场景:脚本日志记录
# 提交 Spark 任务,把所有输出保存到日志文件
spark-submit \
--class com.example.DataJob \
--master yarn \
job.jar \
> /var/log/spark/data_job_$(date +%Y%m%d).log 2>&1
# 提交后,用 tail -f 实时查看
tail -f /var/log/spark/data_job_20260318.log
/dev/null - Linux 的垃圾桶
/dev/null 是一个特殊文件,写入它的数据全部被丢弃,读取它什么都读不到。
# 丢弃错误信息(不想看到 Permission denied 报错)
find / -name "*.log" 2>/dev/null
# 丢弃所有输出(让命令静默运行)
command > /dev/null 2>&1
# 清空文件
cat /dev/null > file.txt
# 或
> file.txt
tip find 命令常配合 2>/dev/null
# 搜索整个系统的 log 文件
# 不加 2>/dev/null 会报大量 Permission denied
find / -name "*.log" -size +100M 2>/dev/null
tee - T 形管道(同时输出到终端和文件)
# 把结果既显示在终端,又保存到文件
command | tee output.txt
# 追加模式(不覆盖已有文件)
command | tee -a output.txt
# 实际应用:ETL 任务的运行输出,既看又存
./run_etl.sh 2>&1 | tee etl_$(date +%Y%m%d).log
实战:数据处理流水线
# 场景:每天处理用户行为日志,生成统计报告
# 1. 提取今天的日志(假设空白分隔的字段依次为:不含空格且以 YYYY-MM-DD 开头的时间戳、IP、状态码、页面)
today=$(date +%Y-%m-%d)
grep "^${today}" /var/log/app/user_behavior.log > /tmp/today_behavior.log
# 2. 过滤有效记录(状态码 200,去掉机器人 IP 段)
# 仅当本业务已确认 10.* 为需要排除的来源时使用此过滤条件
awk '$3 == 200 && $2 !~ /^10\./' /tmp/today_behavior.log > /tmp/valid_behavior.log
# 3. 统计各页面访问量,保存报告
awk '{print $4}' /tmp/valid_behavior.log \
| sort \
| uniq -c \
| sort -rn \
| head -20 \
> /data/report/${today}_page_stats.txt
# 4. 统计独立 IP 数(不等同于独立用户数)
awk '{print $2}' /tmp/valid_behavior.log \
| sort -u \
| wc -l \
>> /data/report/${today}_page_stats.txt
# 5. 清理临时文件
rm -f /tmp/today_behavior.log /tmp/valid_behavior.log
echo "报告生成完成:/data/report/${today}_page_stats.txt"
快速参考
| 符号 | 含义 | 示例 |
|---|---|---|
| |
管道:前一个命令的输出 → 下一个命令的输入 | ls | grep csv |
> |
输出到文件(覆盖) | ls > list.txt |
>> |
追加到文件 | echo done >> log.txt |
< |
从文件读取输入 | sort < data.txt |
2> |
错误输出到文件 | cmd 2> err.log |
2>&1 |
错误合并到标准输出 | cmd > all.log 2>&1 |
&> |
所有输出到文件(bash 简写) | cmd &> all.log |
/dev/null |
丢弃输出 | cmd 2>/dev/null |
tee |
同时输出到终端和文件 | cmd | tee out.txt |
下一步
- 08-Shell脚本基础 - 把管道和重定向写进脚本,实现自动化
- 06-文本处理三剑客 - grep/sed/awk 是管道里最常用的命令
- 11-定时任务crontab - 脚本 + 重定向 + crontab = 自动化数据处理
掌握检查
- [ ] 能解释管道
|的本质:把左边命令的标准输出连接到右边命令的标准输入 - [ ] 知道
>和>>的区别:前者覆盖,后者追加;追加操作在写日志时更安全 - [ ] 能用
cmd > output.log 2>&1把标准输出和错误输出都重定向到同一个文件 - [ ] 理解
tee的用途:既把数据传给下一个管道,又同时保存到文件,调试时常用 - [ ] 能用
cat /dev/null > log.txt原地截断日志文件而不删除其路径(会丢失现有内容;删除路径不必然使已打开的文件描述符失效,对运行中日志应使用适合该程序的日志轮转方式)
实践练习
基础题:用一行管道命令实现:在 /var/log/ 下找出所有 .log 文件,统计各文件行数,并按行数从多到少排序,结果保存到 /tmp/log_stats.txt(提示:find + wc -l + sort)。
进阶题:用管道组合实现日志分析:从 /var/log/syslog(或任意日志)中提取包含 error 的行(不区分大小写),去掉重复行,统计总数,把结果用 tee 同时输出到终端和文件 /tmp/error_summary.txt。
下一步
- Shell脚本基础 - 把管道和重定向写进脚本,实现自动化
- 定时任务crontab - 脚本 + 重定向 + crontab = 自动化数据处理
#Linux #管道 #重定向 #Shell #数据处理