##################################################################################################
shell脚本:
  脚本:可以执行的文件,运行之后实现某种功能(命令的堆积,交互式)

规范shell脚本的一般组成:
#! 环境声明
# 注释文本
可执行代码

###############################################################################################
一。书写第一个脚本程序
#vim /root/1.sh
 #! /bin/bash
 echo "hello world"    //输出hello world
 hostname              //输出主机名
 ifconfig | head -2    //输出网卡信息前两行
 cat /etc/redhat-release //输出系统版本信息
#chmod +x /root/1.sh  //赋予文件执行权限
#/root/1.sh  //执行脚本程序
hello word
server0.example.com
eth0: flags=4163  mtu 1500
        inet 172.25.0.11  netmask 255.255.255.0  broadcast 172.25.0.255
Red Hat Enterprise Linux Server release 7.0 (Maipo)  //输出结果

##################################################################################################

二。书写为server0自动搭建yum的脚本
#vim /root/yum.sh   //创建脚本程序文件
 #! /bin/bash
 echo '[rhel]    //yum仓库信息
 name=rhel        //yum仓库名称
 baseurl=http://172.25.254.254/content/rhel7.0/x86_64/dvd/        //网络yum源地址
 enable=1         //开机自动加载
 gpgcheck=0' > /etc/yum.repos.d/rhel.repo        //不进行签名认证,将这些内容重定向输出到文件/etc/yum.repos.d/rhel.repo
#yum clean all        //清空缓存
#yum repolist        //查看yum软件包信息
#chmod +x /root/yum.sh    //赋予执行权限
#/root/yum.sh        //执行脚本程序已加载插件:langpacks
正在清理软件源: rhel
Cleaning up everything
已加载插件:langpacks
rhel                                                     | 4.1 kB     00:00     
(1/2): rhel/group_gz                                       | 134 kB   00:00     
(2/2): rhel/primary_db                                     | 3.4 MB   00:00     
源标识                                源名称                               状态
rhel                                  rhel                                 4,305
repolist: 4,305                                                //运行成功


###############################################################################################################

管道传递:
管道操作:将上一条命令的标准输出交由下一条命令进行处理。

免交互及输出处理:
免交互处理: 脚本一般在后台进行,要减少人工交互的语句

脚本输出信息处理:
记录有价值的信息(>> /var/log/foo.log)
屏蔽无价值的,干扰的信息(&> /dev/null)
用户自定义输出:echo ‘文本字符串’

重定向输出:
标准输出:命令执行正常是显示结果
标准错误:命令执行出错或异常时显示结果

将屏幕信息保存到文件:
  > 将正确输出收集到文件当中
  2> 将错误输出收集到文件当中
  &> 收集前面命令的正确和错误输出
  >&2 将命令的正确输出改为错误输出

# echo 123 > /opt/a.txt
# cat /opt/a.txt /etc
123                //正确输出
cat: /etc: 是一个目录    //错误输出
# cat /opt/a.txt /etc > /opt/b.txt  //只收集正确输出
cat: /etc: 是一个目录
# cat /opt/a.txt /etc 2> /opt/b.txt  //只收集错误输出
123
# cat /opt/a.txt /etc &> /opt/b.txt  //正确与错误输出全都收集

#################################################################################################################

三。书写创建用户并设置密码的脚本:
# vim /root/user.sh

 #!/bin/bash
 useradd test06 &> /dev/null
 echo test06创建成功
 echo 123 | passwd --stdin test06 &> /dev/null
 echo test06密码设置成功

#  chmod +x /root/user.sh
# /root/user.sh
 
 #################################################################################################################

变量:为了增加脚本适应环境的能力,增加脚本的灵活度,方便。
变量:相当于容器,以不变的名称,储存变化的值。
    变量名=变化的值

  使用变量:    $变量名


   为了降低脚本使用难度,可以产生交互
  read   :可以产生交互,将键盘输入的内容赋值给变量

#vim /root/user.sh
 read -p "请输入您要创建的用户:" user   //user为用户名变量
 read -p "请输入您要设置的密码:" pass   //pass为用户密码变量
 useradd $user &> /dev/null        //正确与错误信息全都收集在/dev/null
 echo $user 创建成功
 echo $pass | passwd --stdin $user &> /dev/null
 echo $user 密码设置成功
#/root/user.sh
请输入您要创建的用户:lala
请输入您要设置的密码:12
lala 创建成功
lala 密码设置成功

#######################################################################
 
什么是变量
以不变的名称存放的可能会变化的值
– 变量名=变量值
– 方便以固定名称重复使用某个值
– 提高对任务需求、运行环境变化的适应能力


设置变量时的注意事项
– 若指定的变量名已存在,相当于为此变量重新赋值
– 等号两边不要有空格
– 变量名由字母/数字/下划线组成,区分大小写
– 变量名不能以数字开头,不要使用关键字和特殊字符


基本格式
– 引用变量值:$变量名
– 查看变量值:echo $变量名、echo ${变量名}


 变量的种类



位置变量
在执行脚本时提供的命令行参数(非交互式传值)

[root@server0 ~]# vim  /root/2.sh
 #!/bin/bash
 echo $1
 echo $2
 echo $3
 echo ${10}
 echo ${11}

# /root/2.sh haha  benniu  xixi  hehe   lele   dc  tc   dz   tz 100 200

[root@server0 ~]# vim /root/3.sh
  #!/bin/bash
  cat -n $1  |  head -$2

[root@server0 ~]# /root/3.sh /etc/passwd   2
[root@server0 ~]# /root/3.sh /etc/passwd   3



 预定义变量
  用来保存脚本程序的执行信息
    – 直接使用这些变量
    – 不能直接为这些变量赋值

     $#  已加载的位置变量的个数
    $*  所有位置变量的值
    $?  程序退出后的状态值,0表示正常,其他值异常



[root@server0 ~]# vim /root/2.sh

 #!/bin/bash
 echo $1
 echo $2
 echo $3
 echo ${10}
 echo ${11}
 echo $#
 echo $*

[root@server0 ~]# /root/2.sh  1  2 3 4 5 6 7 8 9 10 11


########################################################
 运算
 
[root@server0 ~]# expr 10 / 3

[root@server0 ~]# expr 10 \* 3

[root@server0 ~]# expr 1 + 2

[root@server0 ~]# expr 3 - 1

[root@server0 ~]# expr 10  %  3    #取余数 运算

  $() :将命令的输出结果,作为参数

[root@server0 opt]# date
[root@server0 opt]# date +%F
[root@server0 opt]# cd /opt

[root@server0 opt]# mkdir   $(date +%F)
[root@server0 opt]# ls
[root@server0 opt]# mkdir   mydir-$(date +%F)
[root@server0 opt]# ls
[root@server0 opt]# mkdir   MariaDB-$(date +%F)
[root@server0 opt]# ls
[root@server0 opt]# mkdir   $(hostname)-$(date +%F)

#######################################################
常用的测试选项

检查文件状态
    -e:文档存在为真
    -d:文档存在且为目录为真
    -f:文档存在且为文件为真
    -r:文档存在且有读取权限为真
    -w:文档存在且有写入权限为真
    -x:文档存在且有执行权限为真

比较整数大小(带e都有等于二字,g代表大于,l代表小于)

    -gt:大于
    -ge:大于等于
    -eq:等于
    -ne:不等于
    -lt:小于
    -le:小于等于

字符串比对
     == :相等
     !=:不相等


########################################################



 if [ 条件测试 ] ; then
     命令序列xx
 else
     命令序列yy
 fi

[root@server0 /]# vim  /root/5.sh
 #!/bin/bash
 if  [ $1 -eq $2 ];then
   echo hello
 else
   echo hi
 fi

[root@server0 /]# /root/5.sh  1 1

[root@server0 /]# /root/5.sh  1 2

###########################################################################################################

   请书写一个脚本:
      用户输入一个IP地址(read),判断是否可以与该IP地址通信,
   能通则输出 "IP ok"   否则 输出 "IP no"

[root@server0 /]# vim  /root/6.sh

   #!/bin/bash
   read  -p  '请输入一个IP地址:'    ip
   ping  -c  2  $ip  &> /dev/null

     if [ $? -eq 0 ];then
          echo  ${ip} ok
      else
          echo  ${ip} no
     fi

[root@server0 /]#   /root/6.sh

##########################################################################################

 if [条件测试1] ; then
      命令序列xx
 elif [条件测试2] ; then
      命令序列yy
 else
      命令序列zz
 fi
 
     
    成绩    大于等于90    优秀
      大于等于80    良好             
      大于等于70    及格  
      大于等于60    仍需努力  
      60以下          在牛的肖邦,也弹不出哥忧伤




[root@server0 ~]# vim /root/8.sh
#!/bin/bash
 read -p  '请输入您的成绩:'     num
if [ $num -gt  100 ];then
     echo 成绩有误
  elif [ $num -lt 0 ];then
     echo 成绩有误
  elif [ $num -ge 90 ];then
     echo 优秀
  elif [ $num -ge 80 ];then
     echo 良好
  elif [ $num -ge 70 ];then
     echo 及格
  elif [ $num -ge 60 ];then
     echo 仍需努力
  else
    echo 在牛的肖邦,也弹不出哥忧伤
fi

############################################################################################################3

在 server0 上创建 /root/foo.sh 脚本
1)当运行/root/foo.sh redhat,输出为fedora
2)当运行/root/foo.sh fedora,输出为redhat
3)当没有任何参数或者参数不是 redhat 或者
fedora时,其错误输出产生以下信息:
  /root/foo.sh  redhat|fedora







     ' ':把所有的特殊字符,当作普通文本字符输出

[root@server0 ~]# vim  /root/foo.sh
 #!/bin/bash
 if [  $1  ==  redhat  ];then
   echo  fedora
 elif [  $1  ==  fedora  ];then
   echo  redhat
 else
   echo  '/root/foo.sh  redhat|fedora'
 fi

[root@server0 ~]# /root/foo.sh redhat
[root@server0 ~]# /root/foo.sh fedora

[root@server0 ~]# /root/foo.sh haha

存在的问题:当用户不输入任何参数时,表达式不成立;因为$1没有,所以表达式if [  $1  ==  redhat  ];then,就相当于if [    ==  redhat  ];then,相当于redhet在和一个不存在变量在比较;所以表达式不成立。



 #!/bin/bash
 if [ $# -eq 0 ];then
   echo '/root/foo.sh  redhat|fedora'
  elif [ $1 == redhat ];then
   echo fedora
  elif [ $1 == fedora ];then
   echo redhat
 else
   echo '/root/foo.sh  redhat|fedora'
 fi

存在问题:题中表示其错误输出表示为:/root/foo.sh  redhat|fedora。但是,在我们运行此脚本,root/foo.sh  redhat|fedora为正确输出,所以我们要将root/foo.sh  redhat|fedora变为错误输出。

   >&2   #将正确输出变成错误
   " ":可以将 “没有” 变成 “ 空值”


 #!/bin/bash

 if [ "$1" == redhat ];then   
   echo fedora
  elif [ "$1" == fedora ];then
   echo redhat
 else
   echo '/root/foo.sh  redhat|fedora'  >&2   #将正确输出变成错误
   exit 2                                   #脚本退出返回值
 fi

 解释:当用户不输入任何参数时,表达式[ "$1" == redhat ],相当于[ " " == redhat ]。表示一个空值,所以不相等,所以输出/root/foo.sh  redhat|fedora

################################################################################################################


 for循环结构

  循环结构:将反复执行的语句,循环去执行


  for 变量名 in   值列表
  do
        命令序列
  done




[root@server0 /]# vim  /root/for.sh
  #!/bin/bash
  for a in 1 2 3 4 5
  do
    useradd nsd$a
    echo nsd$a创建成功
  done

[root@server0 /]# vim  /root/for02.sh
  #!/bin/bash
  for a in 1 2 3 4 5
  do
      echo hello
  done

##################################################################################################################

案例5:编写一个批量添加用户脚本
           在 server0 上创建 /root/batchusers 脚本
    1)此脚本要求提供用户名列表文件作为参数
    2)如果没有提供参数,此脚本应该给出提示
       Usage:    /root/batchusers,退出并返回相应值
    3)如果提供一个不存在的文件,此脚本应该给出提
    示 Input file not found,退出并返回相应值
    4)新用户的登录Shell为 /bin/false,无需设置密码
    5)用户列表测试文件:
    http://cla***oom/pub/materials/userlist


# wget    http://cla***oom/pub/materials/userlist

[root@server0 /]# vim  /root/batchusers
 #!/bin/bash
 if [ $# -eq 0 ];then  //$#位置变量的数量,当不提供参数时,$#为0,表达式成立
    echo 'Usage: /root/batchusers' >&2     //输出Usage: /root/batchusers  >&2 变为错误输出
    exit 1                        //返回值为1,提示输入参数有误
 elif [ ! -f $1 ];then
    echo 'Input file not found' >&2
    exit 2
 fi
 for  a  in $(cat $1)
 do
    useradd -s /bin/false $a
    echo $a创建成功
 done

##################################################



 #!/bin/bash
 if [ $# -eq 0 ];then
    echo 'Usage: /root/batchusers' >&2
    exit 1
 elif [ -e $1 ];then
    for  a  in $(cat $1)
     do
    useradd -s /bin/false $a
    echo $a创建成功
     done
  else
    echo 'Input file not found' >&2
    exit 2
 fi

###################################################