Bash脚本 - 从txt文件创建用户名和密码并存储在组中?

时间:2015-03-10 06:08:23

标签: bash shell

此脚本将带有四列的.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

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

2 个答案:

答案 0 :(得分: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行。其余的应该是稳固的。

答案 1 :(得分:1)

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

不是在for的输出上执行cat循环,而是逐行读取文件的通常习惯是使用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。我希望你在用户登录时让你的用户首先更改密码in,所以这应该是一个可接受的妥协。)