You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Linux Bash脚本批量复制文件到用户目录失败求助

问题分析与解决方案

嘿,我看了你的问题和脚本,一眼就发现问题所在了——你的_USERS变量里混进了换行符,导致脚本把mahmutsmbguest当成了一个带换行的字符串来处理,所以才会出现/home/mahmut\nsmbguest/Şablonlar这种完全错误的路径。

错误根源

你用eval结合大括号扩展的方式获取用户列表,结果把所有用户名连在一起(带换行符)存进了_USERS变量。而直接用for u in $_USERS遍历的时候,Bash虽然会按空格/制表符/换行分割内容,但这里变量展开时换行被保留成了字符串的一部分,导致两个用户被当成了一个整体,自然找不到对应的用户目录,后续的id命令也会报错找不到用户。

修复方案

我们需要正确获取用户列表,并用合适的方式遍历每个用户,同时优化脚本里的细节(比如避免重复创建目录、递归修改权限等):

1. 正确筛选符合UID范围的用户

先单独提取UID_MINUID_MAX,再用getent passwd结合awk筛选用户,完全避开eval带来的问题:

UID_MIN=$(awk '/^UID_MIN/ {print $2}' /etc/login.defs)
UID_MAX=$(awk '/^UID_MAX/ {print $2}' /etc/login.defs)

然后用while read循环逐个读取用户,确保每个用户都会被单独处理。

2. 优化脚本逻辑

  • mkdir加上-p参数,避免目录已存在时重复创建报错
  • chown -R递归修改目录及内部所有文件的所有权(原脚本只修改了目录本身,内部文件权限还是不对)
  • 加上shopt -s nullglob,避免当./Şablonlar/下没有文件时,*被当作普通字符串处理

修改后的完整脚本

#!/bin/bash

# 启用nullglob,避免无匹配文件时*被当作文件名
shopt -s nullglob

# 获取系统定义的普通用户UID范围
UID_MIN=$(awk '/^UID_MIN/ {print $2}' /etc/login.defs)
UID_MAX=$(awk '/^UID_MAX/ {print $2}' /etc/login.defs)

UHOME="/home"
SAB="Şablonlar"
_FILESS="./Şablonlar/*"

# 逐个读取符合UID范围的用户并处理
getent passwd | awk -v min="$UID_MIN" -v max="$UID_MAX" '$3 >= min && $3 <= max {print $1}' | while read -r u
do
    _dir="${UHOME}/${u}"
    # 先检查用户目录是否存在,避免无效操作
    if [ -d "$_dir" ]; then
        target_dir="${_dir}/${SAB}"
        # 创建目标目录(-p参数自动创建父目录,且目录已存在时不报错)
        mkdir -p "$target_dir"
        # 复制模板文件到目标目录
        cp -r "${_FILESS[@]}" "$target_dir"
        # 修改所有文件权限(注意777权限过于开放,建议根据实际需求调整为755等更严格的权限)
        find "$target_dir" -type f -exec chmod 777 {} \+
        # 递归修改目录及内部所有文件的所有权
        chown -R "$u":"$u" "$target_dir"
    else
        echo "警告:用户目录 $_dir 不存在,跳过该用户"
    fi
done

额外提示

  • 脚本里的chmod 777权限非常开放,任何用户都能修改这些文件,建议根据实际需求调整为更合理的权限(比如755表示所有者可读可写可执行,其他用户可读可执行)
  • read -r参数能避免用户名单包含引号或反斜杠时出现解析问题

内容的提问来源于stack exchange,提问作者Mahmut Elmas

火山引擎 最新活动