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