批量创建10个用户stu01-stu10,并且设置随机8位密码,要求:不能用shell循环(例如:for,while等),只能用linux命令及管道实现。
此题考察的是基础命令的熟练运用,因此,限制了使用shell循环。
------------题目来自老男孩Linux培训博客
题目看似非常简单,实际上,对Linux基础命令要求非常高,不能使用shell循环就是为了考同学们的基础知识的。
话不多说,言归正传,说实话如果单纯为了到达这道题的结果,只要基础命令好的同学,也很简单,我先说一下我看到题目的思路吧。
1、用户名称的批量生成。
2、随机密码生成的方法。
3、因为要一条命令搞定,所以考虑构造一个命令,使之符合要求,最后交给bash执行。
思路明确之后,那我们就开始着手做吧。
<1> 用户名称的批量生成
因为我们要生成类似如下的序列:
stu01
stu02
stu03
......
stu08
stu09
stu10
法一:花括号展开{..}
stu01 stu02 stu03 stu04 stu05 stu06 stu07 stu08 stu09 stu10
因为我们需要的是竖行排列的,那怎么办呢?
这里说明一下为什么非要竖行排列的,因为我们后面构造命令,是期望一行一行的执行,所以需要让它竖列排序的。
那我们就想办法呀,看看有什么命令能搞定或者echo本身能不能搞定啊。
于是我们又有了两个思路:
①通过echo本身可以打印出竖列的效果,但是此处似乎用不上啊。
stu01
stu02
②想办法把echo打印出来的序列中的空格替换成回车不就行了嘛,于是,我们想到了tr命令。
1
2
3
4
5
6
7
8
9
10
11
[root@oldboylinux ~]# echo -e stu{01..10}|tr " " "\n"
stu01
stu02
stu03
stu04
stu05
stu06
stu07
stu08
stu09
stu10
法二:利用seq命令,seq本身就是干这活的呀,是不是,哈哈。
1
2
3
4
5
6
7
8
9
10
11
[root@oldboylinux ~]# seq 10
1
2
3
4
5
6
7
8
9
10
似乎不是我们想要的结果呀,我们想要的是
01
02
...
09
10
那怎么办啊,想想老师的运维思路,你想要的结果,也许就是写程序的人想要的结果,也就是说很可能有类似参数可以用啊,结果一查帮助,果然,而且还有意外的收获。
①seq的"-w"参数,就是专门生成类似序列需求而生的。
②seq的"-f"参数,可以格式化输出序列,我去这不正是我们想要的效果嘛,赶紧试试看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@oldboylinux ~]# seq -w 5
1
2
3
4
5
[root@oldboylinux ~]# seq -w 05
01
02
03
04
05
[root@oldboylinux ~]# seq -w 10
01
02
03
04
05
06
07
08
09
10
如果我们单纯只是用"-w"参数,那还需要配合其他命令才能达到我们想要的这样的效果。
stu01
stu02
stu03
......
比如:用sed替换
1
2
3
4
5
6
7
8
9
10
11
stu01
stu02
stu03
stu04
stu05
stu06
stu07
stu08
stu09
stu10
但是我们"man seq"不是看到还有"-f"参数嘛,那还不赶紧试试看。
1
2
3
4
5
6
7
8
9
10
11
stu01
stu02
stu03
stu04
stu05
stu06
stu07
stu08
stu09
stu10
解释一下,后面引号里面的内容,这个是与C语言printf格式化输出类似,%号前面指定字符串,后面的02g中的2表示输出列宽为2列,0表示用0填充不足的部分,默认是用空格填充不足的部分,g是表示整数输出。
好了,序列我们有了,下一个就是想办法生成8位随机密码了。
<2> 8位随机密码的生成
Linux系统下生成随机密码的方法有很多,我们最容易想到的就是$RANDOM,这是一个由系统自动维护的随机数。我们参考网络资料,简单介绍其中的四种方法供大家参考。
来源:http://www.cnblogs.com/chengmo/archive/2010/10/23/1858879.html
①通过时间获得随机数(date)
这个也是我们经常用到的,可以说时间是唯一的,也不会重复的,从这个里面获得同一时间的唯一值。适应所有程序里面了。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
[chengmo@centos5 shell]$ date +%s
1287764773
#获得时间戳,当前到:1970-01-01 00:00:00 相隔的秒数
#如果用它做随机数,相同一秒的数据是一样的。在做循环处理,多线程里面基本不能满足要求了。
[chengmo@centos5 shell]$ date +%N
738710457
#获得当前时间的纳秒数据,精确到亿分之一秒。
#这个相当精确了,就算在多cpu,大量循环里面,同一秒里面,也很难出现相同结果,不过不同时间里面还会有大量重复碰撞
[chengmo@centos5 shell]$ date +%s%N
1287764807051101270
#这个可以说比较完美了,加入了时间戳,又加上了纳秒
通过上面说明,用它来做随机数的基数了,接下来我们看怎么样获得一段数据内怎么样获得随机数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/sh
#写个随机函数,调用方法random min max
#在min 与 max直接获得随机整数
#copyright chengmo QQ:8292669
#获得随机数返回值,shell函数里算出随机数后,更新该值
function random()
{
min=$1;
max=$2-$1;
num=$(date +%s+%N);
((retnum=num%max+min));
#进行求余数运算即可
echo $retnum;
#这里通过echo 打印出来值,然后获得函数的,stdout就可以获得值
#还有一种返回,定义全价变量,然后函数改下内容,外面读取
}
#得到1-10的seq数据项
for i in {1..10};
do
out=$(random 2 10000);
echo $i,"2-10000",$out;
done;
②通过内部系统变量($RANDOM)
其实,linux已经提供有个系统环境变量了,直接就是随机数,哈哈,觉得刚学习方法,是不是白费了!!
1
2
3
4
5
6
[chengmo@centos5 shell]$ echo $RANDOM
10918
[chengmo@centos5 shell]$ echo $RANDOM
10001
#连续2次访问,结果不一样,这个数据是一个小于或等于5位的整数
可能有疑问了,如果超过5位的随机数怎么得到呢?
呵呵,加个固定10位整数,然后进行求余,跟例1 一样了。接下来的例子又是我们自立更生做了。
③通过系统内部唯一数据生成随机数(/dev/random,urandom)
我们知道dev目录下面,是linux一些默认设备,它给我们感觉就是放的是键盘,硬盘,光驱等设备的对应文件了。 其实linux有些设备很特殊,有特殊用途。前面我们说到的:/dev/[udp|tcp]/host/port比较特殊吧。呵呵,有扯远了。
/dev/random设备,存储着系统当前运行的环境的实时数据。它可以看作是系统某个时候,唯一值数据,因此可以用作随机数元数据。我们可以通过文件读取方式,读得里面数据。/dev/urandom这个设备数据与random里面一样。只是,它是非阻塞的随机数发生器,读取操作不会产生阻塞。
得到整型数据,然后,类似一的方法就可以获得到随机数了。 题外话:在程序里面,我们经常md5得到唯一值,然后是字符串的,如果想表示成整型方式,可以通过crc函数.crc是循环冗余校验,相同数据通过运算,都会得到一串整型数据。现在这种验证应用很广。详细要了解,可以参考:crc.
④读取linux 的uuid码
在提到这个之前,有个概念,就是什么是uuid呢?
UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),它 是一个软件建构的标准,亦为自由软件基金会 (Open Software Foundation, OSF) 的组织在分布式计算环境 (Distributed Computing Environment, DCE) 领域的一部份。
UUID 的目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的 UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。它会让网络任何一台计算机所生成的uuid码,都是互联网整个服务器网络中唯一的。它的原信息会加入硬件,时间,机器当前运行信息等等。
UUID格式是:包含32个16进位数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。范例;550e8400-e29b-41d4-a716-446655440000 ,所以:UUID理论上的总数为216 x 8=2128,约等于3.4 x 1038。 也就是说若每奈秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
其实,大家做数据库设计时候,肯定听说过,guid(全局唯一标识符)码,它其实是与uuid类似,由微软支持。 这里编码,基本有操作系统内核产生。大家记得把,在windows里面,无论数据库,还是其它软件,很容易得到这个uuid编码。
linux 的uuid码
linux的uuid码也是有内核提供的,在/proc/sys/kernel/random/uuid这个文件内。其实,random目录,里面还有很多其它文件,都与生成uuid有关系的。
1
2
3
4
5
6
7
8
9
[chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuid
dff68213-b700-4947-87b1-d9e640334196
[chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuid
7b57209a-d285-4fd0-88b4-9d3162d2e1bc
#连续2次读取,得到的uuid是不同的
[chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuid| cksum | cut -f1 -d" "
2141807556
#同上方法得到随机整数
我们用的是方法是第二种,然后结合md5sum,最后取出8位作为密码,因为这样获取的密码是字符加数字
1
2
3
4
5
6
7
8
[root@oldboylinux ~]# echo $RANDOM|md5sum|cut -c 1-8
d8c57fd6
[root@oldboylinux ~]# echo $RANDOM|md5sum|cut -c 1-8
b6e693b6
[root@oldboylinux ~]# echo $RANDOM|md5sum|cut -c 1-8
6dbb7cac
[root@oldboylinux ~]# echo $RANDOM|md5sum|cut -c 1-8
663bda06
好了,到这里为止,我们前两步都有办法解决了,那就是最后一步了,把他们拼凑成我们想要的命令效果,然后交个bash执行就可以了。
<3> 拼凑想要的语句效果提交给bash执行
#seq -f "stu%02g" 10|sed -nr 's#(.*)#useradd \1;random=$(echo $RANDOM|md5sum|cut -c 1-8);echo "$random"|passwd --stdin \1#gp'|bash -x &>useradd.txt
好了,我们来分开解释一下每一部分的作用。
①seq -f "stu%02g" 10
这一部分就是用于批量生成用户名;
②sed -nr 's#(.*)#useradd \1;random=$(echo $RANDOM|md5sum|cut -c 1-8);echo "$random"|passwd --stdin \1#gp'
这一段,就是用sed的替换功能来拼凑我们想要的命令结果,拼凑的结果类似于如下结果,
\1表示前面(.*)内匹配到的字符串;
useadd stu01;random=$(echo $RANDOM|md5sum|cut -c 1-8);echo "$random"|passwd --stdin stu01
③bash -x &>useradd.txt
这一段,按道理说,只要有"bash"就可以了,结果肯定会执行了,但是我们想一下,是不是哪里还有点小问题啊,那就是我们自己创建的用户,密码是什么呢?你不会告诉我,你也不知道吧,哈哈,一开始我就是干的呀,后面想测试一下能不能用创建的用户登陆系统时,发现完蛋,不知道登录密码,所以想再交个bash执行前,把内容输出一份到文件,可是前面没有执行啊,哪里有密码呢,一度以为这条路是必定有瑕疵了,后来又转念一想,bash不是有调试参数嘛,OK,那就试试,结果很不错,可是又无法追加到文件,奇怪呀,原来调试信息是当错误信息来处理的呀,那就来个绝的,管你是标准输出还是错误输出都给我到指定文件去,这下就OK了, 完美。
你是不是以为到这里就结束了,哼,才不会呢!继续往下看哦,更多精彩还在后面呢。。。
拼凑方法大总结:
①sed替换大法,即sed 's#要替换的内容#替换后的内容#g',例子见上面和最后面的案例。
②awk拼凑大法,例子如下:
#echo -e "$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)"|awk '{print "echo "$1"|""passwd --stdin stu0"NR}'|awk '{print "useradd " $NF";"$0}'|tee useradd.txt|bash
1、echo -e "$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)\n$(echo $RANDOM|md5sum|cut -c 1-8)"
这一大段,看着好吓人啊,其实就是一个目的重复10次,你分开看就是这样的
【$(echo $RANDOM|md5sum|cut -c 1-8)\n】就是用来生成8位随机密码,重复10次,还记得最开始的echo -e参数换行大法嘛,没错,这里就用上了。
2、awk '{print "echo "$1"|""passwd --stdin stu0"NR}'|awk '{print "useradd " $NF";"$0}'
这一行就是用来拼凑我们想要实现的效果语句,具体类似如下:
useradd stu01;echo 1b487225|passwd --stdin stu01
3、tee useradd.txt
这一行就是为了保存生成密码和用户名到文件useradd.txt
4、bash
把上面拼凑的语句交给bash,执行。
其他拼凑方法参考:
基本上都是类似上述思路,只是实现方法有所不同罢了,各位自己斟酌吧,这些都搞定,说明我们的Linux基础就真OK了,重点关注一下加红的部分的实现思路。
①#echo a2stu{01..02}|xargs -n1|awk '{print"useradd "$0" && mkpasswd -l 8 >>/tmp/mima.txt;tail -1 /tmp/mima.txt|passwd --stdin "$0}'|bash
②#echo stu{01..10} | sed "s# #\n#g" | awk '{print "useradd " $1 " -p " "echo $[RANDOM**3]|cut -c 1-8
"}'|bash
③#echo stu{01..10} | sed "s# #\n#g" | awk '{cmd="echo $[RANDOM3]|cut -c 1-8";print "useradd " $1 " -p " "`echo $[RANDOM3]|cut -c 1-8`"}' |bash
④echo stu{1..10}|xargs -n 1|awk '{print "useradd", $1,"&& " "echo date +%N
|cut -c 1-8 |" "passwd --stdin",$1 }'|bash
⑤# echo stu{01..10}|xargs -n 1|sed -n 's#.*#useradd & \&\& echo date +s%
|cut -c 1-8|passwd --stdin & #gp'|bash
⑥#echo stu{1..10}|xargs -n 1|awk '{print "useradd", $1,"&& " "echo date +%N
|cut -c 1-8 |" "passwd --stdin",$1 }'|bash
⑦#echo stu{01..10}|xargs -n1 useradd && echo stu{01..10}:date +%N|cut -c1-8
|xargs -n1|tee -a pass.txt|chpasswd
⑧#echo user{01..10} | xargs -n1| sed -n 's/.*/useradd &\n echo &|md5sum|cut -c 1-8
|passwd --stdin &/p'|bash
⑨#echo stu{01..10}|tr " " "\n"|sed -r 's#(.*)#useradd \1;pass=echo $((RANDOM+123456))|md5sum|cut -c 2-9
;echo $pass|passwd --stdin \1;echo "\1 echo $pass
" >>/tmp/b.log#g'|bash
⑩#echo stu{01..10}|xargs -n1|sed -nr 's#^(.*)$#useradd \1;echo $(date +%T)|md5sum|cut -c 1-8 >/root/\1.txt;cat /root/\1.txt|passwd --stdin \1#gp' >>/root/useradd.txt 2>&1
#echo stu{01..10}:$(date +%N)|sed 's# #\n#g' >/mnt/pass;awk -F ":" '{print $1}' /mnt/pass |xargs -n 1 useradd;pwunconv;chpasswd
#echo stu{01..10}|tr " " "\n"|sed -r 's#(.*)#useradd \1;lc=$((RANDOM+10000000)); echo "$lc"|passwd --stdin \1#g'|bash
#echo stu{01..10}:$(cut -c 1-8 <<< $(md5sum <<< $RANDOM))|xargs -n1|tee useradd.txt|awk -F ':' '{print "useradd "$1 " && echo " $2 "|passwd --stdin " $1}'|bash
#echo stu{01..10} |tr ' ' '\n'|sed -rn 's@^(.*)$@useradd \1 ; echo $RANDOM|md5sum|cut -c 1-8 >/data/\1;cat /data/\1|passwd --stdin \1@gp'|bash
#$echo stu{01..10}c$[$RANDOM**3] | sed 's# #\n#g' | cut -c 1-14 | awk -F'c' '{print"useradd " $1" && echo "$2" | passwd --stdin "$1}' | bash
#echo stu{1..10}|xargs -n1 useradd ;echo stu{1..10}:cat /dev/urandom|tr -dc 0-9|fold -w8|head -1
|xargs -n1|tee -a pass.txt|chpasswd
转载于:https://blog.51cto.com/13859027/2159455