/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
你看起来很机智,所以我不会给你提供脚本,但这里有一些提示:
你使用
awk
方法不对。试试这个:awk -F: -v uid_min=${UID_MIN:-1000} '$3%2==0 && $3>uid_min && $3!=65534{print $6}' /etc/passwd
没有必要
cat
。使用您的
awk
输出作为循环的输入read
,即。while read USER_HOME_DIR ; do ... ; done < $(awk...)
。请理解,这意味着只awk
需要生成一个进程,而原始脚本会awk
为每一行生成一个单独的进程,因此效率更高。在您的程序中添加一个检查
awk
,将其限制为 UID 大于 1000,否则您将无意中为许多系统用户执行您的副本。请注意,在上面的 #1 中,我将您的更改为 ,
$1
以便$6
提取用户的主目录而不是用户名。我刚刚注意到我的 debian 机器上存在一个 UID 65534 的“nobody”用户,因此您可能需要考虑这一点。我
awk
相应地修改了 #1 中的语句。根据用户 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
)