我们有时需要将多个独立的目录各自打包成压缩包,以便按需传输或备份。本文介绍一套专业的 Linux 命令方案,涵盖从基础到进阶的各种场景,并给出可直接使用的脚本模板。
1. 基础需求:逐个压缩子文件夹
若当前目录下存在多个子文件夹(如 project_a/, project_b/, data/ 等),希望将它们各自压缩为独立的 .tar.gz,且文件名加上自定义前缀(例如 www_),可用以下 for 循环实现:
for dir in */; do
# 去掉末尾的斜杠,得到纯目录名
dirname="${dir%/}"
# 打包压缩,文件名格式:前缀 + 目录名 + .tar.gz
tar czvf "www_${dirname}.tar.gz" "$dir"
done
*/会匹配当前目录下的所有子目录(不包含文件)。dirname="${dir%/}"用于去除末尾的/,得到干净的目录名。tar czvf创建压缩包,z表示 gzip 压缩,v显示过程,f指定文件名。
执行后,会生成类似 www_project_a.tar.gz、www_project_b.tar.gz 等文件。
2. 指定压缩目标(避免压缩所有目录)
如果只想压缩指定的几个目录,可以显式列出目录名(或使用数组):
dirs=("project_a" "project_b" "data")
for dir in "${dirs[@]}"; do
tar czvf "www_${dir}.tar.gz" "./$dir"
done
3. 高级选项:排除某些子目录
有些目录(如 cache/、tmp/、*.git)不需要打包,可在 tar 命令中添加 --exclude 选项:
for dir in */; do
dirname="${dir%/}"
tar czvf "www_${dirname}.tar.gz" \
--exclude="$dirname/cache" \
--exclude="$dirname/tmp" \
--exclude="*.git" \
"$dir"
done
注意:
--exclude的模式是相对于打包根目录的,且支持通配符。
4. 使用 find 动态获取目录列表(更灵活)
若目录名不符合简单通配,或需要过滤条件(如只压缩修改时间在 7 天内的目录),可以借助 find:
find . -maxdepth 1 -type d ! -name "." -mtime -7 | while read -r dir; do
dirname=$(basename "$dir")
tar czvf "www_${dirname}.tar.gz" "$dir"
done
-maxdepth 1只查找当前目录下的直接子目录。! -name "."排除当前目录本身。-mtime -7只处理 7 天内修改过的目录(可按需修改)。
5. 并行压缩加速(利用多核 CPU)
当目录数量多或数据量大时,串行压缩可能较慢。可使用 GNU Parallel 或 xargs 并行执行 tar,大幅提升速度。
5.1 使用 parallel
# 安装 parallel(若未安装)
sudo apt install parallel # Debian/Ubuntu
sudo yum install parallel # CentOS/RHEL
# 并行压缩
ls -d */ | parallel 'dir={}; dirname={%/}; tar czvf "www_${dirname}.tar.gz" "$dir"'
5.2 使用 xargs -P
ls -d */ | xargs -P 4 -I {} sh -c 'dir={}; dirname=${dir%/}; tar czvf "www_${dirname}.tar.gz" "$dir"'
-P 4表示同时运行 4 个压缩进程,可根据 CPU 核心数调整。
6. 保存日志与错误处理
压缩过程可能产生大量输出,建议将标准输出和错误分别记录:
for dir in */; do
dirname="${dir%/}"
tar czvf "www_${dirname}.tar.gz" "$dir" \
> "logs/${dirname}.log" 2>&1
done
提前创建 logs/ 目录,以便追踪每个包的压缩详情。
7. 校验压缩包完整性
压缩完成后,建议校验每个包是否可正常读取,避免损坏:
for tarfile in www_*.tar.gz; do
if tar tzf "$tarfile" > /dev/null 2>&1; then
echo "$tarfile OK"
else
echo "$tarfile CORRUPTED" >&2
fi
done
也可生成 MD5 校验文件供后续比对:
md5sum www_*.tar.gz > checksums.md5
8. 清理原始文件夹(可选)
若确认压缩包无误,且原始目录不再需要,可删除它们(慎用!):
# 先确认压缩包存在且可读,再删除原目录
for dir in */; do
dirname="${dir%/}"
if [ -f "www_${dirname}.tar.gz" ]; then
rm -rf "$dir"
fi
done
9. 一键脚本:综合示例
将上述功能整合为一个 Bash 脚本 batch_tar.sh,支持参数化前缀、排除模式、并行数等:
#!/bin/bash
# 批量压缩子目录为独立的 tar.gz
PREFIX="www_"
EXCLUDE_PATTERNS=("cache" "tmp" "*.log")
PARALLEL_JOBS=2
# 获取目录列表(排除隐藏目录)
dirs=( $(ls -d */ 2>/dev/null | sed 's|/$||') )
if [ ${#dirs[@]} -eq 0 ]; then
echo "No subdirectories found."
exit 1
fi
compress_dir() {
local dir=$1
local tarfile="${PREFIX}${dir}.tar.gz"
local exclude_opts=()
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
exclude_opts+=(--exclude="${dir}/${pattern}")
done
echo "Compressing $dir -> $tarfile"
tar czf "$tarfile" "${exclude_opts[@]}" "$dir"
}
export -f compress_dir
export PREFIX EXCLUDE_PATTERNS
# 并行执行
printf "%s\n" "${dirs[@]}" | xargs -P "$PARALLEL_JOBS" -I {} bash -c 'compress_dir "$@"' _ {}
echo "All done."
赋予执行权限并运行:
chmod +x batch_tar.sh
./batch_tar.sh
10. 进阶:使用 pigz 加速压缩
默认的 gzip 是单线程,可用 pigz(并行 gzip)替代,在多核服务器上显著提速。配合 tar 使用:
# 安装 pigz
sudo apt install pigz # Debian/Ubuntu
# 压缩时调用 pigz
tar -I pigz -cvf "www_${dirname}.tar.gz" "$dir"
注意:-I pigz 指定压缩程序,输出文件后缀仍为 .tar.gz 但实际是 pigz 压缩。
总结
| 需求 | 推荐命令 |
|---|---|
| 基本批量压缩 | for dir in */; do tar czvf "前缀${dir%/}.tar.gz" "$dir"; done |
| 指定目录列表 | 使用数组或显式列表 |
| 排除某些子目录 | --exclude 选项 |
| 并行加速 | parallel 或 xargs -P |
| 压缩后校验 | tar tzf 测试 |
| 极速压缩(多核) | 配合 pigz |

评论