【问题标题】:Bash script- Create usernames and passwords from txt file and store in group?Bash 脚本 - 从 txt 文件创建用户名和密码并存储在组中?
【发布时间】:2015-05-11 12:06:05
【问题描述】:

此脚本采用一个包含四列的 .txt 文件(其中包含 LastName FirstName MiddleInitial Group)作为参数,并且需要为每个人创建一个唯一的用户名和密码;然后根据每个用户的组分配适当的目录:即如果“John Doe”在“mgmt”组中,并且他的用户名是 jdoe1234,那么他的目录将是 /home/mgmt/jdoe1234。然后它应该生成一个 .txt 文件,其中包含以下列- LastName FirstName UID(userid) Password- 。

我有以下几点:

#!/bin/bash
IFS=$'\n';
for i in `cat $1`;
do
    last=`echo $i|cut -f 1 -d ' '`;
    first=`echo $i|cut -f 2 -d ' '`;
    middle=`echo $i|cut -f 3 -d ' '`;
    groups=`echo $i|cut -f 4 -d ' '`;
    r=$(( $RANDOM % 10 ));
    s=$(( $RANDOM % 10 ));
    y=$(( $RANDOM % 10 ));
    username=`echo $first| head -c 1 && echo $last| head -c 3 && echo $r$s$y`
    echo $username
done
#check if group exists, if not then create one
for group in ${groups[*]}
do
    grep -q "^$group" /etc/group ; let x=$?
    if [ $x -eq 1 ]
    then
            groupadd "$group"
    fi
done

#try to add user to correct group
x=0
created=0
for user in ${username[*]}
do
    useradd -n -g "{groups[$x]}" -m $user 2> /dev/null
done

我希望用户名包含:firstName 的第一个字母、lastName 的前 3 个字母、中间的首字母,然后是 3 个随机生成的数字。因此,与上面的 John Doe 示例并不完全相同,但相似。它不能超过 8 个字符。我不确定我是否正确创建了用户名。

当然,我也遇到了密码问题;不确定是否需要在用户名旁边或之后创建。

在第一个“for 循环”之后,我首先尝试添加一个不存在的组,然后尝试将用户名放入正确的组中。我从 Youtube 视频中获得了语法,但他将其作为数组使用,我不确定我是否这样做。

如果有帮助,假设 .txt 文件包含:

doe john a mgmt
lee amy f temp
smith tracy s empl

如果您有时间,我们将不胜感激。谢谢。

【问题讨论】:

  • 要求人们有一个中间的首字母是非常愚蠢的失礼。如果你有很多空闲时间,kalzumeus.com/2010/06/17/…有更详细的讨论。
  • 将组放在一个数组中表明可以有多个组,但您的其他要求似乎基于每个用户一个组。是哪条路?

标签: bash shell


【解决方案1】:

根据您使用的发行版,对您的脚本进行一些更改会有所帮助。我还没有时间实际测试这个,所以谨慎使用:

#!/bin/bash

# This will loop through the argumented txt file, and create the users as necessary.
# You will need to run this as root, so be very careful. Start with a small user file.

line=1 # Initiate variable for counting.
count="$(cat $1 | wc -l)"  # This counts the number of lines, which will decide how many times the loop itterates.
until [ $line -gt $count ]
do
    # Begin by grabbing one line (user to be added)
    newuser="$(head -$line $1 | tail -1)" # This gets just the one line at a time.
    # Now split the data as needed according to your original post:
    fname="$(echo $newuser | awk '{print $2}')" # AWK to get First Name
    lname="$(echo $newuser | awk '{print $1}')" # AWK to get Last Name
    minit="$(echo $newuser | awk '{print $3}')" # AWK to get middle initial
    group="$(echo $newuser | awk '{print $4}')" # AWK to get Group
    # Now create the random username.
    initial="$(echo $fname | head -c 1)"
    random="$(shuf -i 1-9 -z -n 3)"
    shortname="$(echo $lname | head -c 3)"
    username="$initial$shortname$random" # This will output exactly what is needed, although your example does not stick to what you want...
    # Now create the user.
    # Does group exist?
    if egrep -i "^$group" /etc/group
    then
        true # This is not the best way to do this, but my toddler kept me up all night...
    else
        groupadd $group
    fi
    if [ ! -d "/home/$group" ]
    then
        mkdir -m 774 /home/$group
    fi
    # Make the home dir.
    mkdir -m 777 /home/$group/$username

    # Actual useradd command
    useradd -g $group -d /home/$group/$username -p $(openssl passwd -1 $username) $username
    if [ $? = 0 ]
    then
       echo "User $username has been successfully created."
       chown $username:$group /home/$group/$username
       chmod 755 /home/$group/$username
    else
       echo "Something went wrong, user $username was NOT created."
       rm /home/$group/$username
    fi

    # Now generate line for txt output file
    output="$lname $fname $(id -u $username) $username"
    printf "\n$output" >>./output.txt
    # Now increment the counter
    line="$((line +1))"
done

exit

就像我在开始时所说的那样,我没有正确测试这个,因为我真的不想创建一堆用户 :-) 所以要小心 - 首先测试 useradd 行。其余的应该是固体。

【讨论】:

  • 另外请注意,这样的密码创建不是很安全。我让它创建了密码作为用户名-应该更改。像这样在 shell 脚本中创建任何密码都是危险的,很容易被窃听。
  • 在文件上重复运行head -n x | tail -n 1 确实不是从文件中一次读取一行的明智方法。
  • 是的,这不是最简洁的脚本,并且使用的处理器比必要的多,但话又说回来,这可能没那么重要,似乎这个家伙只是需要它来工作。但你是对的,还有更明智的方法可以做到这一点。
  • 谢谢,我也会试试这个以及其他答案。我感谢您的帮助。正如我在对另一个答案的评论中所说的那样,我并不关心功能,而是关心让它工作 - 所以你认为是对的。这是一个作业,我将在本地服务器上测试它,我可以成为 root 用户。
  • 所以我在当地实验室尝试了这个,我很确定它有效!似乎添加了正确的组(/home/empl/___、/home/temp/___、/home/mgmt/____)并添加了正确的用户名。您提供的输出文件不包含每个用户的 UID 或他们的密码。如何打印为每个用户生成的 UID 和密码?我注意到,当我尝试打印使用 'id -u ' 生成的任何用户名的 UID 时,它说没有用户存在,即使它显然已创建。
【解决方案2】:

恐怕你的语法相当笨拙。重构以避免数十个多余的外部进程也应该使脚本更具可读性和可维护性,尽管您需要了解新的构造。

不是对cat 的输出执行for 循环,而是使用while read ...; do ...; done <file 逐行读取文件的常用习惯用法,这也为您带来了read 将拆分为您输入令牌。

与其调用$RANDOM 三次,不如用模数 1000 调用一次并在必要时添加前导零似乎更简单。

不,您的数组工作不正常,但您在这里甚至不需要数组 - 只需在主循环中为每个用户做您想做的事情。

与以往一样,您应该正确引用每个字符串,除非您特别要求 shell 对值执行通配符扩展和标记拆分。

我还冒昧地将grep; if [ $? = 1 ]; then... 修改为if ! grep; then...,这样更简单、更惯用,也更易读。但是我们不应该使用grep 来检查密码,所以我用getent 代替了它。构造 getent || groupadd 基本上是 if ! getent; then groupadd; fi 的简写。

您将标准错误从useradd 重定向到/dev/null,但我把它拿走了——如果出现故障,您需要查看错误消息;否则,您可能会花费数小时调试错误,如果您知道出了什么问题,这将是显而易见的。 (我们在 StackOverflow 上看到的比我们应该看到的要多得多。)

最后一点——Bash 有一个简单的内置语法来提取子字符串; ${string:0:3} 在偏移量 0 处提取长度为 3 的子字符串。类似地,${string//foo/bar} 返回 string 的值,并将所有出现的 foo 替换为 bar

#!/bin/bash
while read last first middle groups; do
    rsy=$(prinf '%03i' $(($RANDOM % 1000)))
    username="${first:0:1}${last:0:3}$middle$rsy"
    echo "$username"
    for group in $groups; do
      getent group "$group" >/dev/null || groupadd "$group"
    done
    password=$(LC_ALL=C tr -dc '!-~' </dev/urandom | head -c 14)
    enc=$(openssl passwd -1 "$password")
    useradd -n -G "${groups// /,}" -m "$username" -p "$enc" -d "/home/${groups%% *}/$username" #2> /dev/null
    # Print generated user's first, last, UID, and password
    echo "$first $last $(id -u "$username") $password"
done <"$1"

我没有尝试增强useradd 命令——正如@asimovwasright 的回答中所述,您可能需要做额外的事情才能正确执行此操作。如果您使用的是基于 Debian 的发行版,则应将 adduser 视为更高级别的替代品,它会为您处理许多此类琐事。

密码创建有点麻烦。我改编了How to automatically add user account AND password with a Bash script? 的答案之一,但从可用性或安全性的角度来看,它可能不是最佳的。但是,无论如何,你真的不应该创建密码 - 只需创建没有密码的用户,将他们的 SSH 公钥放在适当的位置,然后让他们以这种方式登录。

(我一开始使用/dev/random,但在我的测试中需要很长时间,所以我切换到/dev/urandom。我希望你让你的用户在登录时首先更改他们的密码,所以这应该是一个可以接受的妥协。)

【讨论】:

  • 这允许每个用户有多个组,这可能是一个不必要的让步?我不会把它扔掉,以防它毕竟有用,但那部分代码可以简化。
  • 好的,这对我来说很多都是陌生的,但我会试一试。我感谢您的帮助。我应该注意,这只是一项学校作业,不会在现实世界中实施。我只需要在我拥有 root 访问权限的本地服务器上测试它,而我一直在学校 Linux 服务器上工作。我什至没有机会测试组/用户添加部分。我会回来找你的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-02
  • 1970-01-01
  • 2013-03-24
  • 2015-09-27
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多