Shell脚本如何迁移用户家目录

wen 实用脚本 1

本文目录导读:

Shell脚本如何迁移用户家目录

  1. 基本迁移流程
  2. 使用示例
  3. 重要注意事项

我来详细介绍Shell脚本迁移用户家目录的方法。

基本迁移流程

单用户迁移脚本

#!/bin/bash
# 迁移单个用户家目录
migrate_user_home() {
    local username=$1
    local new_base_dir=$2
    # 检查用户是否存在
    if ! id "$username" &>/dev/null; then
        echo "错误: 用户 $username 不存在"
        return 1
    fi
    # 获取当前家目录
    local old_home=$(eval echo ~$username)
    local new_home="${new_base_dir}/${username}"
    # 检查新目录是否已存在
    if [ -d "$new_home" ]; then
        echo "警告: 新家目录 $new_home 已存在"
        read -p "是否覆盖? (y/n): " confirm
        if [ "$confirm" != "y" ]; then
            return 1
        fi
    fi
    # 创建新家目录
    mkdir -p "$new_home"
    # 复制文件(保留权限和时间戳)
    echo "正在复制文件到 $new_home ..."
    cp -rp "$old_home/"* "$new_home/"
    cp -rp "$old_home/."* "$new_home/" 2>/dev/null  # 复制隐藏文件
    # 设置正确的所有权
    chown -R "$username:$(id -gn $username)" "$new_home"
    # 更新用户家目录配置
    usermod -d "$new_home" "$username"
    echo "用户 $username 的家目录已从 $old_home 迁移到 $new_home"
}
# 使用示例
# migrate_user_home "username" "/data/home"

批量迁移脚本

#!/bin/bash
# 批量迁移家目录
batch_migrate_home() {
    local old_base_dir=$1
    local new_base_dir=$2
    local exclude_users=("root" "nobody" "systemd-coredump")
    echo "开始批量迁移家目录..."
    echo "从: $old_base_dir"
    echo "到: $new_base_dir"
    # 获取所有用户列表
    for user_dir in "$old_base_dir"/*/; do
        local username=$(basename "$user_dir")
        # 跳过排除的用户
        if [[ " ${exclude_users[@]} " =~ " ${username} " ]]; then
            echo "跳过用户: $username"
            continue
        fi
        # 检查是否为系统用户
        local uid=$(id -u "$username" 2>/dev/null)
        if [ "$uid" -gt 1000 ] 2>/dev/null; then  # 只迁移普通用户
            echo "正在迁移用户: $username"
            migrate_user_home "$username" "$new_base_dir"
        fi
    done
}
# 使用示例
# batch_migrate_home "/home" "/data/home"

完整版迁移脚本

#!/bin/bash
# 配置
BACKUP_DIR="/backup/home_$(date +%Y%m%d)"
LOG_FILE="/var/log/home_migration_$(date +%Y%m%d_%H%M%S).log"
EXCLUDE_USERS=("root" "nobody" "systemd-coredump" "games")
# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 错误处理
error_exit() {
    log "错误: $1"
    exit 1
}
# 备份家目录
backup_home() {
    local username=$1
    local old_home=$2
    log "正在备份 $username 的家目录..."
    mkdir -p "$BACKUP_DIR"
    # 创建备份(使用tar或rsync)
    if command -v rsync &>/dev/null; then
        rsync -a --delete "$old_home/" "$BACKUP_DIR/$username/"
    else
        tar -czf "$BACKUP_DIR/${username}_home_backup.tar.gz" -C "$(dirname $old_home)" "$(basename $old_home)"
    fi
    log "备份完成: $BACKUP_DIR/$username"
}
# 检查磁盘空间
check_disk_space() {
    local new_home=$1
    local required_space=$2
    local available_space=$(df "$new_home" | awk 'NR==2 {print $4}')
    if [ "$available_space" -lt "$required_space" ]; then
        return 1
    fi
    return 0
}
# 迁移用户家目录(完整版)
migrate_user_home_advanced() {
    local username=$1
    local new_base_dir=$2
    log "开始迁移用户: $username"
    # 检查用户
    if ! id "$username" &>/dev/null; then
        log "用户 $username 不存在"
        return 1
    fi
    # 获取用户信息
    local old_home=$(grep "^${username}:" /etc/passwd | cut -d: -f6)
    local user_shell=$(grep "^${username}:" /etc/passwd | cut -d: -f7)
    local uid=$(id -u "$username")
    local gid=$(id -g "$username")
    log "当前家目录: $old_home"
    log "用户Shell: $user_shell"
    # 检查是否是系统用户
    if [ "$uid" -lt 1000 ]; then
        log "跳过系统用户: $username"
        return 1
    fi
    # 新家目录路径
    local new_home="${new_base_dir}/${username}"
    # 检查磁盘空间
    local old_size=$(du -s "$old_home" 2>/dev/null | awk '{print $1}')
    if ! check_disk_space "$new_base_dir" "$old_size"; then
        log "错误: 目标磁盘空间不足"
        return 1
    fi
    # 备份
    if ! backup_home "$username" "$old_home"; then
        log "备份失败,取消迁移"
        return 1
    fi
    # 检查是否有用户正在登录
    if who | grep -q "^$username "; then
        log "警告: 用户 $username 当前已登录"
        read -p "是否继续? (y/n): " confirm
        if [ "$confirm" != "y" ]; then
            return 1
        fi
    fi
    # 创建新目录
    mkdir -p "$new_home"
    # 使用rsync复制(更快更可靠)
    if command -v rsync &>/dev/null; then
        log "使用rsync复制文件..."
        rsync -a --progress "$old_home/" "$new_home/" 2>&1 | tee -a "$LOG_FILE"
    else
        log "使用cp复制文件..."
        cp -rp "$old_home/"* "$new_home/"
        cp -rp "$old_home/."* "$new_home/" 2>/dev/null
    fi
    # 检查复制是否成功
    if [ $? -ne 0 ]; then
        log "文件复制失败"
        return 1
    fi
    # 设置权限
    chown -R "$uid:$gid" "$new_home"
    chmod --reference="$old_home" "$new_home"
    # 更新系统配置
    usermod -d "$new_home" -m "$username" 2>/dev/null || {
        log "警告: usermod失败,尝试直接修改passwd文件"
        # 直接修改passwd文件(谨慎操作)
        sed -i "s|^${username}:.*:${uid}:${gid}:.*:${old_home}:.*|${username}:x:${uid}:${gid}:${username}:${new_home}:${user_shell}|" /etc/passwd
    }
    log "用户 $username 迁移完成"
    log "旧家目录: $old_home"
    log "新家目录: $new_home"
    return 0
}
# 清理临时文件
cleanup() {
    log "清理临时文件..."
    # 可以添加清理逻辑
}
# 主函数
main() {
    local mode=$1
    case $mode in
        "single")
            read -p "输入用户名: " username
            read -p "输入新家目录基路径: " new_base
            migrate_user_home_advanced "$username" "$new_base"
            ;;
        "batch")
            read -p "输入旧家目录基路径 [/home]: " old_base
            old_base=${old_base:-/home}
            read -p "输入新家目录基路径: " new_base
            log "批量迁移模式: $old_base -> $new_base"
            # 获取所有用户列表
            for user_dir in "$old_base"/*/; do
                [ -d "$user_dir" ] || continue
                local username=$(basename "$user_dir")
                # 跳过排除用户
                if [[ " ${EXCLUDE_USERS[@]} " =~ " ${username} " ]]; then
                    log "跳过用户: $username"
                    continue
                fi
                migrate_user_home_advanced "$username" "$new_base"
            done
            ;;
        "rollback")
            read -p "输入需要回滚的用户名: " username
            # 回滚逻辑
            log "回滚功能待实现"
            ;;
        *)
            echo "用法: $0 {single|batch|rollback}"
            echo "  single  - 迁移单个用户"
            echo "  batch   - 批量迁移所有用户"
            echo "  rollback- 回滚迁移"
            exit 1
            ;;
    esac
    cleanup
    log "迁移完成,日志文件: $LOG_FILE"
}
# 执行主函数
main "$@"

使用示例

基本使用

# 迁移单个用户
./migrate_home.sh single
# 批量迁移
./migrate_home.sh batch

命令行直接调用

# 单用户迁移
migrate_user_home "john" "/data/home"
# 批量迁移
batch_migrate_home "/home" "/data/home"

重要注意事项

  1. 备份优先

    • 迁移前务必备份原家目录
    • 保留数据完整性
  2. 用户权限

    • 需要root权限执行
    • 确保目标目录权限正确
  3. 服务停止

    # 迁移前停止相关服务
    systemctl stop user-runtime-dir@$UID.service
    systemctl stop user@$UID.service
  4. 验证迁移

    # 验证文件完整性
    diff -r old_home new_home
    # 检查用户设置
    getent passwd username
    id username
  5. 回滚方案

    # 从备份恢复
    systemctl stop user@$UID.service
    usermod -d /old/home username
    cp -rp /backup/home/username/* /old/home/
    chown -R username:username /old/home

这个脚本提供了完整的家目录迁移功能,包括备份、迁移、验证和回滚机制,实际使用时请根据具体环境调整参数。

抱歉,评论功能暂时关闭!