Bash 脚本将文件复制到用户(通配符)的主目录

Bash 脚本将文件复制到用户(通配符)的主目录

/root/nbu/file1.sh如果用户的 id 是偶数,我需要复制到每个用户的主目录。

尝试执行以下脚本:

#!/bin/bash
cat /etc/passwd | while read LINE
do
    username=$(awk -v var="$LINE" -F: '{
        if ($3 % 2 == 0)
           print $1
        }')
    cp /root/nbu/file1.sh ~"$username"
done

但它什么也没做。如果我回显cp /root/nbu/file1.sh ~"$username"命令并直接在脚本中执行它,它就可以工作。

我猜问题是~在 bash 脚本中得到扩展,但不知道如何解决这个问题。

先感谢您。

答案1

如果用户名部分被引用,波浪线扩展不起作用:

$ echo ~root ~"root"
/root ~root

(无论如何,它发生在变量扩展之前。)

但既然您已经passwd在 shell 中阅读,为什么不直接完整地执行它:

#!/bin/bash
getent passwd | while IFS=: read -r user pass uid gid gecos home shell; do 
    if (( uid % 2 == 0 )); then
        echo "uid $uid of user '$user' is even and their home is '$home'";
    fi; 
done

如果您的系统有getent,最好使用它,而不是/etc/passwd直接使用。

另一方面,由于您似乎并不真正需要用户名来执行任何操作,因此您可以让awk脚本输出目录$6) 反而。

答案2

那是因为波形符扩展发生在变量扩展之前:

展开的顺序是:大括号展开;波形符扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和文件名扩展。

echo计算结果看起来正确,并且如果您重新评估它就可以工作,但是对于脚本,您需要以不同的方式进行操作。也许:

# ...
homedir=$(getent passwd "$username" | cut -d: -f6)
cp /root/nbu/file1.sh "$homedir"
# ...

答案3

你看起来很机智,所以我不会给你提供脚本,但这里有一些提示:

  1. 你使用awk方法不对。试试这个:

    awk -F: -v uid_min=${UID_MIN:-1000} '$3%2==0 && $3>uid_min && $3!=65534{print $6}' /etc/passwd
    
  2. 没有必要cat

  3. 使用您的awk输出作为循环的输入read,即。while read USER_HOME_DIR ; do ... ; done < $(awk...)。请理解,这意味着只awk需要生成一个进程,而原始脚本会awk为每一行生成一个单独的进程,因此效率更高。

  4. 在您的程序中添加一个检查awk,将其限制为 UID 大于 1000,否则您将无意中为许多系统用户执行您的副本。

  5. 请注意,在上面的 #1 中,我将您的更改为 ,$1以便$6提取用户的主目录而不是用户名。

  6. 我刚刚注意到我的 debian 机器上存在一个 UID 65534 的“nobody”用户,因此您可能需要考虑这一点。我awk相应地修改了 #1 中的语句。

  7. 根据用户 Jeff Schaller 的评论,我修改了awk程序以考虑自定义最小 UID。${UID_MIN:-1000}如果该值本来为 null 或未设置,则该形式表示将该值设置为 1000。

答案4

我想我一句话就能做到。看一下这个:

eval $(awk -v source="/root/nbu/file1.sh" -v uid_min=${UID_MIN:-1000} -F: '$3%2==0 && $3>uid_min && $3!=65534{printf "cp %s %s ;", source, $6 }' /etc/passwd)

为了可读性:

eval $( 
  awk \
    -v source="/root/nbu/file1.sh" \
    -v uid_min=${UID_MIN:-1000} \
    -F: '
      $3%2==0 && $3>uid_min && $3!=65534 {
         printf "cp %s %s ;", source, $6 
      }
    ' /etc/passwd 
  )

相关内容