Linux pax命令 详解

pax(Portable Archive eXchange)是一个跨平台的文件归档和交换工具,支持多种归档格式,可以在不同系统间传输文件,同时保留文件属性和权限。

基本介绍

pax命令特点

pax是一个功能强大的归档工具:

  • 支持多种归档格式(tar, cpio等)
  • 跨平台兼容性好
  • 支持文件属性和权限保留
  • 支持增量备份
  • 可以创建、提取、列出归档内容
  • 支持目录树复制
与tar的区别
特性 pax tar
跨平台兼容性 优秀 良好
格式支持 多种格式 主要tar格式
标准支持 POSIX标准 非标准
使用复杂度 较高 较低

基本语法

pax [选项] [操作模式] [文件...]

# 三种基本操作模式:
# -r 读取模式(提取归档)
# -w 写入模式(创建归档)
# -r -w 复制模式(复制文件)

# 示例
pax -wf archive.tar file1 file2       # 创建归档
pax -rf archive.tar                   # 提取归档
pax -rw dir1 dir2                     # 复制目录树

常用选项

选项 说明
-r 读取模式(从归档提取文件)
-w 写入模式(创建归档文件)
-f 文件 指定归档文件名(默认为标准输入/输出)
-v 详细模式(显示处理文件)
-x 格式 指定归档格式(如cpio, ustar, tar等)
-a 追加文件到现有归档
-c 匹配除指定模式外的所有文件
-d 仅匹配目录本身,不包含其内容
-p 权限 保留指定的文件属性(如mtime, atime等)
-s 替换表达式 文件名替换(类似sed的s命令)
-t 保留文件访问时间
-u 仅复制比目标新的文件
-z 使用gzip压缩/解压(归档格式为tar时)
-j 使用bzip2压缩/解压
-o 选项 归档格式特定选项

归档模式详解

写入模式 (-w)

创建归档文件:

  • 从标准输入或文件列表读取
  • 创建归档文件
  • 支持多种归档格式
  • 可以保留文件属性
  • 支持增量备份
读取模式 (-r)

提取归档文件:

  • 从归档文件读取
  • 提取到当前目录或指定目录
  • 支持选择性提取
  • 可以保留文件属性
  • 支持文件重命名
复制模式 (-rw)

复制文件树:

  • 复制目录树结构
  • 保留文件属性
  • 类似cp -r但功能更强
  • 支持增量复制
  • 可以跨文件系统

创建和提取归档

创建归档文件
# 1. 基本创建归档
pax -wf archive.tar file1 file2       # 创建tar归档
pax -wf archive.tar *                 # 归档当前目录所有文件

# 2. 使用特定格式
pax -x cpio -wf archive.cpio file1 file2  # 创建cpio格式
pax -x ustar -wf archive.ustar .          # 创建ustar格式

# 3. 使用压缩
pax -wf archive.tar.gz -z file1 file2     # 创建gzip压缩的tar
pax -wf archive.tar.bz2 -j file1 file2    # 创建bzip2压缩的tar

# 4. 详细模式查看过程
pax -vwf archive.tar file1 file2 dir1/

# 5. 从标准输入读取文件列表
find . -name "*.txt" | pax -wf textfiles.tar

# 6. 排除特定文件
find . -type f ! -name "*.tmp" | pax -wf notmp.tar

# 7. 保留文件属性
pax -wf archive.tar -p e file1 file2      # 保留所有属性

# 8. 创建增量备份(基于时间戳)
pax -wf backup.tar -T 20230101000000 .   # 备份指定时间后的文件

# 9. 归档到远程服务器(通过ssh)
pax -wf - . | ssh user@host 'cat > backup.tar'

# 10. 分卷归档
pax -wf - . | split -b 100M - backup.tar.part
提取归档文件
# 1. 基本提取
pax -rf archive.tar                    # 提取到当前目录
pax -rf archive.tar -C /tmp            # 提取到指定目录

# 2. 提取特定格式
pax -rf archive.cpio -x cpio           # 提取cpio格式
pax -rf archive.ustar -x ustar         # 提取ustar格式

# 3. 解压缩提取
pax -rf archive.tar.gz -z              # 提取gzip压缩的tar
pax -rf archive.tar.bz2 -j             # 提取bzip2压缩的tar

# 4. 详细模式查看提取过程
pax -vrf archive.tar

# 5. 选择性提取
pax -rf archive.tar file1              # 只提取file1
pax -rf archive.tar "*.txt"            # 只提取txt文件

# 6. 保留文件属性
pax -rf archive.tar -p e               # 保留所有属性

# 7. 不覆盖已存在文件
pax -rf archive.tar -k                 # -k选项防止覆盖

# 8. 从标准输入读取归档
cat archive.tar | pax -rf -            # 从stdin读取
ssh user@host 'cat backup.tar' | pax -rf -  # 从远程提取

# 9. 列出归档内容而不提取
pax -f archive.tar                     # 列出归档内容
pax -vf archive.tar                    # 详细列出

# 10. 提取并重命名文件
pax -rf archive.tar -s '|oldname|newname|'  # 重命名提取的文件

复制模式

目录树复制操作
# 1. 基本目录复制
pax -rw dir1 dir2                     # 复制dir1到dir2
pax -rw source destination            # 复制source到destination

# 2. 保留文件属性
pax -rw -p e source destination       # 保留所有属性
pax -rw -p m source destination       # 保留修改时间

# 3. 详细模式复制
pax -rwv source destination           # 显示复制过程

# 4. 仅复制新文件
pax -rwu source destination           # 仅复制比目标新的文件

# 5. 排除特定文件
find source -type f ! -name "*.tmp" | pax -rw -d destination

# 6. 跨文件系统复制
pax -rw -pe source /mnt/backup        # 保留属性跨文件系统

# 7. 复制并重命名
pax -rw source destination -s '|source/|dest/|'  # 路径重命名

# 8. 复制到远程服务器
pax -rw . -s ',.*/,,' | ssh user@host 'cd /backup && pax -r'

# 9. 增量备份复制
pax -rw -T 20230101000000 source destination  # 复制指定时间后的文件

# 10. 复制权限和所有权(需要root)
sudo pax -rw -p p source destination  # 保留所有权

# 11. 比较复制(显示差异)
pax -rw -v source destination | grep -v "skipped"

# 12. 复制特定文件类型
find source -name "*.txt" -o -name "*.pdf" | pax -rw -d destination

# 13. 创建硬链接而不是复制
# pax本身不支持硬链接,但可以结合find
cd source && find . -type f -exec ln {} ../destination/{} \;

# 14. 复制大量文件(比cp更稳定)
pax -rw -p e /source/large_dir /destination/

支持的归档格式

格式 选项 说明 常见扩展名
cpio -x cpio 旧的Unix归档格式,支持设备文件 .cpio, .cpio.gz
ustar -x ustar POSIX tar格式(推荐) .tar, .tar.gz
tar -x tar 传统tar格式 .tar, .tar.Z
sv4cpio -x sv4cpio System V Release 4 cpio .cpio
sv4crc -x sv4crc 带CRC校验的System V cpio .cpio
格式选择建议:
  • 跨平台兼容:使用ustar格式(POSIX标准)
  • 传统Unix系统:使用cpio格式
  • 最大兼容性:使用tar格式(最广泛支持)
  • 需要校验:使用sv4crc格式
  • 压缩选择:配合-z(gzip)或-j(bzip2)

实战示例

示例1:完整的备份和恢复脚本
#!/bin/bash
# 完整的备份和恢复脚本
# 文件名:pax_backup_system.sh

BACKUP_DIR="/backup"
LOG_FILE="/var/log/pax_backup.log"
CONFIG_FILE="/etc/backup.conf"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

# 日志函数
log() {
    local level="$1"
    local message="$2"
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")

    echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}

# 初始化备份环境
init_backup() {
    log "INFO" "初始化备份环境"

    # 创建备份目录
    mkdir -p "$BACKUP_DIR"/{daily,weekly,monthly}

    # 检查pax命令
    if ! command -v pax &> /dev/null; then
        log "ERROR" "pax命令未找到,请安装"
        exit 1
    fi

    # 加载配置文件
    if [ -f "$CONFIG_FILE" ]; then
        source "$CONFIG_FILE"
    else
        # 默认配置
        BACKUP_SOURCES=(
            "/etc"
            "/home"
            "/var/www"
            "/opt"
        )
        BACKUP_EXCLUDES=(
            "*.tmp"
            "*.log"
            "*.cache"
        )
        RETENTION_DAYS=30
    fi

    log "INFO" "备份环境初始化完成"
}

# 创建完整备份
create_full_backup() {
    local backup_name="full_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
    local backup_path="$BACKUP_DIR/monthly/$backup_name"

    log "INFO" "开始创建完整备份: $backup_name"

    # 创建排除文件列表
    local exclude_file="/tmp/exclude_$$.txt"
    for pattern in "${BACKUP_EXCLUDES[@]}"; do
        echo "$pattern" >> "$exclude_file"
    done

    # 使用pax创建备份
    log "INFO" "收集备份文件..."
    find "${BACKUP_SOURCES[@]}" -type f ! -name "*.tmp" ! -name "*.log" 2>/dev/null | \
        pax -wzf "$backup_path" -d -s "|^/||"

    if [ $? -eq 0 ]; then
        local size=$(du -h "$backup_path" | cut -f1)
        log "SUCCESS" "完整备份创建完成: $backup_name ($size)"

        # 创建校验文件
        md5sum "$backup_path" > "$backup_path.md5"
    else
        log "ERROR" "完整备份创建失败"
    fi

    # 清理
    rm -f "$exclude_file"
}

# 创建增量备份
create_incremental_backup() {
    local backup_name="inc_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
    local backup_path="$BACKUP_DIR/daily/$backup_name"
    local last_backup=$(find "$BACKUP_DIR" -name "*.tar.gz" -type f -printf "%T@ %p\n" | sort -nr | head -1 | cut -d' ' -f2)

    log "INFO" "开始创建增量备份: $backup_name"

    if [ -z "$last_backup" ]; then
        log "WARNING" "未找到之前的备份,创建完整备份"
        create_full_backup
        return
    fi

    # 获取上次备份时间
    local last_time=$(stat -c %Y "$last_backup")

    # 查找上次备份后修改的文件
    log "INFO" "查找自上次备份后修改的文件..."
    find "${BACKUP_SOURCES[@]}" -type f -newer "@$last_time" ! -name "*.tmp" ! -name "*.log" 2>/dev/null | \
        pax -wzf "$backup_path" -d -s "|^/||"

    if [ $? -eq 0 ]; then
        local size=$(du -h "$backup_path" | cut -f1)
        local file_count=$(pax -tzf "$backup_path" | wc -l)
        log "SUCCESS" "增量备份创建完成: $backup_name ($size, $file_count 个文件)"
    else
        log "ERROR" "增量备份创建失败"
    fi
}

# 恢复备份
restore_backup() {
    local backup_file="$1"
    local restore_path="${2:-/}"

    if [ ! -f "$backup_file" ]; then
        log "ERROR" "备份文件不存在: $backup_file"
        return 1
    fi

    log "INFO" "开始恢复备份: $(basename "$backup_file")"
    log "INFO" "恢复到: $restore_path"

    # 验证备份文件
    if [ -f "$backup_file.md5" ]; then
        if ! md5sum -c "$backup_file.md5" &> /dev/null; then
            log "ERROR" "备份文件校验失败,可能已损坏"
            return 1
        fi
    fi

    # 交互式确认
    read -p "确认恢复备份?这将覆盖现有文件。 (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log "INFO" "恢复操作已取消"
        return 0
    fi

    # 执行恢复
    log "INFO" "正在恢复文件..."
    if pax -rzf "$backup_file" -C "$restore_path" -p e; then
        log "SUCCESS" "备份恢复完成"

        # 恢复文件权限
        log "INFO" "修复文件权限..."
        restore_permissions "$backup_file" "$restore_path"
    else
        log "ERROR" "备份恢复失败"
        return 1
    fi
}

# 恢复文件权限
restore_permissions() {
    local backup_file="$1"
    local restore_path="$2"

    log "INFO" "从备份中提取权限信息..."

    # 创建临时目录存放权限信息
    local temp_dir="/tmp/restore_perms_$$"
    mkdir -p "$temp_dir"

    # 提取包含权限信息的文件列表
    pax -tzvf "$backup_file" | awk '{print $6, $3, $4, $1}' > "$temp_dir/filelist.txt"

    # 应用权限
    while read -r file mode owner group; do
        # 移除开头的./
        file="${file#./}"

        if [ -f "$restore_path/$file" ]; then
            # 设置权限
            chmod "$mode" "$restore_path/$file" 2>/dev/null || true

            # 设置所有者和组(需要root权限)
            if [ $(id -u) -eq 0 ]; then
                chown "$owner:$group" "$restore_path/$file" 2>/dev/null || true
            fi
        fi
    done < "$temp_dir/filelist.txt"

    rm -rf "$temp_dir"
    log "INFO" "权限恢复完成"
}

# 清理旧备份
cleanup_old_backups() {
    log "INFO" "清理旧备份文件"

    # 清理daily备份(保留7天)
    find "$BACKUP_DIR/daily" -name "*.tar.gz" -mtime +7 -delete
    find "$BACKUP_DIR/daily" -name "*.md5" -mtime +7 -delete

    # 清理weekly备份(保留30天)
    find "$BACKUP_DIR/weekly" -name "*.tar.gz" -mtime +30 -delete
    find "$BACKUP_DIR/weekly" -name "*.md5" -mtime +30 -delete

    # 清理monthly备份(保留365天)
    find "$BACKUP_DIR/monthly" -name "*.tar.gz" -mtime +365 -delete
    find "$BACKUP_DIR/monthly" -name "*.md5" -mtime +365 -delete

    log "INFO" "旧备份清理完成"
}

# 列出可用备份
list_backups() {
    echo "=== 可用备份 ==="
    echo ""

    echo "月度备份:"
    find "$BACKUP_DIR/monthly" -name "*.tar.gz" -type f -printf "  %f (%TY-%Tm-%Td %TH:%TM)\n" 2>/dev/null | sort -r

    echo ""
    echo "周度备份:"
    find "$BACKUP_DIR/weekly" -name "*.tar.gz" -type f -printf "  %f (%TY-%Tm-%Td %TH:%TM)\n" 2>/dev/null | sort -r

    echo ""
    echo "每日备份:"
    find "$BACKUP_DIR/daily" -name "*.tar.gz" -type f -printf "  %f (%TY-%Tm-%Td %TH:%TM)\n" 2>/dev/null | sort -r
}

# 主菜单
main_menu() {
    init_backup

    while true; do
        echo ""
        echo "=== PAX备份管理系统 ==="
        echo "1. 创建完整备份"
        echo "2. 创建增量备份"
        echo "3. 恢复备份"
        echo "4. 列出所有备份"
        echo "5. 清理旧备份"
        echo "6. 查看备份日志"
        echo "7. 退出"
        echo -n "请选择 [1-7]: "

        read -r choice

        case $choice in
            1)
                create_full_backup
                ;;
            2)
                create_incremental_backup
                ;;
            3)
                echo "可用的备份文件:"
                find "$BACKUP_DIR" -name "*.tar.gz" -type f | nl
                echo -n "请输入备份编号: "
                read -r backup_num

                backups=($(find "$BACKUP_DIR" -name "*.tar.gz" -type f | sort))
                selected="${backups[$((backup_num-1))]}"

                if [ -n "$selected" ]; then
                    echo -n "请输入恢复路径 (默认: /): "
                    read -r restore_path
                    restore_backup "$selected" "${restore_path:-/}"
                else
                    echo "无效的选择"
                fi
                ;;
            4)
                list_backups
                ;;
            5)
                cleanup_old_backups
                ;;
            6)
                echo "=== 备份日志 ==="
                tail -50 "$LOG_FILE"
                ;;
            7)
                echo "退出"
                exit 0
                ;;
            *)
                echo "无效选择"
                ;;
        esac

        echo ""
        read -p "按回车键继续..." -n1
        clear
    done
}

# 运行主菜单
main_menu
示例2:跨平台文件传输工具
#!/bin/bash
# 跨平台文件传输工具
# 文件名:cross_platform_transfer.sh

SOURCE_HOST=""
SOURCE_PATH=""
DEST_HOST=""
DEST_PATH=""
TRANSFER_MODE="archive"  # archive, copy, sync
ARCHIVE_FORMAT="ustar"
COMPRESSION="gzip"
PRESERVE_ATTRS=true
VERBOSE=false

# 显示帮助
show_help() {
    cat << EOF
跨平台文件传输工具

使用方法: $0 [选项]

选项:
  -s, --source HOST:PATH     源主机和路径(本地路径不需要主机)
  -d, --dest HOST:PATH       目标主机和路径
  -m, --mode MODE            传输模式: archive, copy, sync (默认: archive)
  -f, --format FORMAT        归档格式: ustar, cpio, tar (默认: ustar)
  -c, --compress TYPE        压缩类型: gzip, bzip2, none (默认: gzip)
  -p, --preserve             保留文件属性(默认: 是)
  -n, --no-preserve          不保留文件属性
  -v, --verbose              详细输出
  -h, --help                 显示此帮助信息

示例:
  # 本地到本地归档传输
  $0 -s /local/path -d /backup/path

  # 本地到远程传输
  $0 -s /local/path -d user@remote:/remote/path

  # 远程到本地传输
  $0 -s user@remote:/remote/path -d /local/path

  # 同步模式
  $0 -s /source -d /dest -m sync -p
EOF
}

# 解析命令行参数
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -s|--source)
                SOURCE="$2"
                # 解析主机和路径
                if [[ "$SOURCE" == *:* ]]; then
                    SOURCE_HOST="${SOURCE%%:*}"
                    SOURCE_PATH="${SOURCE#*:}"
                else
                    SOURCE_HOST="localhost"
                    SOURCE_PATH="$SOURCE"
                fi
                shift 2
                ;;
            -d|--dest)
                DEST="$2"
                if [[ "$DEST" == *:* ]]; then
                    DEST_HOST="${DEST%%:*}"
                    DEST_PATH="${DEST#*:}"
                else
                    DEST_HOST="localhost"
                    DEST_PATH="$DEST"
                fi
                shift 2
                ;;
            -m|--mode)
                TRANSFER_MODE="$2"
                shift 2
                ;;
            -f|--format)
                ARCHIVE_FORMAT="$2"
                shift 2
                ;;
            -c|--compress)
                COMPRESSION="$2"
                shift 2
                ;;
            -p|--preserve)
                PRESERVE_ATTRS=true
                shift
                ;;
            -n|--no-preserve)
                PRESERVE_ATTRS=false
                shift
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            *)
                echo "未知选项: $1"
                show_help
                exit 1
                ;;
        esac
    done

    # 验证参数
    if [ -z "$SOURCE_PATH" ] || [ -z "$DEST_PATH" ]; then
        echo "错误: 必须指定源路径和目标路径"
        show_help
        exit 1
    fi
}

# 执行SSH命令
ssh_cmd() {
    local host="$1"
    local cmd="$2"

    if [ "$host" = "localhost" ]; then
        eval "$cmd"
    else
        ssh "$host" "$cmd"
    fi
}

# 检查远程主机是否可用
check_host() {
    local host="$1"

    if [ "$host" != "localhost" ]; then
        echo "检查主机连接: $host"
        if ! ssh -o ConnectTimeout=5 "$host" "echo '连接成功'" &> /dev/null; then
            echo "错误: 无法连接到主机 $host"
            return 1
        fi
    fi
    return 0
}

# 归档模式传输
transfer_archive() {
    echo "使用归档模式传输"
    echo "源: $SOURCE_HOST:$SOURCE_PATH"
    echo "目标: $DEST_HOST:$DEST_PATH"
    echo "格式: $ARCHIVE_FORMAT"
    echo "压缩: $COMPRESSION"

    # 构建pax命令选项
    local pax_opts="-x $ARCHIVE_FORMAT"

    if [ "$PRESERVE_ATTRS" = true ]; then
        pax_opts="$pax_opts -p e"
    fi

    if [ "$VERBOSE" = true ]; then
        pax_opts="$pax_opts -v"
    fi

    # 压缩选项
    local compress_opts=""
    case "$COMPRESSION" in
        gzip)
            compress_opts="-z"
            ;;
        bzip2)
            compress_opts="-j"
            ;;
        none)
            compress_opts=""
            ;;
    esac

    # 创建临时文件
    local temp_file="/tmp/transfer_$$.tar"

    # 从源读取并归档
    echo "正在从源读取文件..."
    if [ "$SOURCE_HOST" = "localhost" ]; then
        cd "$SOURCE_PATH" || { echo "错误: 无法进入源目录"; return 1; }
        pax -w $pax_opts $compress_opts -f "$temp_file" .
    else
        ssh_cmd "$SOURCE_HOST" "cd '$SOURCE_PATH' && pax -w $pax_opts $compress_opts" > "$temp_file"
    fi

    if [ $? -ne 0 ]; then
        echo "错误: 创建归档失败"
        rm -f "$temp_file"
        return 1
    fi

    # 传输到目标
    echo "正在传输到目标..."
    local file_size=$(du -h "$temp_file" | cut -f1)
    echo "归档大小: $file_size"

    if [ "$DEST_HOST" = "localhost" ]; then
        # 确保目标目录存在
        mkdir -p "$DEST_PATH"
        # 提取到目标
        pax -r $pax_opts $compress_opts -f "$temp_file" -C "$DEST_PATH"
    else
        # 传输到远程并提取
        cat "$temp_file" | ssh_cmd "$DEST_HOST" "mkdir -p '$DEST_PATH' && cd '$DEST_PATH' && pax -r $pax_opts $compress_opts"
    fi

    if [ $? -eq 0 ]; then
        echo "传输完成"
    else
        echo "错误: 提取归档失败"
    fi

    # 清理临时文件
    rm -f "$temp_file"
}

# 复制模式传输
transfer_copy() {
    echo "使用复制模式传输"

    # 构建pax命令选项
    local pax_opts="-rw"

    if [ "$PRESERVE_ATTRS" = true ]; then
        pax_opts="$pax_opts -p e"
    fi

    if [ "$VERBOSE" = true ]; then
        pax_opts="$pax_opts -v"
    fi

    # 检查源和目标是否在同一主机
    if [ "$SOURCE_HOST" = "$DEST_HOST" ]; then
        # 本地复制
        if [ "$SOURCE_HOST" = "localhost" ]; then
            echo "执行本地复制..."
            pax $pax_opts "$SOURCE_PATH" "$DEST_PATH"
        else
            # 远程主机内复制
            echo "在远程主机 $SOURCE_HOST 内复制..."
            ssh_cmd "$SOURCE_HOST" "pax $pax_opts '$SOURCE_PATH' '$DEST_PATH'"
        fi
    else
        echo "错误: 复制模式不支持跨主机传输"
        echo "请使用归档模式 (-m archive)"
        return 1
    fi
}

# 同步模式传输
transfer_sync() {
    echo "使用同步模式传输"

    # 同步模式实际上是复制模式的增量版本
    local pax_opts="-rwu"  # -u 只复制更新的文件

    if [ "$PRESERVE_ATTRS" = true ]; then
        pax_opts="$pax_opts -p e"
    fi

    if [ "$VERBOSE" = true ]; then
        pax_opts="$pax_opts -v"
    fi

    if [ "$SOURCE_HOST" = "$DEST_HOST" ]; then
        # 本地同步
        if [ "$SOURCE_HOST" = "localhost" ]; then
            echo "执行本地同步..."
            pax $pax_opts "$SOURCE_PATH" "$DEST_PATH"
        else
            # 远程主机内同步
            echo "在远程主机 $SOURCE_HOST 内同步..."
            ssh_cmd "$SOURCE_HOST" "pax $pax_opts '$SOURCE_PATH' '$DEST_PATH'"
        fi
    else
        echo "错误: 同步模式不支持跨主机传输"
        echo "请使用归档模式 (-m archive)"
        return 1
    fi
}

# 主函数
main() {
    parse_args "$@"

    echo "=== 跨平台文件传输工具 ==="
    echo ""

    # 检查主机连接
    check_host "$SOURCE_HOST" || exit 1
    check_host "$DEST_HOST" || exit 1

    # 执行传输
    case "$TRANSFER_MODE" in
        archive)
            transfer_archive
            ;;
        copy)
            transfer_copy
            ;;
        sync)
            transfer_sync
            ;;
        *)
            echo "错误: 未知的传输模式: $TRANSFER_MODE"
            exit 1
            ;;
    esac

    echo ""
    echo "传输完成"
}

# 运行主函数
main "$@"

故障排除

# 错误:bash: pax: command not found
# 原因:pax命令未安装

# 解决方案:
# 1. 检查是否已安装
which pax
pax --version

# 2. 安装pax(不同Linux发行版)
# Debian/Ubuntu:
sudo apt-get update
sudo apt-get install pax

# CentOS/RHEL:
sudo yum install pax

# Fedora:
sudo dnf install pax

# Arch Linux:
sudo pacman -S pax

# 3. 如果无法安装pax,使用tar替代
# pax常用功能tar基本都支持

# 4. 检查PATH环境变量
echo $PATH
# 确保/usr/bin在PATH中

# 5. 从源码编译安装
# 下载源码:ftp://ftp.suse.com/pub/people/kukuk/pax/
# 编译安装:
tar xzf pax-*.tar.gz
cd pax-*
./configure
make
sudo make install

# 6. 验证安装
pax -w . | pax -r -v 2>/dev/null
# 如果正常,说明pax工作正常

# 错误:pax: Invalid header, archive corrupted
# 原因:归档文件损坏或格式不匹配

# 解决方案:
# 1. 检查归档文件完整性
file archive.tar
# 输出应为:POSIX tar archive

# 2. 尝试列出归档内容
pax -f archive.tar
# 或
pax < archive.tar

# 3. 使用不同格式尝试
pax -f archive.tar -x tar
pax -f archive.tar -x ustar
pax -f archive.tar -x cpio

# 4. 检查文件大小
ls -lh archive.tar
# 如果大小为0,文件可能损坏

# 5. 使用dd尝试修复
dd if=archive.tar of=archive_fixed.tar conv=sync,noerror

# 6. 从备份恢复
# 如果有备份,重新获取归档文件

# 7. 使用其他工具尝试
tar -tf archive.tar     # 使用tar列出
cpio -t < archive.cpio  # 使用cpio列出

# 8. 检查磁盘错误
fsck /dev/sda1  # 检查文件系统
badblocks -v /dev/sda1  # 检查坏块

# 9. 验证归档创建过程
# 重新创建归档并验证
pax -wf test.tar .
pax -rf test.tar -C /tmp/test
diff -r . /tmp/test

# 10. 使用压缩时检查
# 如果是压缩归档,先解压再测试
gzip -t archive.tar.gz  # 测试gzip文件
bzip2 -t archive.tar.bz2  # 测试bzip2文件

# 错误:pax: Cannot open: Permission denied
# 原因:权限不足无法读取/写入文件

# 解决方案:
# 1. 检查文件权限
ls -la 文件名
# 需要读取权限(r)来归档,写入权限(w)来提取

# 2. 使用sudo(如果需要)
sudo pax -wf archive.tar /etc
sudo pax -rf archive.tar -C /root

# 3. 检查磁盘空间
df -h .
# 确保有足够空间创建归档

# 4. 检查文件所有权
# 如果文件属于其他用户,可能需要sudo
sudo pax -wf archive.tar /home/otheruser

# 5. 使用-p选项处理权限
pax -wf archive.tar -p p .  # 保留所有权(需要root)

# 6. 避免权限问题的方法
# 创建归档时不包含权限信息
pax -wf archive.tar -p "" .

# 7. 检查SELinux/AppArmor
# 这些安全模块可能阻止访问
getenforce  # 检查SELinux状态
# 如果是Enforcing模式,尝试
sudo setenforce 0  # 临时禁用(测试用)

# 8. 检查文件系统挂载选项
# 某些文件系统可能以只读方式挂载
mount | grep " / "
# 如果是ro,重新挂载为rw
sudo mount -o remount,rw /

# 9. 使用find排除权限问题文件
find . -type f -readable | pax -wf archive.tar

# 10. 创建用户可访问的临时目录
mkdir -p /tmp/mybackup
cp -a 文件 /tmp/mybackup/
pax -wf archive.tar /tmp/mybackup

# 问题:在Linux上创建的归档在Solaris/AIX上无法读取
# 原因:平台差异和格式兼容性问题

# 解决方案:
# 1. 使用最兼容的格式
pax -x ustar -wf archive.tar .  # ustar是POSIX标准

# 2. 避免使用平台特定功能
# 不使用扩展属性、ACL等

# 3. 文件名长度限制
# 传统tar限制文件名100字符,ustar限制256字符
# 使用find检查长文件名
find . -name "*" | awk 'length($0) > 100'

# 4. 特殊字符处理
# 避免使用换行符等特殊字符
find . -name "*" -print0 | pax -0 -wf archive.tar

# 5. 文件类型兼容性
# 某些平台不支持某些文件类型(如FIFO、设备文件)
# 使用-type f只归档普通文件
find . -type f | pax -wf archive.tar

# 6. 时间戳格式
# 使用-p m保留修改时间
pax -wf archive.tar -p m .

# 7. 符号链接处理
# 默认会归档链接目标,使用-L跟随链接
pax -wf archive.tar -L .  # 归档链接指向的文件

# 8. 大文件支持
# 确保使用支持大文件的格式
pax -x ustar -wf archive.tar .  # ustar支持最大8GB文件

# 9. 字符编码
# 确保文件名使用ASCII字符
# 非ASCII字符可能在不同平台有问题

# 10. 测试跨平台兼容性
# 创建测试归档
pax -x ustar -wf test.tar .
# 在目标平台测试
pax -rf test.tar
# 比较文件差异
pax命令速查表
基本操作:
  • pax -wf 归档.tar 文件 - 创建归档
  • pax -rf 归档.tar - 提取归档
  • pax -f 归档.tar - 列出内容
  • pax -rw 源 目标 - 复制目录树
常用选项:
  • -v - 详细输出
  • -z - gzip压缩
  • -j - bzip2压缩
  • -p e - 保留所有属性
格式选择:
-x ustar    # POSIX标准tar(推荐)
-x cpio     # 传统cpio格式
-x tar      # 传统tar格式
-x sv4crc   # 带CRC校验的System V格式
最佳实践
  • 跨平台传输使用ustar格式(-x ustar
  • 重要备份使用-p e保留所有文件属性
  • 大文件归档使用-z-j压缩减少大小
  • 定期验证归档文件完整性(使用pax -t
  • 使用增量备份减少备份时间和空间
  • 在生产环境使用前先测试pax命令
注意事项
  • pax在不同Unix变体中的实现可能有差异
  • 归档特殊文件(设备文件)可能需要root权限
  • 跨平台时注意文件名长度和字符编码
  • 使用压缩时,损坏的归档可能无法部分恢复
  • 生产环境备份前务必测试恢复过程
  • 注意归档文件大小,避免超出文件系统限制