linux shell 脚本 if和else代码块都被执行 | shell 批量添加、删除用户(for循环做if嵌套)

前言:

略懂编程的都知道,if else只能进其一,满足if条件就不会进else,

然而在shell学习过程中,却遇到了,满足了if条件后,依然执行了else中的代码块。 

本案例所有代码均在:/root/myshell/for 目录下进行,案例中不再累述。

注:“批量删除用户”和问题无关,属于扩展内容。 

概述:问题的根源在用shell写的不严谨,另外shell解释器本身也存在问题(应该是个bug)

 一、准备工作(切换目录,并创建测试数据)

          1.创建测试用户users.txt,并向其中写入测试数据

          注:t是一条特殊数据。

#cd /root/myshell/for
#vim users.txt

t
centos
suse
huawei

二、批量添加用户

1.编辑脚本

#vim adduser.sh
!/bin/bash
userList=$(cat /root/myshell/for/users.txt)
for user in $userList
do
  user_a=$(grep "$user" /etc/passwd | awk -F : '{print $1}' )  #不严谨的写法
  #user_a=$(egrep "^\<$user\>" /etc/passwd | awk -F : '{print $1}' ) #严谨的写法
  #user_a=$(getent passwd $user| awk -F : '{print $1}' )  #严谨的写法
  if [[ $user_a == $user ]]
     then echo "user:$user is already exists"
  else
        useradd $user
    echo "123456" | passwd --stdin $user
    echo "user:$user has been add and passwd has been set"
fi
done

 2.测试脚本(问题所在,t用户同时执行了if和else中的代码块

#ls /home
#sh adduser.sh  #第一次批量添加(一切正常)
#ls /home
#sh adduser.sh  #第二次批量添加,所有用户都应该被提示已存在的,偏偏就t用户,一方面进入了if被提示已存在,一方面又进入了else执行了else的代码块。

 

 3.问题解决(再次验证)

 #user_a=$(grep "$user" /etc/passwd | awk -F : '{print $1}' )      #不严谨写法(问题根源)
  #user_a=$(egrep "^\<$user\>" /etc/passwd | awk -F : '{print $1}' )  #严谨写法
  user_a=$(getent passwd $user| awk -F : '{print $1}' )   #严谨写法

经过一番求助,百度未果,在Q群好友的协助下,问题得以解决,再次验证。一切正常。

 具体步骤:把上面三行代码中的第一行注释掉,下面两行都是严谨写法,任选其一即可。   


4.问题分析

1、首先,略懂编程的都知道,if和else不会同时进入,执行里面的代码的,至少java语言不会遇到这种情况。

但是,shell脚本同一个命令,确实可以同时被if和else里面的代码块执行,本案例就是个奇葩的证明。

定论:这足以说明,/bin/bash的shell解释器是不走寻常路,能同时执行if和else里的代码,应该是个bug。

2、遇到问题,还是要想办法解决的。和度娘一番探讨后,英雄磨鞋底,未果,求助QQ群好友,最终得以解决。具体分析一下这两行严谨的代码:

#user_a=$(grep "$user" /etc/passwd | awk -F : '{print $1}' ) #不严谨写法(问题根源)

#user_a=$(egrep "^\<$user\>" /etc/passwd | awk -F : '{print $1}' ) #严谨写法(正则过滤)

user_a=$(getent passwd $user| awk -F : '{print $1}' ) #严谨写法

第一行:之所以会被同时进入if和else,是应该在进行for循环的时候,t用户通过grep查找,被匹配到了,不严谨之处是,grep并不是精准匹配,所以会匹配到含有t字母的用户。所以会进入if代码块,被提示t用户已存在。

然而,t用户依然满足else,因为站在grep不是精准匹配这个角度考虑,tom这个用户也可能会被过滤出来。

也就是if语句的条件判断,最终由两个形态:

 if [[ $user_a == $user ]]

if tom ==t    #站在这个角度,返回结果自然是false,自然会进入else

if t == t       #站在这个角度,返回结果自然是true,自然会进入if

奇葩之处就在这里了。

3、后两行严谨的写法,都是精准查找,第二行是通过正则表达式完全匹配,第三者也是完全匹配。所以,不会出现查找过滤出tom,出现 if tom==t 返回false的情况,只会查找到 if t==t返回true。

注:上图之所以看到grep "t" 过滤出的用户名中不包含t,依然被过滤了出来,是因为该用户所在数据的行中出现了t,因为管道过滤有先后的问题,调换一下管道过滤顺序,就一目了然了。

三、批量删除用户(简略版

注:由于脚本比较简单,作为扩展内容,不再过多累述。

        1.编辑脚本

#vim deluser.sh
#!/bin/bash
delList=$(cat /root/myshell/for/users.txt)
for user in $delList
do
  userdel -r $user >> /dev/null 
  if [ $? -eq 0 ] 
     then 
        echo "user :$user has been deleted"
  else
     echo "user :$user may be not exists,delete fail"
  fi  
done

        2.验证脚本

#ls /home 查看home目录下,刚才新建的用户跟目录
#cat /etc/passwd | tail -5 也可以查看
#sh deluser.sh 执行批量删除命令
#ls /home 再次查看home目录

 批量删除的过程,很顺利。

四、批量删除用户(for循环嵌套if

设计思路:

删除前,先判断被删除用户是否存在。然后再根据是否删除成功,给予不同的提示。
注:删除前需要在users.txt中特意添加一个不存在的用户tom,便于看测试效果。

1.编辑脚本

#vim del.sh

 #!/bin/bash
delList=$(cat /root/myshell/for/users.txt)
for user in $delList
  do  
  user_a=$(getent passwd $user | awk -F : '{print $1}')
  if [ "$user_a" !=  "$user" ]
    then 
       echo "user:$user isn't exit"
  else
     userdel -r $user >> /dev/null
     if [ $? -eq 0 ] 
     then "user:$user has been delete succfully!"
     else
      echo "user:$user fail to be delete "
     fi  
  fi  
done

 

 2.脚本验证

#sh del.sh

后记:

在此,再次感谢“Linux运维交流与招聘(859407315)”群的“需谨慎几十年(1827617524) ”的耐心指导。 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值