Shell脚本进阶——管道、正则和批量数据处理

Shell脚本进阶——管道、正则和批量数据处理
面试翻车现场上篇讲了Shell脚本基础有读者说我会写if和for了但看别人的脚本里一堆|、grep、awk、sed完全看不懂。这就是管道和文本处理工具。它们是Shell脚本的灵魂。面试中也常考。我一般会问给你一个日志文件怎么找出所有ERROR行并统计数量如果你只会用vim打开然后数那就尴尬了。管道命令的串联管道的思想很简单把一个命令的输出传给下一个命令作为输入。符号是|。ps aux | grep robot # 列出进程过滤出robot相关的 cat log.txt | grep ERROR # 读日志过滤出ERROR行 ls -l | wc -l # 列出文件统计行数即文件数量管道可以串联多个命令cat robot.log | grep ERROR | grep lidar | wc -l这条命令做了四件事读日志→找ERROR→再找包含lidar的→统计行数。最终结果是激光雷达相关的错误数量。重定向echo hello file.txt # 写入文件覆盖 echo world file.txt # 追加到文件 cat log.txt 21 # 把标准错误重定向到标准输出 command /dev/null 21 # 丢弃所有输出21这个写法很常见但新手容易搞混。文件描述符1是标准输出2是标准错误。21意思是把标准错误也送到标准输出去。配合就能把所有输出都重定向到文件或者丢弃。grep文本搜索利器grep是最常用的文本搜索工具。grep ERROR robot.log # 搜索包含ERROR的行 grep -i error robot.log # 忽略大小写 grep -r TODO src/ # 递归搜索目录下所有文件 grep -n ERROR robot.log # 显示行号 grep -c ERROR robot.log # 只输出匹配行数 grep -v DEBUG robot.log # 反向匹配排除DEBUG grep -E ERROR|WARN robot.log # 扩展正则匹配ERROR或WARN组合使用# 找出最近1小时内修改过的文件 find ~/robot_ws -name *.cpp -mmin -60 # 找出所有包含TODO的C文件 grep -rn TODO src/ --include*.cpp # 统计每个文件的ERROR数量 grep -c ERROR *.log | sort -t: -k2 -nrsed流编辑器sed可以在不打开文件的情况下修改文本。sed s/old/new/g file.txt # 替换只输出不改文件 sed -i s/old/new/g file.txt # 直接修改文件 sed -i s/DEBUG/INFO/g *.log # 批量修改多个文件 sed -n 10,20p file.txt # 只输出第10到20行 sed /ERROR/d file.txt # 删除包含ERROR的行实际应用场景# 批量修改配置文件中的IP地址 sed -i s/192.168.1.100/192.168.1.200/g config.yaml # 给所有C文件添加头文件保护 sed -i 1i #pragma once *.h # 删除日志中的时间戳假设格式是[2024-01-01 12:00:00] sed s/\[[0-9-]* [0-9:]*\]//g robot.logawk文本处理利器awk是按列处理文本的工具。默认以空格或Tab分隔。# 输出每行的第1列和第3列 awk {print $1, $3} data.txt # 输出进程列表中CPU占用超过10%的进程 ps aux | awk $3 10 {print $2, $3, $11} # 计算日志中ERROR出现的次数 grep ERROR robot.log | awk END {print NR} # 按分隔符处理 echo a:b:c | awk -F: {print $2} # 输出bawk还能做数学运算# 计算一列数字的平均值 cat scores.txt | awk {sum $1} END {print sum/NR} # 统计日志中每种错误类型的数量 grep ERROR robot.log | awk {print $5} | sort | uniq -c | sort -rn正则表达式正则表达式是文本匹配的通用语法grep、sed、awk都支持。常用模式. 匹配任意单个字符 * 匹配前一个字符0次或多次 [abc] 匹配a、b或c [a-z] 匹配a到z之间的任意字符 ^ 行首 $ 行尾 \d 数字需要-E或-P \w 字母数字下划线 匹配前一个字符1次或多次 ? 匹配前一个字符0次或1次 () 分组 | 或实际例子# 匹配IP地址 grep -E [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} log.txt # 匹配邮箱 grep -E [a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,} contacts.txt # 匹配ROS2的topic名称以/开头 grep -E ^/[a-z_/] topics.txt批量数据处理实战场景1分析机器人日志#!/bin/bash # 分析日志中的错误分布 LOG_DIR~/robot_logs echo 日志错误分析 for log in $LOG_DIR/*.log; do errors$(grep -c ERROR $log 2/dev/null || echo 0) warns$(grep -c WARN $log 2/dev/null || echo 0) echo $(basename $log): ERROR$errors, WARN$warns done echo echo 最常见的ERROR类型 grep ERROR $LOG_DIR/*.log | awk -FERROR {print $2} | sort | uniq -c | sort -rn | head -10场景2批量重命名文件#!/bin/bash # 把所有.jpg改成.png假设内容已经是PNG格式 for file in *.jpg; do mv $file ${file%.jpg}.png done echo 重命名完成场景3提取ROS2 bag中的信息#!/bin/bash # 列出所有rosbag中的topic和消息数量 for bag in ~/bags/*.db3; do echo $(basename $bag) ros2 bag info $bag | grep -E Topic|Count echo done面试常见考点管道和重定向的区别——管道把一个命令的输出传给另一个命令重定向把命令的输出送到文件或从文件读取输入。grep、sed、awk分别适合什么场景——grep擅长搜索过滤sed擅长替换修改awk擅长按列处理和统计。怎么统计一个文件中某个单词出现的次数——grep -o word file | wc -l。-o让grep每个匹配输出单独一行然后wc -l统计行数。xargs是什么——把标准输入转换成命令的参数。比如find . -name *.log | xargs rm先找到所有.log文件然后传给rm删除。Shell脚本的工程实践在实际项目中Shell脚本经常用于系统初始化和部署流程。一个好的习惯是在脚本开头加上set -euo pipefail这样遇到未定义变量、命令失败或管道错误时都会立即退出。另外用trap捕获退出信号可以做清理工作比如删除临时文件。面试时被问到Shell编程能力举一个实际的自动化部署案例会比泛泛而谈好得多。给你的建议管道和文本处理工具需要多练。光看教程没用得在实际场景中用几次才能记住。给你几个练习题找出当前目录下最大的10个文件统计你的代码仓库里有多少行C代码从日志中提取所有IP地址并去重。做机器人开发你每天都会和数据打交道——日志、配置文件、传感器输出。掌握这些工具你就能快速从海量数据中提取有用信息。这比写Python脚本快得多特别是在SSH到机器人上的时候。上一篇第89篇 Shell脚本入门——自动化测试和环境配置的起点下一篇预告第91篇 apt与源码编译——Linux软件安装的完整指南