批量文件处理:重命名、转换、压缩 | Batch File Processing: Rename, Convert, Compress
章节概述
核心理念:批量文件处理是 Bash 最能体现效率优势的场景——用一行命令处理成百上千个文件,替代手动逐个操作。这类似于 C 语言中用循环遍历文件数组并调用处理函数,但更加简洁高效。
第1节:find + xargs 批量操作
1.1 find 与 xargs 的配合
find 负责定位文件,xargs 负责将结果传递给命令执行,两者配合是批量处理的基础。
# 查找并删除所有 .tmp 文件
find . -name "*.tmp" -type f | xargs rm -f
# 安全删除(处理文件名含空格的情况)
find . -name "*.tmp" -type f -print0 | xargs -0 rm -f
# 批量压缩日志文件
find /var/log -name "*.log" -mtime +1 -type f | xargs gzip
# 统计所有 .py 文件的总行数
find . -name "*.py" -type f | xargs wc -l
# 批量设置权限
find . -type f -name "*.sh" | xargs chmod +x| 参数 | 说明 |
|---|---|
-print0 | 用 null 字符分隔输出(处理特殊文件名) |
-0 | xargs 以 null 字符为分隔符 |
-I {} | 指定替换占位符 |
-n N | 每次传递 N 个参数 |
-P N | 并行执行 N 个进程 |
1.2 并行执行
# 并行压缩(使用 4 个 CPU 核心)
find . -name "*.log" -type f | xargs -P4 -I{} gzip {}
# 并行下载多个文件
cat urls.txt | xargs -P5 -I{} wget -q {}
# 并行处理图像(使用 ImageMagick)
find . -name "*.png" -type f | xargs -P4 -I{} convert {} -resize 50% small_{}第2节:rename 批量重命名
2.1 rename 命令
rename 是批量重命名的利器,支持正则表达式。
# 将空格替换为下划线
rename 's/ /_/g' *.txt
# 将所有 .jpeg 改为 .jpg
rename 's/\.jpeg$/.jpg/' *.jpeg
# 添加前缀
rename 's/^/prefix_/' *.csv
# 添加后缀(在扩展名前)
rename 's/(\.[^.]+)$/_modified$1/' *.dat
# 转为小写
rename 'y/A-Z/a-z/' *.TXT
# 去除文件名中的特殊字符
rename 's/[^a-zA-Z0-9._-]//g' *2.2 循环重命名
# 顺序编号重命名
i=1; for f in *.jpg; do mv "$f" "photo_$(printf '%03d' $i).jpg"; ((i++)); done
# 按日期重命名
for f in *.txt; do
date_str=$(stat -c %y "$f" | cut -d' ' -f1)
mv "$f" "${date_str}_${f}"
done
# 批量替换空格为下划线
for f in *\ *; do
mv "$f" "${f// /_}"
done第3节:批量转换
3.1 图片批量转换
# 使用 ImageMagick 批量转换格式
for f in *.png; do convert "$f" "${f%.png}.jpg"; done
# 批量调整大小
mogrify -resize 800x600 *.jpg
# 批量添加水印
for f in *.jpg; do
composite -dissolve 30 -gravity southeast watermark.png "$f" "wm_$f"
done
# 批量压缩质量
mogrify -quality 80 *.jpg3.2 文档批量转换
# 批量转换 Markdown 为 HTML(使用 pandoc)
find . -name "*.md" -type f | xargs -I{} pandoc {} -o "${md%.md}.html"
# 批量转换 CSV 为 JSON(使用 jq)
for f in *.csv; do
header=$(head -1 "$f")
tail -n +2 "$f" | awk -F',' -v h="$header" 'BEGIN {split(h,a,",")} {printf "{"; for(i=1;i<=NF;i++) printf "\"%s\":\"%s\",", a[i], $i; print "}"}' > "${f%.csv}.json"
done
# 批量转换编码
find . -name "*.txt" -exec file {} \; | grep -i "iso-8859" | cut -d: -f1 | xargs -I{} iconv -f ISO-8859-1 -t UTF-8 {} -o "utf8_{}"第4节:压缩与归档
4.1 tar 归档
# 创建 tar.gz 归档
tar -czf archive.tar.gz /path/to/directory
# 创建 tar.bz2 归档(压缩率更高)
tar -cjf archive.tar.bz2 /path/to/directory
# 创建 tar.xz 归档(最高压缩率)
tar -cJf archive.tar.xz /path/to/directory
# 解压 tar.gz
tar -xzf archive.tar.gz
# 查看归档内容(不解压)
tar -tzf archive.tar.gz
# 解压到指定目录
tar -xzf archive.tar.gz -C /target/directory
# 增量归档
tar -czf backup_$(date +%Y%m%d).tar.gz --newer-mtime="2026-08-20" /data4.2 gzip 与 bzip2
# gzip 压缩(原文件被替换)
gzip file.txt # 生成 file.txt.gz
gzip -k file.txt # 保留原文件
# gzip 解压
gunzip file.txt.gz
# bzip2 压缩(压缩率更高,速度更慢)
bzip2 file.txt # 生成 file.txt.bz2
bzip2 -k file.txt # 保留原文件
# xz 压缩(最高压缩率)
xz file.txt # 生成 file.txt.xz
xz -k file.txt # 保留原文件
# 批量压缩所有日志
find /var/log -name "*.log" -type f -exec gzip {} \;| 工具 | 压缩率 | 速度 | 适用场景 |
|---|---|---|---|
gzip | 中等 | 快 | 日常使用、网络传输 |
bzip2 | 高 | 慢 | 需要高压缩率 |
xz | 最高 | 最慢 | 归档存储 |
zstd | 高 | 快 | 现代场景、备份 |
第5节:C 文件操作对比
Bash 的文件操作与 C 语言的文件 I/O 有直接的对应关系:
// C 语言文件操作
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "r");
char line[256];
while (fgets(line, sizeof(line), fp)) {
printf("%s", line);
}
fclose(fp);
return 0;
}# Bash 等价操作
while IFS= read -r line; do
echo "$line"
done < data.txt
# 或使用 cat
cat data.txt
# 或使用 while + process substitution
while read -r line; do
echo "$line"
done < <(cat data.txt)| C 文件操作 | Bash 等价操作 |
|---|---|
fopen() | < file 或 cat file |
fgets() | read -r line |
fputs() | echo "$line" > file |
fprintf() | printf "%s\n" "$line" > file |
fclose() | 无需显式关闭 |
fseek() | 无需(流式处理) |
rewind() | 重新读取重定向 |
第6节:实战案例
6.1 批量清理项目
#!/bin/bash
# 批量清理脚本:删除编译产物、压缩旧日志、重命名备份
# 删除所有 __pycache__ 目录
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null
# 删除 .pyc 文件
find . -name "*.pyc" -delete
# 压缩 7 天前的日志
find /var/log/myapp -name "*.log" -mtime +7 -exec gzip {} \;
# 重命名备份文件(添加日期前缀)
for f in backup_*.tar.gz; do
mv "$f" "$(date +%Y%m%d)_$f"
done
echo "Cleanup completed at $(date)"6.2 批量文件信息收集
#!/bin/bash
# 收集目录下所有文件的信息
echo "文件名,大小(bytes),修改时间,权限" > file_info.csv
find . -type f -printf "%f,%s,%T+,%m\n" | sort >> file_info.csv
# 统计各类型文件数量
echo ""
echo "=== 文件类型统计 ==="
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -10
# 统计总大小
echo ""
echo "=== 目录大小统计 ==="
du -sh */ 2>/dev/null | sort -rh6.3 批量编码转换
#!/bin/bash
# 批量将 Windows 编码文件转换为 UTF-8
for f in *.txt; do
encoding=$(file -bi "$f" | grep -oP 'charset=\K[^ ]+')
if [ "$encoding" != "utf-8" ] && [ "$encoding" != "us-ascii" ]; then
echo "Converting $f from $encoding to UTF-8"
iconv -f "$encoding" -t UTF-8 "$f" > "${f}.utf8" && mv "${f}.utf8" "$f"
fi
done
echo "All files converted to UTF-8"