Linux unison命令详解

Unison是一个双向文件同步工具,允许两个或多个位置(可以是本地目录或远程服务器)保持文件一致。它支持跨平台同步,具有智能冲突检测和解决机制,是保持多台计算机文件同步的理想工具。

核心特性:双向同步 | 跨平台支持 | 冲突检测 | 增量传输 | 安全传输

核心特性

双向同步

两个方向的同步,保持文件一致性

跨平台

支持Linux, Windows, macOS

安全传输

通过SSH加密传输数据

增量传输

只传输有变化的文件部分

冲突检测

智能检测和解决文件冲突

版本控制

保留文件历史版本

安装方法

Ubuntu/Debian
# 安装unison
sudo apt update
sudo apt install unison

# 安装图形界面(可选)
sudo apt install unison-gtk

# 安装特定版本(如2.48)
sudo apt install unison=2.48.*
CentOS/RHEL
# CentOS/RHEL 7
sudo yum install epel-release
sudo yum install unison

# CentOS/RHEL 8
sudo dnf install epel-release
sudo dnf install unison

# 从源码编译(最新版本)
wget https://github.com/bcpierce00/unison/releases/download/v2.53.0/unison-v2.53.0+ocaml-4.14.0+x86_64.linux.tar.gz
tar -xzf unison*.tar.gz
sudo cp unison /usr/local/bin/
macOS
# 使用Homebrew安装
brew install unison

# 或使用MacPorts
sudo port install unison
Windows
# 下载Windows安装包
# 从 https://github.com/bcpierce00/unison/releases 下载
# 安装后添加到系统PATH

# 或使用Chocolatey包管理器
choco install unison
Unison核心概念

Unison使用"档案文件"(archive)来记录同步状态,通过比较档案文件来确定需要同步的文件:

# 工作原理:
1. 比较两个位置的档案文件
2. 检测文件变化(创建、修改、删除)
3. 检测冲突(双方都修改了同一个文件)
4. 应用同步操作
5. 更新档案文件

# 档案文件位置
~/.unison/           # 用户配置文件目录
~/.unison/*.prf      # 配置文件
~/.unison/*.archive  # 档案文件

# 同步方向术语
- 从A到B(单向)
- 从B到A(单向)
- 双向(默认)

基本语法

# 基本格式
unison [配置文件] [选项] 目录1 目录2

# 使用配置文件
unison 配置文件名

# 命令行指定目录
unison /path/to/local ssh://user@host//path/to/remote

# 常用简写形式
unison 本地目录 远程目录
unison profile_name

常用选项

-batch
批处理模式(无需交互)
-batch
-auto
自动接受非冲突变更
-auto
-confirm
需要确认每个变更
-confirm
-testserver
测试服务器连接
-testserver
-terse
简洁输出模式
-terse
-silent
静默模式(无输出)
-silent
-debug
调试模式(指定级别)
-debug all
-log
记录日志到文件
-logfile sync.log
-repeat
定期重复同步
-repeat 3600
-contactquietly
安静连接(不显示信息)
-contactquietly
-path
只同步指定路径
-path Documents
-ignore
忽略模式
-ignore "Name *.tmp"

基础同步示例

本地同步 两个本地目录同步
# 1. 基本本地同步(交互式)
unison /home/user/documents /mnt/backup/documents

# 2. 批处理模式(自动同步)
unison /home/user/documents /mnt/backup/documents -batch

# 3. 自动接受非冲突变更
unison /home/user/documents /mnt/backup/documents -auto

# 4. 只同步特定子目录
unison /home/user/documents /mnt/backup/documents -path photos

# 5. 测试同步(不实际执行)
unison /home/user/documents /mnt/backup/documents -dryrun

# 6. 查看同步状态
unison /home/user/documents /mnt/backup/documents -stats
远程同步 本地与远程服务器同步
# 1. 通过SSH同步
unison /local/dir ssh://user@remote.example.com//remote/dir

# 2. 指定SSH端口
unison /local/dir ssh://user@remote.example.com:2222//remote/dir

# 3. 使用SSH密钥(无需密码)
unison /local/dir ssh://user@remote.example.com//remote/dir -sshargs "-i /path/to/key"

# 4. 批量模式远程同步
unison /local/dir ssh://user@remote.example.com//remote/dir -batch

# 5. 测试服务器连接
unison -testserver ssh://user@remote.example.com//remote/dir

# 6. 使用RSH协议(不推荐,不安全)
unison /local/dir rsh://user@remote.example.com//remote/dir

配置文件

Unison配置文件(.prf文件)

配置文件存储在 ~/.unison/ 目录中,用于保存同步配置:

# ~/.unison/mybackup.prf 示例
# 根目录配置
root = /home/user/documents
root = ssh://user@server.example.com//backup/documents

# 同步选项
auto = true
batch = true
confirmbigdeletes = false
log = true
logfile = /var/log/unison/mybackup.log

# 忽略规则
ignore = Name *.tmp
ignore = Name *.log
ignore = Name .DS_Store
ignore = Name .git
ignore = Name .svn
ignore = Path .cache
ignore = Path .tmp

# 路径限制
path = documents
path = photos
path = music

# 冲突处理
prefer = newer        # 优先使用较新文件
# prefer = local      # 优先使用本地文件
# prefer = remote     # 优先使用远程文件

# SSH设置
sshargs = -C -o ServerAliveInterval=30

# 性能优化
maxthreads = 10
retry = 3
contactquietly = true

# 备份设置
backup = Name *.doc
backuplocation = local
backupdir = /home/user/unison-backups
maxbackups = 5
# 使用配置文件同步
unison mybackup

# 查看配置文件
ls -la ~/.unison/*.prf

# 创建默认配置文件
unison -ui text -dumbtty  # 交互式创建配置

冲突解决

冲突检测与解决策略
# 1. 冲突检测示例
# 文件在两端都被修改时产生冲突
unison /local/dir /remote/dir

# 输出类似:
#  Conflict: file.txt
#    local changed on 2024-01-01 10:00:00
#    remote changed on 2024-01-01 11:00:00

# 2. 冲突解决策略
# a) 优先使用较新文件
unison /local/dir /remote/dir -prefer newer

# b) 优先使用本地文件
unison /local/dir /remote/dir -prefer local

# c) 优先使用远程文件
unison /local/dir /remote/dir -prefer remote

# d) 合并文件(需要配置合并工具)
# 在配置文件中添加:
merge = Name *.txt -> diff3 -m CURRENT1 CURRENT2 CURRENTARCH

# 3. 备份冲突文件
# 在配置文件中添加:
backup = Name *
backuplocation = local
backupdir = /path/to/backups
maxbackups = 10

# 4. 交互式冲突解决
unison /local/dir /remote/dir -confirm

# 5. 忽略特定冲突
# 在配置文件中添加:
ignorenot = Name important.txt  # 不忽略重要文件

高级配置

多目录同步 复杂同步场景
# 1. 同步多个目录
# 创建配置文件 multi.prf
cat > ~/.unison/multi.prf << 'EOF'
# 主目录同步
root = /home/user
root = ssh://user@server//backup/home

# 排除大文件目录
ignore = Path videos
ignore = Path downloads

# 包含重要目录
path = documents
path = pictures
path = .config

# 单独配置音乐目录
include extra/music.prf
EOF

# 2. 创建子配置文件
mkdir -p ~/.unison/extra
cat > ~/.unison/extra/music.prf << 'EOF'
# 音乐目录特殊配置
root = /home/user/music
root = ssh://user@server//backup/music

# 只同步mp3和flac文件
ignore = Name *
include = Name *.mp3
include = Name *.flac

# 保持目录结构
times = true
perms = true
EOF

# 3. 执行同步
unison multi
定时同步 自动化同步任务
# 1. 使用cron定时同步
# 编辑crontab
crontab -e

# 添加以下行(每小时同步一次)
0 * * * * /usr/bin/unison -batch /home/user/documents ssh://user@server//backup/documents

# 2. 使用systemd定时服务
# 创建服务文件
sudo vim /etc/systemd/system/unison-sync.service

[Unit]
Description=Unison Document Sync
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=username
ExecStart=/usr/bin/unison -batch documents
Environment=HOME=/home/username

[Install]
WantedBy=multi-user.target

# 创建定时器
sudo vim /etc/systemd/system/unison-sync.timer

[Unit]
Description=Unison Sync Timer

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

# 启用定时器
sudo systemctl enable unison-sync.timer
sudo systemctl start unison-sync.timer

# 3. 使用inotify实时同步(需要unison-fsmonitor)
sudo apt install unison-fsmonitor
unison /local/dir /remote/dir -repeat watch

# 4. 循环同步(每10分钟)
unison /local/dir /remote/dir -repeat 600

脚本自动化

#!/bin/bash
# unison_backup.sh - 自动备份脚本
CONFIG_DIR="$HOME/.unison"
LOG_DIR="$HOME/logs/unison"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$LOG_DIR"

# 配置文件列表
profiles=("documents" "photos" "music" "code")

echo "开始同步: $(date)" | tee -a "$LOG_DIR/sync_$DATE.log"

for profile in "${profiles[@]}"; do
    echo "同步配置: $profile" | tee -a "$LOG_DIR/sync_$DATE.log"

    if [ -f "$CONFIG_DIR/$profile.prf" ]; then
        unison "$profile" -batch -logfile "$LOG_DIR/${profile}_$DATE.log" 2>&1 | tee -a "$LOG_DIR/sync_$DATE.log"

        if [ $? -eq 0 ]; then
            echo "  ✓ $profile 同步成功" | tee -a "$LOG_DIR/sync_$DATE.log"
        else
            echo "  ✗ $profile 同步失败" | tee -a "$LOG_DIR/sync_$DATE.log"
        fi
    else
        echo "  ! 配置文件 $profile.prf 不存在" | tee -a "$LOG_DIR/sync_$DATE.log"
    fi
done

echo "同步完成: $(date)" | tee -a "$LOG_DIR/sync_$DATE.log"

# 发送通知(需要配置邮件或通知服务)
if command -v notify-send &> /dev/null; then
    notify-send "Unison同步完成" "所有配置同步执行完毕"
fi

跨平台同步

# 1. Linux ↔ Windows 同步
# Windows端安装Unison,配置相同的版本
# 使用Samba共享或SSH连接

# Linux端同步到Windows共享
unison /home/user/documents smb://windows-pc/shared/documents

# 或通过SSH同步到Windows(需安装SSH服务器)
unison /home/user/documents ssh://user@windows-pc//C:/Users/user/documents

# 2. macOS ↔ Linux 同步
# macOS安装:brew install unison
# 忽略macOS特有文件
ignore = Name .DS_Store
ignore = Name ._*
ignore = Name .Spotlight-*
ignore = Name .Trashes
ignore = Name .fseventsd

# 3. 三台机器同步策略
# 使用星型拓扑:A ↔ C, B ↔ C
# C作为中心节点,A和B通过C间接同步

# 4. 版本控制注意事项
# 确保所有机器使用相同版本的Unison
unison -version

# 5. 字符编码处理
# 在配置文件中添加:
charset = utf8
unicode = yes

故障排除

连接问题
# 错误: Connection refused
# 解决方案:
# 1. 检查SSH服务
ssh user@server

# 2. 测试Unison连接
unison -testserver ssh://user@server//path

# 3. 检查防火墙
sudo ufw allow 22/tcp

# 4. 使用详细模式
unison -debug ssh ssh://user@server//path
版本不匹配
# 错误: Fatal error: Received unexpected header
# 解决方案:
# 1. 检查版本
unison -version

# 2. 安装相同版本
# 在两端安装相同版本的Unison

# 3. 使用-version指定版本
unison -version 2.48

# 4. 从源码编译相同版本
# 下载相同版本的源码编译安装
权限问题
# 错误: Permission denied
# 解决方案:
# 1. 检查文件权限
ls -la /path/to/sync

# 2. 使用正确的用户
sudo unison /path1 /path2

# 3. 配置权限保留
# 在配置文件中添加:
owner = true
group = true
perms = true

# 4. 忽略权限问题
noperms = true
档案文件损坏
# 错误: Archive format mismatch
# 解决方案:
# 1. 删除损坏的档案文件
rm ~/.unison/*.archive

# 2. 重新扫描文件
unison /path1 /path2 -force /path1

# 3. 重置同步状态
unison /path1 /path2 -reset

# 4. 创建新的配置文件
cp ~/.unison/default.prf ~/.unison/default.prf.backup
rm ~/.unison/default.prf
调试与日志
# 启用详细调试
unison /path1 /path2 -debug all 2>&1 | tee debug.log

# 启用特定模块调试
unison /path1 /path2 -debug update -debug ssh

# 查看同步统计
unison /path1 /path2 -stats

# 检查配置文件
unison -prefs /path1 /path2

# 查看Unison内部状态
unison /path1 /path2 -dumbtty -ui text

# 清理Unison缓存
rm -rf ~/.unison/*.archive
rm -f ~/.unison/*.log

# 测试配置文件语法
unison -test /path/to/profile.prf

与其他工具对比

特性对比 unison rsync syncthing
同步方向 双向 单向(主从) 双向(P2P)
冲突处理 智能检测和解决 覆盖(无检测) 版本控制
实时同步 需要外部监控 不支持 支持
跨平台 优秀 优秀 优秀
安全性 SSH加密 SSH加密 TLS加密
配置复杂度 中等 简单 中等(Web界面)
适用场景 双向同步、多设备文件同步 备份、单向同步、镜像 实时同步、多设备同步
最佳实践
  • 始终在配置文件中使用完整路径,避免相对路径问题
  • 为不同的同步任务创建单独的配置文件
  • 定期检查日志文件,监控同步状态
  • 重要文件同步前先进行备份
  • 确保同步双方使用相同版本的Unison
  • 使用SSH密钥认证,避免密码传输
  • 设置合理的忽略规则,避免同步临时文件
  • 定期清理档案文件和日志文件,避免占用过多空间
安全建议
  • 使用SSH协议进行远程同步,避免使用不安全的协议
  • 为Unison创建专用的SSH密钥,限制访问权限
  • 定期更新Unison版本,修复安全漏洞
  • 不要在配置文件中明文存储敏感信息
  • 使用防火墙限制SSH访问来源IP
  • 监控同步日志,及时发现异常同步行为
  • 重要数据同步前进行加密处理

实用脚本示例

多设备同步管理
#!/bin/bash
# unison_manager.sh - 管理多设备同步
CONFIG_DIR="$HOME/.unison"
LOG_FILE="$HOME/logs/unison/manager.log"

# 设备列表
declare -A devices=(
    ["laptop"]="ssh://user@laptop//home/user"
    ["desktop"]="ssh://user@desktop//home/user"
    ["server"]="ssh://user@server//backup"
)

# 同步配置
sync_config() {
    local config=$1
    local device=$2

    echo "[$(date)] 同步 $config 到 $device" >> "$LOG_FILE"

    unison "$config" -root2 "${devices[$device]}" -batch -logfile "$LOG_FILE" 2>&1

    if [ $? -eq 0 ]; then
        echo "  ✓ 成功" >> "$LOG_FILE"
    else
        echo "  ✗ 失败" >> "$LOG_FILE"
    fi
}

# 主循环
for config in "$CONFIG_DIR"/*.prf; do
    config_name=$(basename "$config" .prf)

    for device in "${!devices[@]}"; do
        sync_config "$config_name" "$device"
    done
done
冲突报告脚本
#!/bin/bash
# conflict_report.sh - 生成冲突报告
CONFIG_DIR="$HOME/.unison"
REPORT_DIR="$HOME/reports/unison"
DATE=$(date +%Y%m%d)

mkdir -p "$REPORT_DIR"

generate_report() {
    local config=$1
    local report_file="$REPORT_DIR/${config}_${DATE}.txt"

    echo "=== Unison冲突报告 ===" > "$report_file"
    echo "配置: $config" >> "$report_file"
    echo "日期: $(date)" >> "$report_file"
    echo "=====================" >> "$report_file"

    # 运行unison并捕获冲突
    unison "$config" -batch -terse 2>&1 | grep -i conflict >> "$report_file"

    # 统计冲突数量
    conflict_count=$(grep -c "Conflict" "$report_file" 2>/dev/null || echo "0")

    if [ "$conflict_count" -gt 0 ]; then
        echo "" >> "$report_file"
        echo "发现 $conflict_count 个冲突" >> "$report_file"
        echo "请手动解决这些冲突" >> "$report_file"

        # 发送邮件通知
        if command -v mail &> /dev/null; then
            mail -s "Unison冲突报告: $config" user@example.com < "$report_file"
        fi
    fi
}

# 处理所有配置文件
for config_file in "$CONFIG_DIR"/*.prf; do
    config_name=$(basename "$config_file" .prf)
    generate_report "$config_name"
done