第 8 章:核心工具
第 8 章:核心工具
8.1 文件查找:find
8.1.1 基本用法
# 按名称查找
$ find /etc -name "*.conf"
/etc/resolv.conf
/etc/hostname
/etc/inittab
# 按类型查找
$ find /tmp -type f # 普通文件
$ find /tmp -type d # 目录
$ find /tmp -type l # 符号链接
# 按大小查找
$ find /var -size +1M # 大于 1MB
$ find /tmp -size 0 # 空文件
# 按时间查找
$ find /tmp -mtime -1 # 最近 1 天修改
$ find /etc -mtime +30 # 超过 30 天修改
$ find /var -newer /tmp/old # 比 old 文件更新
# 按权限查找
$ find /usr -perm 755 # 精确权限
$ find /usr -perm -644 # 至少包含 644
8.1.2 执行操作
# 删除文件
$ find /tmp -name "*.log" -delete
# 执行命令
$ find /tmp -name "*.txt" -exec ls -l {} \;
# 使用 xargs
$ find /tmp -name "*.log" | xargs rm -f
# 批量处理
$ find /etc -name "*.conf" -exec grep "dns" {} +
8.1.3 实用示例
# 查找大文件
$ find / -type f -size +10M 2>/dev/null -exec ls -lh {} \;
# 查找并清理日志
$ find /var/log -name "*.log" -mtime +7 -delete
# 查找可执行文件
$ find /usr/bin -type f -executable -name "busy*"
# 查找符号链接
$ find / -type l -name "sh" -exec ls -la {} \;
# 查找空目录
$ find /tmp -type d -empty -delete
8.2 文本搜索:grep
8.2.1 基本用法
# 搜索字符串
$ grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/sh
# 忽略大小写
$ grep -i "Root" /etc/passwd
# 递归搜索目录
$ grep -r "nameserver" /etc/
# 显示行号
$ grep -n "root" /etc/passwd
1:root:x:0:0:root:/root:/bin/sh
# 反向匹配
$ grep -v "nobody" /etc/passwd
# 只显示匹配部分
$ grep -o "root" /etc/passwd | wc -l
8.2.2 正则表达式
# 基本正则
$ grep "^root" /etc/passwd # 以 root 开头
$ grep "sh$" /etc/passwd # 以 sh 结尾
$ grep "r..t" /etc/passwd # 匹配 r 开 t 结中间两个字符
# 扩展正则(-E 或 egrep)
$ grep -E "root|nobody" /etc/passwd
$ grep -E "[0-9]+" /etc/passwd
$ egrep "(root|admin)" /etc/passwd
# 注意:BusyBox grep 不支持 -P(PCRE)
# 错误:grep -P '\d+' file
# 正确:grep -E '[0-9]+' file
8.2.3 常用选项
# 统计匹配行数
$ grep -c "error" /var/log/messages
# 显示匹配文件名
$ grep -l "nameserver" /etc/*
# 显示不匹配的文件名
$ grep -L "nameserver" /etc/*
# 上下文显示
$ grep -A 3 "error" logfile # 匹配行后 3 行
$ grep -B 3 "error" logfile # 匹配行前 3 行
$ grep -C 3 "error" logfile # 匹配行前后各 3 行
# 静默模式(只看退出码)
$ grep -q "root" /etc/passwd && echo "Found"
8.3 流编辑器:sed
8.3.1 基本替换
# 替换第一个匹配
$ echo "hello world" | sed 's/world/busybox/'
hello busybox
# 全局替换
$ echo "aaa" | sed 's/a/b/g'
bbb
# 忽略大小写
$ echo "Hello" | sed 's/hello/hi/I'
hi
# 写入文件(原地编辑)
$ sed -i 's/old/new/g' file.txt
# 原地编辑(创建备份)
$ sed -i.bak 's/old/new/g' file.txt
8.3.2 删除和插入
# 删除行
$ sed '3d' file.txt # 删除第 3 行
$ sed '2,5d' file.txt # 删除 2-5 行
$ sed '/^#/d' file.txt # 删除注释行
$ sed '/^$/d' file.txt # 删除空行
# 插入行
$ sed '1i\New first line' file.txt
$ sed '$a\New last line' file.txt
# 替换行
$ sed '3c\New line 3' file.txt
8.3.3 高级用法
# 多命令
$ sed -e 's/foo/bar/' -e 's/baz/qux/' file.txt
# 地址范围
$ sed '10,20s/old/new/g' file.txt # 只在 10-20 行替换
# 条件执行
$ sed '/pattern/s/old/new/g' file.txt
# 提取行
$ sed -n '10,20p' file.txt # 打印 10-20 行
# 引用匹配
$ echo "hello" | sed 's/\(hel\)lo/\1p/'
helpp
# 变量替换
$ NEW="world"
$ sed "s/hello/$NEW/" file.txt
8.3.4 配置文件编辑示例
# 修改配置文件
$ sed -i 's/^#DNS=.*/DNS=8.8.8.8/' /etc/systemd/resolved.conf
# 在行前添加
$ sed -i '/^\[mysqld\]/a\max_connections=100' /etc/my.cnf
# 删除配置项
$ sed -i '/^old_setting/d' /etc/config.conf
# 取消注释
$ sed -i 's/^#\(option\)/\1/' config.txt
8.4 文本处理:awk
8.4.1 基本用法
# 打印特定字段
$ echo "hello world" | awk '{print $1}'
hello
$ cat /etc/passwd | awk -F: '{print $1, $3}'
root 0
nobody 65534
# 打印所有字段
$ echo "a b c" | awk '{print $0}'
a b c
$ echo "a b c" | awk '{print NR, NF}'
1 3
8.4.2 模式匹配
# 匹配模式
$ awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/sh
# 条件过滤
$ awk -F: '$3 == 0 {print $1}' /etc/passwd
root
# 大小比较
$ awk -F: '$3 >= 1000 {print $1}' /etc/passwd
8.4.3 字段分隔
# 指定分隔符
$ awk -F: '{print $1}' /etc/passwd
# 多分隔符
$ echo "a:b-c" | awk -F '[:\-]' '{print $1, $2, $3}'
a b c
# 输出分隔符
$ awk -F: -v OFS=',' '{print $1, $3}' /etc/passwd
root,0
8.4.4 变量和计算
# 内置变量
# NR - 当前行号
# NF - 当前行字段数
# FS - 输入分隔符
# OFS - 输出分隔符
# 求和
$ echo -e "1\n2\n3" | awk '{sum+=$1} END {print sum}'
6
# 统计行数
$ awk 'END {print NR}' /etc/passwd
# 最大值
$ echo -e "3\n1\n4\n1\n5" | awk 'max < $1 {max=$1} END {print max}'
5
8.4.5 实用脚本
# 格式化磁盘使用
$ df -h | awk 'NR>1 {printf "%-20s %s\n", $5, $6}'
# 统计日志中的错误
$ awk '/error/i {count++} END {print "Errors:", count}' /var/log/messages
# 提取 IP 地址
$ awk '/inet / {print $2}' /proc/net/tcp
# 处理 CSV
$ awk -F, '{print $2}' data.csv
# 条件求和
$ awk '$1 > 100 {sum+=$2} END {print sum}' data.txt
8.5 归档工具:tar
8.5.1 基本操作
# 创建归档
$ tar cf archive.tar /tmp/files/
# 创建 gzip 压缩归档
$ tar czf archive.tar.gz /tmp/files/
# 创建 bzip2 压缩归档
$ tar cjf archive.tar.bz2 /tmp/files/
# 创建 xz 压缩归档
$ tar cJf archive.tar.xz /tmp/files/
# 解压归档
$ tar xf archive.tar
$ tar xzf archive.tar.gz
$ tar xjf archive.tar.bz2
$ tar xJf archive.tar.xz
# 解压到指定目录
$ tar xzf archive.tar.gz -C /tmp/extract/
8.5.2 高级用法
# 查看归档内容
$ tar tzf archive.tar.gz
# 排除文件
$ tar czf backup.tar.gz --exclude='*.log' /var/
# 使用排除列表
$ cat exclude.txt
*.log
*.tmp
cache/
$ tar czf backup.tar.gz -X exclude.txt /var/
# 增量备份
$ tar czf backup-full.tar.gz -g /tmp/snapshot /var/
$ tar czf backup-incr.tar.gz -g /tmp/snapshot /var/
# 保留权限和符号链接
$ tar czpf backup.tar.gz --same-owner /etc/
8.5.3 cpio(initramfs)
# 创建 cpio 归档(initramfs 必用)
$ cd rootfs
$ find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz
# 解压 cpio
$ mkdir extract && cd extract
$ zcat ../initramfs.cpio.gz | cpio -idmv
# BusyBox cpio 支持的格式
# newc - 新 ASCII 格式(initramfs 标准)
# odc - POSIX.1 兼容格式
8.6 压缩工具
8.6.1 gzip / gunzip
# 压缩文件
$ gzip file.txt # 产生 file.txt.gz,删除原文件
$ gzip -k file.txt # 保留原文件
$ gzip -9 file.txt # 最高压缩率
# 解压
$ gunzip file.txt.gz
# 查看压缩文件
$ zcat file.txt.gz # 不解压直接查看
$ zless file.txt.gz # 分页查看
$ zgrep "pattern" file.txt.gz # 搜索压缩文件
8.6.2 bzip2 / bunzip2
# 压缩
$ bzip2 file.txt
$ bzip2 -k file.txt # 保留原文件
$ bzip2 -9 file.txt # 最高压缩率
# 解压
$ bunzip2 file.txt.bz2
# 查看
$ bzcat file.txt.bz2
8.6.3 xz / unxz
# 压缩(压缩率最高)
$ xz file.txt
$ xz -k file.txt
$ xz -9 file.txt # 最高压缩率
# 解压
$ unxz file.txt.xz
# 查看
$ xzcat file.txt.xz
8.6.4 压缩工具对比
| 工具 | 压缩率 | 速度 | 扩展名 |
|---|
| gzip | 低 | 快 | .gz |
| bzip2 | 中 | 较慢 | .bz2 |
| xz | 高 | 慢 | .xz |
| lz4 | 低 | 极快 | .lz4 |
| zstd | 高 | 快 | .zst |
8.7 文本处理工具集
8.7.1 cut — 字段提取
# 按分隔符提取字段
$ cut -d: -f1 /etc/passwd # 提取第 1 字段
$ cut -d: -f1,3 /etc/passwd # 提取第 1 和第 3 字段
# 按字符位置提取
$ cut -c1-5 file.txt # 提取前 5 个字符
# 按字节提取
$ cut -b1-10 file.txt
8.7.2 sort — 排序
# 字母排序
$ sort file.txt
# 数值排序
$ sort -n numbers.txt
# 反向排序
$ sort -r file.txt
# 去重
$ sort -u file.txt
# 按字段排序
$ sort -t: -k3 -n /etc/passwd
# 忽略大小写
$ sort -f file.txt
8.7.3 uniq — 去重
# 去除相邻重复行(通常配合 sort 使用)
$ sort file.txt | uniq
# 统计重复次数
$ sort file.txt | uniq -c
# 只显示重复行
$ sort file.txt | uniq -d
# 只显示唯一行
$ sort file.txt | uniq -u
8.7.4 tr — 字符转换
# 大小写转换
$ echo "hello" | tr 'a-z' 'A-Z'
HELLO
# 删除字符
$ echo "hello 123" | tr -d '0-9'
hello
# 压缩空格
$ echo "hello world" | tr -s ' '
hello world
# 替换字符
$ echo "hello" | tr 'l' 'r'
herro
8.7.5 wc — 统计
# 统计行数
$ wc -l /etc/passwd
# 统计字数
$ wc -w file.txt
# 统计字节数
$ wc -c file.txt
# 综合统计
$ wc file.txt
10 20 100 file.txt
8.7.6 diff — 比较文件
# 比较两个文件
$ diff file1.txt file2.txt
# 并排显示
$ diff -y file1.txt file2.txt
# 统一格式
$ diff -u file1.txt file2.txt
# 比较目录
$ diff -r dir1/ dir2/
8.7.7 head / tail — 首尾显示
# 显示前 N 行
$ head -20 /etc/passwd
# 显示后 N 行
$ tail -20 /var/log/messages
# 实时跟踪文件
$ tail -f /var/log/messages
# 显示从第 N 行开始
$ tail -n +10 /etc/passwd
8.8 其他工具
8.8.1 dd — 数据复制
# 创建文件
$ dd if=/dev/zero of=file bs=1M count=10
# 备份磁盘
$ dd if=/dev/sda of=/tmp/disk.img bs=4M
# 写入镜像
$ dd if=rootfs.img of=/dev/sdb bs=4M
# 显示进度
$ dd if=/dev/zero of=file bs=1M count=100 status=progress
8.8.2 xargs — 参数传递
# 基本用法
$ find /tmp -name "*.log" | xargs rm
# 处理空格
$ find /tmp -name "*.log" -print0 | xargs -0 rm
# 限制每次参数数量
$ cat list.txt | xargs -n 5 echo
# 使用占位符
$ find /tmp -name "*.txt" | xargs -I {} cp {} /backup/
8.9 本章小结
| 工具 | 用途 | 关键选项 |
|---|
| find | 文件查找 | -name, -type, -exec |
| grep | 文本搜索 | -i, -r, -E, -v |
| sed | 流编辑 | s/old/new/g, -i, -e |
| awk | 文本处理 | -F, {print}, END |
| tar | 归档 | czf, xzf, -C |
| cut | 字段提取 | -d, -f, -c |
| sort | 排序 | -n, -r, -u |
| tr | 字符转换 | a-z:A-Z, -d, -s |
扩展阅读
上一章: 第 7 章 — ash Shell
下一章: 第 9 章 — 系统工具