Linux cpio命令

功能说明:cpio(Copy In and Out)命令用于创建、提取和管理归档文件,支持多种格式。它是最古老的Unix归档工具之一,常用于系统备份、软件包制作和文件传输。
主要功能
  • 创建归档文件(copy-out模式)
  • 从归档中提取文件(copy-in模式)
  • 文件列表传递(copy-pass模式)
  • 处理特殊文件(设备文件、符号链接等)
  • 支持多卷备份
  • 保持文件属性和权限
三种操作模式
  • -o copy-out:从文件列表创建归档
  • -i copy-in:从归档提取文件
  • -p copy-pass:复制文件到目录
  • 默认支持多种格式:binary, old ASCII, new ASCII, crc, tar, ustar, hpbin, hpodc

命令语法

语法格式
# copy-out模式:创建归档
ls [文件列表] | cpio -o [选项] > 归档文件
find 目录 -print | cpio -o [选项] > 归档文件

# copy-in模式:提取归档
cpio -i [选项] [模式] < 归档文件

# copy-pass模式:复制文件
find 目录 -print | cpio -p 目标目录 [选项]

命令参数

参数 说明
-o, --create copy-out模式,从标准输入读取文件名列表创建归档
-i, --extract copy-in模式,从标准输入读取归档文件并提取文件
-p, --pass-through copy-pass模式,从标准输入读取文件名并复制到指定目录
-t, --list 列出归档文件内容(与-i一起使用)
-v, --verbose 显示详细处理信息
-d, --make-directories 必要时创建目录(自动创建目标目录)
-u, --unconditional 无条件覆盖已存在的文件(不询问)
-m, --preserve-modification-time 保留文件修改时间
-B 设置块大小为5120字节(提高I/O效率)
-H format 指定归档格式(bin, odc, newc, crc, tar, ustar等)
-R, --owner [user][:.][group] 设置文件所有者和组(需root权限)
-l, --link 必要时创建硬链接而非复制文件(copy-pass模式)
-L, --dereference 跟随符号链接(复制链接指向的文件)
-r, --rename 交互式重命名文件
-V, --dot 显示处理进度(每处理一个文件显示一个点)
-F, --file=归档文件 指定归档文件名(替代标准输入/输出)
-O 归档文件 输出到指定归档文件(-o模式)
-I 归档文件 从指定归档文件读取(-i模式)

使用示例

1. 创建归档文件(copy-out模式)常用
示例
# 创建当前目录下所有文件的归档
find . -depth -print | cpio -o > archive.cpio

# 创建指定文件的归档
ls file1.txt file2.txt dir1/ | cpio -o > files.cpio

# 创建指定目录的归档
find /path/to/dir -print | cpio -o > dir_archive.cpio

# 创建归档并压缩
find . -print | cpio -o | gzip > backup.cpio.gz

# 创建归档并显示详细信息
find . -print | cpio -ov > archive.cpio

# 指定归档格式
find . -print | cpio -o -H tar > archive.tar

# 使用大块大小提高效率
find . -print | cpio -oB > archive.cpio

# 创建归档文件时排除特定文件
find . -name "*.tmp" -prune -o -print | cpio -o > archive.cpio
2. 提取归档文件(copy-in模式)
# 提取归档中的所有文件
cpio -i < archive.cpio

# 提取归档并显示详细信息
cpio -iv < archive.cpio

# 提取归档到指定目录
mkdir extracted
cd extracted
cpio -i < ../archive.cpio

# 提取特定文件
cpio -i "*.txt" < archive.cpio
cpio -i file1.txt file2.txt < archive.cpio

# 提取归档并创建必要的目录
cpio -id < archive.cpio

# 保留文件修改时间
cpio -im < archive.cpio

# 无条件覆盖已存在的文件
cpio -iu < archive.cpio

# 从压缩归档提取
gzip -dc backup.cpio.gz | cpio -i

# 使用-F参数指定归档文件
cpio -i -F archive.cpio
cpio -i -I archive.cpio  # 等效
3. 列出归档内容
# 列出归档中的所有文件
cpio -it < archive.cpio

# 详细列出归档内容
cpio -itv < archive.cpio

# 列出归档文件信息
cpio -itv < archive.cpio | head -20

# 统计归档中的文件数
cpio -it < archive.cpio | wc -l

# 查找归档中的特定文件
cpio -it < archive.cpio | grep "\.txt$"

# 列出压缩归档的内容
gzip -dc backup.cpio.gz | cpio -it
4. 直接复制文件(copy-pass模式)
# 复制当前目录到目标目录
find . -depth -print | cpio -pd /backup/destination

# 复制并显示详细信息
find . -print | cpio -pdv /backup/destination

# 复制时创建必要的目录
find . -print | cpio -pdm /backup/destination

# 保留文件修改时间
find . -print | cpio -pdm /backup/destination

# 复制时使用硬链接(节省空间)
find . -print | cpio -pdl /backup/destination

# 复制特定类型的文件
find . -name "*.txt" -print | cpio -pd /backup/destination

# 复制时排除特定文件
find . -name "*.tmp" -prune -o -print | cpio -pd /backup/destination
5. 处理特殊文件
# 归档包含设备文件
find /dev -type b -o -type c -print | cpio -o > devices.cpio

# 归档符号链接(默认保存链接本身)
find /path -print | cpio -o > with_links.cpio

# 归档时跟随符号链接
find /path -print | cpio -oL > dereferenced.cpio

# 处理硬链接
find . -type f -links +1 -print | cpio -o > hardlinks.cpio

# 归档时保留文件所有者(需要root权限)
find . -print | cpio -o -R root:root > archive.cpio

# 归档时保留所有文件属性
find . -print | cpio -o --preserve-modification-time > archive.cpio
6. 高级用法示例
# 创建多卷备份(需要交互)
find /home -print | cpio -oB -F /dev/fd0
# 提示插入下一张软盘时按Enter继续

# 交互式重命名文件
cpio -ir < archive.cpio
# 对每个文件询问新文件名

# 备份系统配置文件
find /etc -type f -name "*.conf" -print | cpio -o > etc_conf.cpio

# 增量备份(结合find)
find /data -type f -mtime -1 -print | cpio -o > incremental.cpio

# 远程备份
find /important -print | cpio -o | ssh user@server "cat > /backup/remote.cpio"

# 从远程恢复
ssh user@server "cat /backup/remote.cpio" | cpio -i

# 验证归档完整性
cpio -itv -I archive.cpio 2>&1 | grep -E "(error|fail)" || echo "归档完整"
7. 实际工作场景
# 场景1:系统配置文件备份
#!/bin/bash
BACKUP_DIR="/backup/etc"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR"
find /etc -type f -name "*.conf" -print | \
    cpio -o | gzip > "$BACKUP_DIR/etc_conf_$DATE.cpio.gz"
echo "备份完成: $BACKUP_DIR/etc_conf_$DATE.cpio.gz"

# 场景2:网站数据迁移
#!/bin/bash
SOURCE="/var/www/html"
TARGET="/new/webroot"

# 复制网站数据,保留所有属性
find "$SOURCE" -print | cpio -pdmu "$TARGET"
echo "网站数据已从 $SOURCE 复制到 $TARGET"

# 场景3:清理临时文件备份
#!/bin/bash
BACKUP_FILE="/backup/tmp_cleanup_$(date +%Y%m%d).cpio"

# 备份/tmp目录中超过30天的文件
find /tmp -type f -mtime +30 -print | cpio -o > "$BACKUP_FILE"

# 删除备份过的文件
find /tmp -type f -mtime +30 -exec rm -f {} \;
echo "临时文件已备份到 $BACKUP_FILE 并清理"

cpio归档格式详解

格式 说明 文件头 兼容性 用途
bin 传统二进制格式(默认) 二进制 旧Unix系统 历史兼容
odc 旧ASCII格式(POSIX.1) ASCII(八进制) 广泛 跨系统交换
newc 新ASCII格式(SVR4) ASCII(十六进制) 广泛 initramfs
crc 带CRC校验的新ASCII格式 ASCII + CRC 广泛 数据完整性
tar tar兼容格式 tar格式 非常好 与tar兼容
ustar POSIX tar格式 ustar格式 优秀 标准兼容
hpbin HP-UX二进制格式 二进制 HP-UX HP-UX系统
hpodc HP-UX旧ASCII格式 ASCII HP-UX HP-UX跨系统
查看和转换归档格式
# 查看归档文件的格式
file archive.cpio
# 输出示例:archive.cpio: ASCII cpio archive (SVR4 with no CRC)

# 以不同格式创建归档
find . -print | cpio -o -H newc > newc.cpio
find . -print | cpio -o -H tar > archive.tar
find . -print | cpio -o -H ustar > archive.ustar

# 转换归档格式
cpio -i -I old.cpio 2>/dev/null | cpio -o -H newc > new.cpio

# 检查归档格式兼容性
cpio -it -H tar < archive.cpio 2>/dev/null && echo "支持tar格式" || echo "不支持tar格式"

# 查看归档格式详细信息
od -c archive.cpio | head -5
# 对于newc格式,文件头以"070701"开头
# 对于crc格式,文件头以"070702"开头
# 对于odc格式,文件头以"070707"开头

与tar命令对比

特性 cpio tar
历史 Unix V7 (1979年) Unix V7 (1979年)
设计理念 管道驱动,处理文件列表 直接处理文件和目录
易用性 较复杂 简单直观
灵活性 很高(支持复杂文件列表) 中等
处理特殊文件 优秀(设备文件、管道等) 良好
硬链接处理 保存和恢复硬链接 可能重复存储
RPM包格式 是(RPM使用cpio格式)
initramfs格式 是(使用newc格式)
流行度 系统级工具 非常流行
推荐用途 系统备份、软件包、initramfs 日常归档、压缩包分发
功能等价命令示例
# 创建归档
# cpio方式
find . -print | cpio -o > archive.cpio
# tar方式
tar -cf archive.tar .

# 提取归档
# cpio方式
cpio -i < archive.cpio
# tar方式
tar -xf archive.tar

# 列出归档内容
# cpio方式
cpio -it < archive.cpio
# tar方式
tar -tf archive.tar

# 压缩归档
# cpio + gzip
find . -print | cpio -o | gzip > archive.cpio.gz
# tar + gzip
tar -czf archive.tar.gz .

# 从归档提取特定文件
# cpio方式
cpio -i "*.txt" < archive.cpio
# tar方式
tar -xf archive.tar --wildcards "*.txt"

实际应用脚本

脚本1:完整的系统备份脚本
#!/bin/bash
# 使用cpio的完整系统备份脚本

BACKUP_ROOT="/backup"
BACKUP_DIR="$BACKUP_ROOT/system_backup_$(date +%Y%m%d_%H%M%S)"
EXCLUDE_FILE="$BACKUP_ROOT/exclude.list"
LOG_FILE="$BACKUP_ROOT/backup_$(date +%Y%m%d).log"
RETENTION_DAYS=30

# 创建备份目录
mkdir -p "$BACKUP_DIR"

echo "=== 系统备份脚本 ==="
echo "开始时间: $(date)"
echo "备份目录: $BACKUP_DIR"
echo "日志文件: $LOG_FILE"

# 定义要排除的目录和文件
cat > "$EXCLUDE_FILE" << 'EOF'
/proc
/sys
/dev
/tmp
/run
/mnt
/media
/lost+found
/backup
/var/cache
/var/tmp
/var/run
*.tmp
*.log
*.swp
EOF

# 记录开始
echo "备份开始: $(date)" >> "$LOG_FILE"

# 备份/etc目录(系统配置)
echo "备份 /etc 目录..."
find /etc -xdev -type f 2>/dev/null | \
    cpio -o -H newc 2>> "$LOG_FILE" | \
    gzip > "$BACKUP_DIR/etc.cpio.gz"
echo "/etc备份完成: $(ls -lh $BACKUP_DIR/etc.cpio.gz)" >> "$LOG_FILE"

# 备份/home目录(用户数据)
echo "备份 /home 目录..."
find /home -xdev -type f 2>/dev/null | \
    cpio -o -H newc 2>> "$LOG_FILE" | \
    gzip > "$BACKUP_DIR/home.cpio.gz"
echo "/home备份完成: $(ls -lh $BACKUP_DIR/home.cpio.gz)" >> "$LOG_FILE"

# 备份/var目录(可变数据)
echo "备份 /var 目录(排除缓存)..."
find /var -xdev -type f -path /var/cache -prune -o -print 2>/dev/null | \
    cpio -o -H newc 2>> "$LOG_FILE" | \
    gzip > "$BACKUP_DIR/var.cpio.gz"
echo "/var备份完成: $(ls -lh $BACKUP_DIR/var.cpio.gz)" >> "$LOG_FILE"

# 备份重要配置文件
echo "备份关键配置文件..."
IMPORTANT_FILES=(
    /etc/passwd
    /etc/group
    /etc/shadow
    /etc/fstab
    /etc/hosts
    /etc/resolv.conf
    /etc/ssh/sshd_config
    /etc/crontab
)

printf "%s\n" "${IMPORTANT_FILES[@]}" | \
    cpio -o -H newc 2>> "$LOG_FILE" | \
    gzip > "$BACKUP_DIR/important_files.cpio.gz"

# 创建备份清单
echo "创建备份清单..."
{
    echo "备份时间: $(date)"
    echo "主机名: $(hostname)"
    echo "备份内容:"
    echo "1. /etc目录"
    echo "2. /home目录"
    echo "3. /var目录(排除缓存)"
    echo "4. 关键配置文件"
    echo ""
    echo "各归档文件大小:"
    ls -lh "$BACKUP_DIR"/*.cpio.gz
    echo ""
    echo "各归档文件内容统计:"
    for archive in "$BACKUP_DIR"/*.cpio.gz; do
        echo -n "$(basename "$archive"): "
        gzip -dc "$archive" | cpio -it 2>/dev/null | wc -l
    done
} > "$BACKUP_DIR/backup_manifest.txt"

echo "备份清单: $BACKUP_DIR/backup_manifest.txt"

# 验证备份完整性
echo "验证备份完整性..."
for archive in "$BACKUP_DIR"/*.cpio.gz; do
    echo -n "验证 $(basename "$archive")... "
    if gzip -t "$archive" 2>/dev/null && gzip -dc "$archive" | cpio -it >/dev/null 2>&1; then
        echo "✓ 完整"
        echo "$(basename "$archive"): 验证通过" >> "$LOG_FILE"
    else
        echo "✗ 损坏"
        echo "$(basename "$archive"): 验证失败" >> "$LOG_FILE"
    fi
done

# 清理旧备份
echo "清理超过${RETENTION_DAYS}天的旧备份..."
find "$BACKUP_ROOT" -name "system_backup_*" -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \; 2>/dev/null
deleted_count=$(find "$BACKUP_ROOT" -name "system_backup_*" -type d -mtime +$RETENTION_DAYS 2>/dev/null | wc -l)
echo "删除 $deleted_count 个旧备份" >> "$LOG_FILE"

# 完成
echo "备份完成: $(date)" >> "$LOG_FILE"
echo ""
echo "=== 备份完成 ==="
echo "备份目录: $BACKUP_DIR"
echo "总大小: $(du -sh $BACKUP_DIR | cut -f1)"
echo "日志文件: $LOG_FILE"
echo "备份清单: $BACKUP_DIR/backup_manifest.txt"
脚本2:RPM包内容提取工具
#!/bin/bash
# RPM包内容提取工具(RPM使用cpio格式)

RPM_FILE="$1"
EXTRACT_DIR="$2"

if [ $# -lt 1 ]; then
    echo "用法: $0  [提取目录]"
    echo "示例: $0 package.rpm /tmp/extracted"
    exit 1
fi

if [ ! -f "$RPM_FILE" ]; then
    echo "错误: RPM文件不存在 - $RPM_FILE"
    exit 1
fi

# 设置提取目录
if [ -z "$EXTRACT_DIR" ]; then
    EXTRACT_DIR="${RPM_FILE%.rpm}_extracted"
fi

# 创建提取目录
mkdir -p "$EXTRACT_DIR"

echo "=== RPM包提取工具 ==="
echo "RPM文件: $RPM_FILE"
echo "提取目录: $EXTRACT_DIR"
echo "开始时间: $(date)"
echo ""

# 检查rpm2cpio是否可用
if ! command -v rpm2cpio &> /dev/null; then
    echo "错误: rpm2cpio命令未找到"
    echo "请安装rpm工具包:"
    echo "  Debian/Ubuntu: sudo apt install rpm2cpio"
    echo "  RHEL/CentOS: sudo yum install rpm"
    exit 1
fi

# 检查cpio是否可用
if ! command -v cpio &> /dev/null; then
    echo "错误: cpio命令未找到"
    exit 1
fi

# 提取RPM包信息
echo "获取RPM包信息..."
rpm -qip "$RPM_FILE" 2>/dev/null | tee "$EXTRACT_DIR/rpm_info.txt"
echo "RPM信息已保存到: $EXTRACT_DIR/rpm_info.txt"

# 列出RPM包内容
echo ""
echo "列出RPM包内容..."
rpm -qlp "$RPM_FILE" 2>/dev/null | tee "$EXTRACT_DIR/file_list.txt"
file_count=$(wc -l < "$EXTRACT_DIR/file_list.txt")
echo "文件总数: $file_count"

# 提取RPM包内容
echo ""
echo "提取RPM包内容到: $EXTRACT_DIR"
cd "$EXTRACT_DIR"
if rpm2cpio "$RPM_FILE" | cpio -idm --quiet; then
    echo "✓ 提取完成"
else
    echo "✗ 提取失败"
    exit 1
fi
cd - >/dev/null

# 验证提取的文件
echo ""
echo "验证提取的文件..."
extracted_count=$(find "$EXTRACT_DIR" -type f ! -name "*.txt" | wc -l)
echo "实际提取文件数: $extracted_count"

if [ "$file_count" -eq "$extracted_count" ]; then
    echo "✓ 文件数量匹配"
else
    echo "⚠ 文件数量不匹配 (清单: $file_count, 实际: $extracted_count)"
fi

# 显示提取结果
echo ""
echo "=== 提取完成 ==="
echo "提取目录: $EXTRACT_DIR"
echo "提取文件: $extracted_count 个"
echo "生成的文档:"
find "$EXTRACT_DIR" -name "*.txt" -exec ls -lh {} \;
echo ""
echo "提取的目录结构:"
ls -la "$EXTRACT_DIR" | head -20

# 可选:创建提取内容的压缩包
echo ""
read -p "是否创建提取内容的压缩包? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    TARBALL="${RPM_FILE%.rpm}_extracted.tar.gz"
    tar -czf "$TARBALL" -C "$(dirname "$EXTRACT_DIR")" "$(basename "$EXTRACT_DIR")"
    echo "压缩包已创建: $TARBALL"
fi
脚本3:initramfs创建和管理工具
#!/bin/bash
# initramfs创建和管理工具

# 配置
INITRAMFS_DIR="/tmp/initramfs_build"
OUTPUT_FILE="/boot/initramfs-$(uname -r).img"
KERNEL_VERSION=$(uname -r)
BUSYBOX_URL="https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64"

echo "=== initramfs创建工具 ==="
echo "内核版本: $KERNEL_VERSION"
echo "构建目录: $INITRAMFS_DIR"
echo "输出文件: $OUTPUT_FILE"
echo ""

# 清理旧目录
cleanup() {
    echo "清理构建目录..."
    rm -rf "$INITRAMFS_DIR"
}

# 错误处理
error_exit() {
    echo "错误: $1"
    cleanup
    exit 1
}

# 创建构建目录
echo "创建构建目录结构..."
cleanup
mkdir -p "$INITRAMFS_DIR"/{bin,sbin,etc,proc,sys,usr/{bin,sbin},dev,lib,lib64,mnt,root,tmp,var}
cd "$INITRAMFS_DIR" || error_exit "无法进入构建目录"

# 创建必要的设备文件
echo "创建设备文件..."
mkdir -p dev
sudo mknod dev/console c 5 1 2>/dev/null || echo "注意: 需要root权限创建设备文件"
sudo mknod dev/null c 1 3 2>/dev/null || echo "注意: 需要root权限创建设备文件"
sudo mknod dev/zero c 1 5 2>/dev/null || echo "注意: 需要root权限创建设备文件"

# 下载BusyBox(如果不存在)
if [ ! -f bin/busybox ]; then
    echo "下载BusyBox..."
    if command -v wget &> /dev/null; then
        wget -q -O bin/busybox "$BUSYBOX_URL" || error_exit "下载BusyBox失败"
    elif command -v curl &> /dev/null; then
        curl -s -o bin/busybox "$BUSYBOX_URL" || error_exit "下载BusyBox失败"
    else
        error_exit "需要wget或curl下载BusyBox"
    fi
    chmod +x bin/busybox
fi

# 创建BusyBox符号链接
echo "创建BusyBox符号链接..."
./bin/busybox --list-full | while read app; do
    app_name=$(basename "$app")
    if [ "$app_name" != "busybox" ]; then
        ln -s /bin/busybox "bin/$app_name" 2>/dev/null || true
    fi
done

# 创建init脚本
echo "创建init脚本..."
cat > init << 'EOF'
#!/bin/busybox sh

# 挂载必要的文件系统
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev

# 设置环境
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH

# 打印启动信息
echo "=========================================="
echo "           Initramfs 启动成功"
echo "=========================================="
echo "内核版本: $(uname -r)"
echo "主机名: $(hostname)"
echo "当前时间: $(date)"
echo ""

# 进入shell
echo "输入 'exit' 退出并继续启动过程"
echo "输入 'poweroff' 关机"
echo "=========================================="
exec /bin/sh
EOF

chmod +x init

# 创建initramfs镜像
echo "创建initramfs镜像..."
find . -print0 | cpio --null -ov --format=newc | gzip -9 > "$OUTPUT_FILE"

# 验证生成的initramfs
echo "验证initramfs镜像..."
if [ -f "$OUTPUT_FILE" ]; then
    file_size=$(stat -c%s "$OUTPUT_FILE")
    echo "✓ initramfs创建成功"
    echo "文件大小: $(numfmt --to=iec $file_size)"

    # 测试是否可以列出内容
    echo "测试镜像内容..."
    if gzip -dc "$OUTPUT_FILE" | cpio -it 2>/dev/null | grep -q "^init$"; then
        echo "✓ 镜像包含有效的init文件"
    else
        echo "⚠ 镜像中未找到init文件"
    fi
else
    error_exit "initramfs创建失败"
fi

# 清理构建目录
cleanup

echo ""
echo "=== initramfs创建完成 ==="
echo "输出文件: $OUTPUT_FILE"
echo "文件大小: $(ls -lh $OUTPUT_FILE | awk '{print $5}')"
echo ""
echo "使用方法:"
echo "1. 测试initramfs:"
echo "   sudo cp $OUTPUT_FILE /boot/"
echo "2. 编辑GRUB配置使用新的initramfs"
echo "3. 或使用kexec测试:"
echo "   sudo kexec -l /boot/vmlinuz-$KERNEL_VERSION --initrd=$OUTPUT_FILE --reuse-cmdline"
echo "   sudo kexec -e"
echo ""
echo "注意: 此initramfs仅包含基本功能,生产环境需要更多配置。"

注意事项

重要注意事项:
  • 路径安全性:cpio会严格按照提供的路径处理文件,可能覆盖系统文件,使用时需小心
  • 绝对路径:使用绝对路径创建归档时,提取时会覆盖相同路径的文件
  • 磁盘空间:确保有足够的磁盘空间进行归档和提取操作
  • 权限要求:提取归档时可能需要相应权限来创建文件和目录
  • 符号链接:默认情况下,cpio保存符号链接本身而非链接目标,使用-L跟随链接
  • 硬链接:cpio能正确处理硬链接,但tar可能重复存储硬链接文件
  • 特殊文件:处理设备文件等特殊文件需要root权限
  • 管道使用:cpio设计为与管道配合,可以方便地与其他命令组合
  • 兼容性:不同系统的cpio实现可能略有差异,跨系统使用时注意格式兼容性

常见问题

A: 各有优缺点,根据需求选择:
场景 推荐工具 原因
日常归档压缩 tar 语法简单,广泛支持,文档丰富
处理复杂文件列表 cpio 从标准输入读取文件列表,更灵活
RPM包处理 cpio RPM内部使用cpio格式
initramfs创建 cpio Linux内核使用cpio格式的initramfs
系统备份 cpio 更好的特殊文件处理,硬链接支持
软件分发 tar 用户更熟悉,跨平台兼容性好

实际建议:

  • 如果已经熟悉tar且需求简单,使用tar
  • 如果需要处理特殊场景(RPM、initramfs、复杂筛选),使用cpio
  • 两者都可以与压缩工具(gzip、bzip2、xz)配合使用

A: 可以尝试以下方法恢复损坏的cpio归档:
  • 使用-E参数:指定要提取的文件模式
  • 使用dd跳过损坏部分:如果知道损坏位置
  • 尝试不同格式:用不同格式参数尝试提取
  • 使用二进制编辑器:手动修复文件头
恢复示例:
# 方法1:尝试提取还能识别的文件
cpio -i -E "*.txt" < damaged.cpio 2>/dev/null

# 方法2:使用dd跳过损坏的头部
dd if=damaged.cpio of=partial.cpio bs=1 skip=100
cpio -i < partial.cpio 2>/dev/null

# 方法3:尝试不同格式
cpio -i -H newc < damaged.cpio 2>/dev/null
cpio -i -H odc < damaged.cpio 2>/dev/null
cpio -i -H bin < damaged.cpio 2>/dev/null

# 方法4:使用strings提取文本内容
strings damaged.cpio > recovered_text.txt

# 方法5:逐块尝试恢复
# 创建一个恢复脚本
#!/bin/bash
ARCHIVE="damaged.cpio"
OUTPUT_DIR="recovered"
mkdir -p "$OUTPUT_DIR"

# 尝试从不同偏移开始提取
for offset in {0..1000..100}; do
    echo "尝试偏移: $offset"
    dd if="$ARCHIVE" of="temp_$offset.cpio" bs=1 skip=$offset 2>/dev/null
    if cpio -i -d < "temp_$offset.cpio" 2>/dev/null; then
        echo "✓ 偏移 $offset 成功"
        mv temp_$offset.cpio "$OUTPUT_DIR/success_$offset.cpio"
    fi
    rm -f "temp_$offset.cpio"
done

A: RPM(Red Hat Package Manager)使用cpio格式有几个重要原因:
  • 历史原因:RPM最初基于cpio开发,保持了向后兼容
  • 特殊文件支持:cpio能更好地处理设备文件、符号链接等
  • 硬链接处理:cpio能正确保存和恢复硬链接关系
  • 元数据支持:cpio能保存完整的文件属性(权限、所有者、时间戳)
  • 流式处理:cpio的管道友好设计适合包管理器的工作流
RPM包内部结构:
# 查看RPM包结构
rpm -qip package.rpm      # 查看包信息
rpm -qlp package.rpm      # 查看包文件列表
rpm2cpio package.rpm      # 转换为cpio流

# RPM包实际是一个cpio归档
# 结构:
# 1. 引导程序(可选)
# 2. 签名字段
# 3. 头部(包含元数据)
# 4. 载荷(cpio格式的归档文件)

# 手动提取RPM包
rpm2cpio package.rpm | cpio -idmv

# 创建简单的RPM包
# 1. 准备文件
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
# 2. 创建spec文件
# 3. 打包文件为cpio格式
# 4. 添加RPM头部信息

# 查看RPM包中的cpio归档
rpm2cpio package.rpm | cpio -itv | head -20

# RPM包使用gzip压缩的cpio归档
# 可以手动解压查看
rpm2cpio package.rpm > package.cpio
file package.cpio
# 输出:package.cpio: ASCII cpio archive

虽然tar现在也很强大,但RPM由于历史原因和cpio的特殊优势,继续使用cpio格式。

相关命令

tar

更常用的归档工具:

tar -cf archive.tar files/
tar -xf archive.tar
tar -czf archive.tar.gz files/
tar -tzf archive.tar.gz
rpm2cpio

RPM包转换工具:

rpm2cpio package.rpm
rpm2cpio package.rpm | cpio -idv
rpm -qil package.rpm
rpm -ivh package.rpm
find

文件查找工具(常与cpio配合):

find . -name "*.txt" -print
find /etc -type f -print
find . -mtime -7 -print
find . -size +1M -print
压缩工具

与cpio配合的压缩工具:

gzip -c file > file.gz
bzip2 -c file > file.bz2
xz -c file > file.xz
find . -print | cpio -o | gzip > backup.cpio.gz