Linux系统shell脚本

                   

                       Linux系统shell脚本

 

shell脚本编程:

      基础编程:

      程序:指令+数据

 程序编程风格:

    过程式:以指令为中心,数据服务于指令

    对象式:以数据为中心,指令服务于数据

 程序的执行方式:

     计算机:运行二进制指令;

编程语言:

    低级:汇编

    高级:编译、解释

        编译:高级语言—–>编译器——–>目标代码 (Javac#

        解释:高级语言—–>解释器——–>机器代码 (shellPerlPython

 编程基本概念:

     编程逻辑处理方式:

       顺序执行

      循环执行

      选择执行

 shell编程:过程式、解释执行

       编程语言的基本结构:

      数据存储:变量数组

      表达式:a + b

      语句:if

 shell脚本基础:

   shell脚本是包含一些命令或声明,并符合一定格式的文本文件;

    格式要求:首行shabang机制

     #/bin/bash

    #/usr/bin/python

    #/usr/bin/perl

 shell 脚本的用途:

   自动化常用命令

  执行系统管理和故障排除

  创建简单的应用程序

  处理文本或文件

 shell脚本的创建:

       第一步:使用文本编辑器来创建文本文件;

         第一行必须包括shell声明:

          #/bin/bash

          添加注释行:

          注释行以#开头

          添加运行命令:

         …………………….

       第二步:运行脚本文件:

           给予执行权限,在命令行上指定脚本的绝对路径或相对路径

          直接运行解释器,将脚本作为解释器程序的参数

 脚本调试:

      检测脚本中的语法错误:

       bash  -n /path/to/somescript

      调试执行脚本:

       bash  -x /path/to/somescript

 shell变量应用:

      本地变量:生效范围为当前shell进程,对当前shell的子shell及其它shell进程均无效;  

     环境变量:生效范围为当前shell进程及其子shell进程;

     局部变量:生效范围为当前shell进程中某代码片段(通常指函数);

 变量命名法则:

     1、不能使用程序中的保留字,例如:iffor等;

    2、只能使用数字、字母、及下划线,且不能以数字开头;

    3、见名知意;

    4、统一命名规范;

本地变量基本格式:

     变量名=变量值

     例:

      [root@centos7 ~]# day=sunday

      [root@centos7 ~]# echo $day

      sunday

      [root@centos7 ~]#

 注意:当变量名称容易和紧跟其后的其他字符相混淆时,需要添加{ }”将其包围起来进行区分,否则将无法确定正确的变量名。

         例:

          [root@centos7 ~]# day=sunday

         [root@centos7 ~]# echo ${day}hayyp

          sundayhayyp

         [root@centos7 ~]#

为变量赋值的常用方法:

       在等号=”后面直接指定变量内容是为变量赋值的最基本的方法,除此之外我们还可以使用 “双引号”、“单引号”、“反撇号”、“read命令”。

       双引号:

           使用双引号时,允许在双引号的范围内使用$符号来引用其他变量的值;

            “ ”:弱引用,双引号中可以引用其他变量的值;

           用法:name=root”   或  name=$USER

                      例:

                       [root@centos7 ~]# echo $day

                      sunday

                      [root@centos7 ~]# today="today is $day"

                      [root@centos7 ~]# echo $today

                      today is sunday

                      [root@centos7 ~]#

       单引号:

           使用单引号时,将不允许在单引号的范围内引用其他变量的值;在单引号中$”符或其他任何符号将作为普通字符看待。

          ‘ ’:强引用,单引号中变量引用不会被替换为变量值,都当做普通字符看待;

                       例:

                        [root@centos7 ~]# echo $day

                       sunday

                       [root@centos7 ~]# today='today is $day'

                       [root@centos7 ~]# echo $today

                       today is $day

                       [root@centos7 ~]#

       反撇号:

         使用反撇号时,允许将执行特定命令的输出结果赋值给变量;

         用法:name=`command`   或  name=$(command)

                         例:

server_ip=$(ifconfig | sed -n "2p" | grep -E -o '(([0-9]|[1-9][0-9]|1[0-9]{2}| 2[0-4][0-9]|25[0-    5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' | head -1 )

               

        login_time=`date +%F-%T`

        host_name=`hostname`     

 read命令:

         我们可以使用bash的内置命令read来给变量赋值,read命令可以从终端键盘读取输入,实现简单的交互过程。read将从标准输入读入一行内容,并以空格为分隔符,将读入的各字段分别赋值给列表中指定的变量,多余的内容赋值给最后一个变量。

         为了使交互操作更加友好,提高易用性,我们可以结合-p”选项来设置提示信息,用于告知用户应该输入的内容。

             例:

               [root@centos7 profile.d]# read -p "please input a number :" number

              please input a number :123

              [root@centos7 profile.d]# echo $number

              123

              [root@centos7 profile.d]#

      显示已定义的所有变量(环境变量和本地变量局部变量):set命令

      删除本地变量:unset 变量名 (可以指定一个或多个变量名做参数)

 环境变量:

            为了使用户定义的本地变量在所有的子shell环境中能够继续使用,减少重复设置工作,可以使用export命令将指定的变量设置为“全局变量”。export命令可以同时使用多个变量名作为参数,变量名之间以空格分隔。

              用法:1export  变量名=变量值

                            

                   2、  变量名=变量值

                        export  变量名

                             

                   3declare  -x  变量名=变量值

                      declare  -r  变量名=变量值(只读变量,不能修改和删除)

                例:

                 现在在子shell中也可以使用父shell定义的环境变量

                 [root@centos7 Desktop]# export day=sunday

                 [root@centos7 Desktop]# echo $day

                 sunday

                 [root@centos7 Desktop]# bash

                 [root@centos7 Desktop]# echo $day

                 sunday

                 [root@centos7 Desktop]#

显示所有环境变量:

        export

        env

        printenv

        declare -x

 删除环境变量:

     unset   变量名

 只读变量:

      只读变量:只能声明,不能修改和删除;

      readonly  变量名=变量值

      declare  -r  变量名=变量值

       例:

        [root@centos7 Desktop]# readonly today="today is sunday"

        [root@centos7 Desktop]# declare -r year=2016

 位置变量:

      位置变量:用于让shell脚本在执行过程中可以调用命令行中给出的位置参数;

      位置变量采用$n”的格式,其中“n”是参数的位置序号从( 1-9

         例:$1 $2$3 $4 $5 $6 $7 $8 $9

 特殊变量:

     特殊变量是由bash程序预先定义好的一些特殊变量,用户只能使用这些特殊变量,不能创建新的特殊变量或直接为特殊变量赋值。

                $0:表示命令本身;

               $#:表示传递给脚本的参数个数;

               $*:表示所有位置参数的内容,全部参数合为一个字符串;

               $@:传递给脚本的所有参数,每个参数为独立的字符串;

               $?:表示命令执行后返回的状态,命令退出状态为0表示命令执行正确,任何非0值得表示命令执行错误,(错误值1-255之间的任意数值)

               $$:表示当前进程的进程号;

               $!:表示后台运行的最后一个进程的进程号;

             注:$#$@只在被双引号包起来的时候才会有差异;

 数值变量运算:

         运算符:    

               “+”:加法运算;

               “”:减法运算;

               “*”:乘法运算,直接用expr运算时需要转义“\*”;

               “/”:除法运算;

               “**”:乘方;

               “%”:取模运算,又称为取余运算,即计算数值相除后的余数;

 算数运算格式:

           let  var=算术运算表达式

          var=$[算术运算表达式]

          var=$((算术运算表达式))

          var=$(expr  $ARG1  $OP  $ARG2 )

          declare  -i  var=算术运算表达式

          echo  ‘算术运算表达式’ |bc

                   例:

                   [root@centos7 ~]# let sum=$num1+$num2

                   [root@centos7 ~]# sum=$[$num1+$num2]

                   [root@centos7 ~]# sum=$(($num1+$num2))

                   [root@centos7 ~]# sum=$(expr $num1 \*  $num2)

                   [root@centos7 ~]# sum=`expr $num1 \*  $num2`

                   [root@centos7 ~]# declare -i var=$num1+$num2

 bash有内建的随机数生成器:$RANDOM 1-32767

      echo $[$RANDOM%50] 0-49之间的随机数;

       赋值:

       增强型赋值:

      +=  -=  *=  /=  %=

       let  varOPERvalue

       let count +=3 意思是:let  count=count+3

       自增,自减

               let  var+=1意思是:let  var=var+1

               let  var++ 意思是:let  var=var

               let  ++var 意思是:let  var=var+

               let  var-=1 意思是:let  var=var-1

               let  var–  意思是:let  var=var

 逻辑运算:

       运算数:

           真(trueyeson1

           假(falsenooff0

                与:

                 1 && 1 = 1

                 1 && 0 = 0

                 0 && 1 = 0

                 0 && 0 = 0

                或:

                 1 || 1 = 1

                 1 || 0 = 1

                 0 || 1 = 1

                 0 || 0 = 0

               非:

                  1 = 0

                  0 = 1

   短路法则:

          ~]# command1 && command2

         command1为“假”,则command2不会执行操作;

        反之,command1为“真”,则command2必须执行;

         ~]# command1 || command2

         command1为“真”,则command2不会再执行;

        反之,command1为“假”,则command2必须执行;

 聚集命令:

       有两种聚集命令的方法:

         1)复合式:date;who | wc -l

        2)子shell:(date; who | wc -l)在子shell中运行的;

 退出状态:

     进程使用退出状态来报告成功或失败;

    $?:变量中保存了最近一次命令执行状态值;

         0:代表成功;

    1-255:代表失败;

 条件测试:

         判断某需求是否满足,需要由测试机制来实现;

        专用的测试表达式需要由测试命令辅助完成测试过程;

       使用test测试命令时,可以有以下两种形式;

         test  条件表达式

                    

        [  条件表达式  ]  

        [[  条件表达式  ]]

     注意:条件表达式两端必须有空白字符,否则为语法错误;

 bash的测试类型

      文件测试:

      数值测试:

      字符串测试:

      逻辑测试:

                 文件测试:

                   -d:测试是否为目录;

                  -e:测试目录或文件是否存在;

                  -c:测试是否为字符设备文件;

                  -f:测试是否为文件;

                  -r:测试当前用户是否有权限读取;

                  -w:测试当前用户是否有权限写入;

                  -x:测试当前用户是否可执行该文件;

                  -L:测试是否为符号链接(link)文件;

                  -p:测试是否为管道文件;

                  -S:测试是否为套接字文件;

                  -s:测试文件是否存在且非空;

                  -g:测试是否拥有sgid权限;

                  -u:测试是否拥有suid权限;

                  -k:测试是否拥有sticky权限;

                  -N:测试文件自上一次被读取之后是否被修改过;

                  -O:测试当前有效用户是否为文件属主;

                  -G:测试当前有效用户是否为文件属组;

             file1  -ef  file2 :测试file1file2是否指向同一个设备上的相同inode

            file1  -nt  file2 :测试file1是否新于file2

            file1  -ot  file2 :测试file1是否旧于file2

               例:

               [root@centos7 ~]# [ -f /etc/passwd ] && echo yes

               yes

               [root@centos7 ~]#

 数值测试:

         数值比较:

        -eq:第1个数等于第二个数;

        -ne:第1个数不等于第二个数;

        -gt:第1个数大于第二个数;

        -lt :第1个数小于第二个数;

        -ge:第1个数大于或等于第二个数;

        -le:第1个数小于或等于第二个数;

                  例:

                     [root@centos7 ~]# sum=`cat /etc/passwd | wc -l`

                     [root@centos7 ~]# echo $sum

                     43

                     [root@centos7 ~]# [ $sum -ge 10 ] && echo "yes"

                     yes

                     [root@centos7 ~]#

 字符串测试:

         ==:是否等于;

         >:是否大于;

         <:是否小于;

        !=:是否不等于;

        =~:左侧字符串是否能够被右侧的pattern所匹配;

-z string”:判断指定的字符串是否为空,空则真,不空则假;

-n sting” :判断指定的字符串是否不空,空则假,不空则真;

        -a : 并且的意思;

      注意:

        1)字符串要加双引号;

        2)要使用[[ ]]进行测试;

                例:

                测试$LANG变量是否等于en.US

                 [root@centos7 ~]# [[ $LANG == en.US ]] ||  echo $LANG

                en_US.UTF-8

                [root@centos7 ~]#

                测试abc字符串是否不等于def字符串:

                  [root@centos7 ~]# [[ "abc" != "def" ]] && echo "yes" || echo "no"

                 yes

                 [root@centos7 ~]#

                 测试文件是否为空:

                  [root@centos7 ~]# [[ -z `cat file1` ]] && echo "yes"

                  yes

                  [root@centos7 ~]#

                   测试文件是否为不空:

                  [root@centos7 ~]# [[ -n `cat file1` ]] && echo "yes"

                 yes

                 [root@centos7 ~]#  

                   判断a是否小于b

                      [root@centos7 ~]# [[ "a" < "b" ]] && echo "yes"

                  yes

                  [root@centos7 ~]#

                  判断aa是否能够被模式[ac]匹配:

                   [root@centos7 ~]# [[ aa=~ [ac] ]] && echo "yes" || echo "no"

                  yes

                  [root@centos7 ~]#

 逻辑测试:

       逻辑测试是指同时使用两个或(多个)条件表达式之间的关系;

       &&逻辑与:表示前后两个表达式都成立时整个测试结果才为真;否则为假;

      ||逻辑或:表示前后两个条件至少有一个成立时整个测试结果即为真,否则结果为假;

      !逻辑否:表示当指定的条件表达式不成立时,整个测试结果的命令为真;

           例:

             测试/etc/profile文件是否有执行权限:

              root@centos7 ~]# [ ! -x /etc/profile ] && ls -l /etc/profile || echo "have x mode"

             -rw-r–r–. 1 root root 1750 jun  7  2013 /etc/profile

             [root@centos7 ~]#

 shell脚本编程语言:

         过程式编程语言:

             顺序执行

            选择执行

            循环执行

  if语句的结构:

         单分支的if语句:

              if  条件测试命令

                  then

                     命令序列1

                   fi

         双分支if语句:

                    if  条件测试命令

                   then

                     命令序列1

                   else

                     命令序列2

                   fi

        多分支的if语句:

                   if  条件测试命令1

                  then

                    命令序列1

                  elif 条件测试命令2

                  then

                    命令序列2

                  else

                    命令序列3

                  fi

   case语句:

             case语句适用于需要进行多重分支的应用情况;

             case支持glob风格的通配符:

              *:任意长度任意字符;

              ?:任意单个字符;

              [ ]:指定范围内的任意单个字符;

              a|bab语句;

                case 变量引用   in

               pat1

                   命令序列1

               ;;

               pat2

                   命令序列2

               ;;

               pat3)

                   命令序列3

               ;;

               *

                   默认执行的命令序列

                esac

            注意:case行尾必须为单词“in”,每一模式必须以右括号“)”结束;

                 双分号;;”表示命令序列的结束;

     循环:

       循环执行:

      将某段代码重复运行多次;

      循环次数事先已知;

      循环次数事先位置;

      循环时执行进入条件和退出条件;

循环语句:

      for   while    until

 for循环:

     for 变量名  in  列表;do

          循环体

    done

        依次将列表中的元素赋值给“变量名”;每次赋值后即执行依次循环体;直到列表中的元素耗尽,循环结束。

        示例:

         for循环 99乘法表

           1 #!/bin/bash

          2 #multiplicationtables

          3

          4 for i in {1..9}

          5 do

          6   for j in {1..9}

          7       do

          8         if [ $i -ge $j ];then

          9         let sum=$j*$i

         10        echo -n -e "$j*$i=$sum\t"

         11        fi

         12      done

         13      echo

         14 done

         17 unset i

         18 unset j

         19 unset sum

           

             1 #!/bin/bash

            2 #zheng

            3

            4 for ((i=1;i<=9;i++));do

            5

            6     for ((j=1;j<=i;j++));do

            7

            8        echo -e -n "${j}x${i}=$[${i}*${j}]\t"

            9      done

           10       echo

           11 done

           12 unset i

           13 unset j

 while 循环:

       while  条件测试判断 ;do

            循环体

      done

         条件测试判断:循环控制条件;进入循环之前,先做一次判断,每一次循环之后会在次做判断;条件为true”,则执行依次循环,直到条件测试状态为false终止循环;

     因此:条件测试判断一般应该有循环控制变量;而此变量的值会在循环体不断的被修正;

           进入条件:条件测试判断为true

          退出条件:条件测试判断为false

        示例:

          测试192.168.3网段的在线主机状态,并统计在线主机和离线主机的个数;

            1 #!/bin/bash

           2 #grep ServerIp    

           3

           4 ip=192.168.3.

           5 net=1

           6 i=0

           7 j=0

           8

           9 while [ $net -lt 255 ];do

          10     ping -c1 -w1 ${ip}$net &> /dev/null

          11          if [ $? -eq 0 ];then

          12          echo "${ip}$net地址正常"

          13                 let i++

          14         else

          15           echo "${ip}$net地址不正常"

          16                 let j++

          17           fi

          18

          19         let net++

          20 done

          21echo "活跃用户:$i"

          22 echo "不活跃用户:$j"

    while循环打印国际围棋:

            示例:

              1 #!/bin/bash

             2 #while打印国际围棋

             3 i=1

             4

             5 while [ $i -le 8 ];do

             6

             7         j=1

             8            while [ $j -le 8 ];do

             9             let sum=$i+$j

            10             let  m=$sum%2

            11        #    [ $m -eq 0 ] &&echo -en "\033[41;1m  \033[0m" || echo -en "\033[43;1m  \033[0m"

            12             if [ $m -eq 0 ];then

            13                  echo -en "\033[41;1m  \033[0m"

            14              else

            15                 echo -en "\033[43;1m  \033[0m"

            16               fi

            17             let j++

            18

            19          done

            20      echo

            21    let i++

            22

            23 done

            24 unset i

            25 unset j

            26 unset sum

 until循环:

        until   条件测试判断;do

             循环体

       done

           进入条件:条件测试判断为false

          退出条件:条件测试判断为true

             示例:

               猜数字游戏:

                 1 #!/bin/bash

                 2 #

                 3

                 4 echo "============================="

                 5 suiji=$(($RANDOM%10+1))

                 6 max=10

                 7 zuixiao=1

                 8

                 9 read -p "please  input a number:" num

                10

                11 until [ $num -eq $suiji ];do

                12

                13      echo "你要猜$zuixiao $max之间的数"  

                14

                15          if [ $suiji -gt $num ];then

                16

                17              echo "你猜的太小了"        

                18         else

                19              echo "你猜的太大了"

                20          fi

                21      read -p "please  input a number:" num

                22

                23

                24 done

                25 echo "恭喜你猜对了"

                26 unset suiji

                27 unset max

                28 unset zuixiao

 continue命令:

       continue即“继续”的意思,用于暂停本次循环,跳转至循环语句的顶部重新测试条件。

         示例:

             计算100以内所有偶数的和:

               1 #!/bin/bash

              2 #zheng

              3

              4

              5 declare -i addsum=0

              6 declare -i i=0

              7

              8 while  [ $i -le 100 ];do

              9      let i++

             10      if [ $(($i%2)) -eq 1 ];then

             11         continue

             12

             13      fi

             14        let addsum+=$i

             15

             16 done

             17

             18

             19 echo "oushu100 sum :$addsum "

             20 unset  addsum

             21 unset  i

 break命令:

       break即“终断”的意思,用于跳出当前所在的循环体,但是并不退出程序;

         示例:

             100以内偶数的和:(使用whilebreak命令)

               1 #!/bin/bash

               2 #zheng

               3

               4 declare -i i=0

               5 declare -i sum=0

               6

               7 while true ;do

               8       ((i+=2))

               9      if [ $i -gt 100 ];then

              10

              11             break

              12       fi

              13       ((sum+=$i))

              14 done

              15 echo " $sum"

              16 unset i

              17 unset sumg

         示例:

             100以内偶数的和:(使用untilbreak命令)

              1 #!/bin/bash

              2 #zheng

              3

              4 declare -i i=0

              5 declare -i sum=0

              6

              7 until false ;do

              8       ((i+=2))

              9      if [ $i -gt 100 ];then

             10             break

             11       fi        

             12       ((sum+=$i))

             13 done  

             14 echo " $sum"

             15 unset i

             16 unset sum

          示例:

             100以内jishu之和:(使用whilebreak命令:)

 

              1 #!/bin/bash

              2 #zheng

              3

              4 declare -i i=1

              5 declare -i sum=0

              6

              7 while true ;do

              8      if [ $i -gt 100 ];then

              9             break

             10       fi

             11       ((sum+=$i))

             12        ((i+=2))

             13 done

             14 echo " $sum"

             15 unset i

             16 unset sum

   sleep 命令:

                示例:

                  检测zheng用户是否登录系统:

                   1 #!/bin/bash

                  2 #zheng

                  3 #

                  4 while true;do

                  5

                  6      if who | grep "^zheng\>" &> /dev/null;then

                  7           break

                  8      fi

                  9       sleep 5

                 10 done

                 11

                 12 echo "zheng logged on " >> /var/log/messages

 创建无线循环:

         while truedo

            循环体命令

        done

        until  falsedo

            循环体命令

        done

 特殊用法:

       while read linedo

          循环体

      done  <  /PATH/FROM/SOMEFILE

      依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将每行赋值给变量line

               示例:

               扫描/etc/passwd/文件每一行,如发现描述字段为空,则填充用户名和单位电话为123456

                1 #!/bin/bash

               2 #zheng

               3

               4 while read line;do

               5   kong=$( echo $line| cut -d: -f5 )

               6      if [ -z "$kong" ];then

               7

               8        user=$(echo $line | cut -d: -f1)

               9        usermod -c "${user} 123456" $user &> /dev/null

              10        echo "add  user:$user"

              11      fi

              12

              13 done </etc/passwd

              14 unset kong

              15 unset user

 特殊用法:

         for循环特殊用法:语法格式

        for (( exp1; exp2; exp3 )); do COMMANDS; done

             for循环的特殊格式:

             for ((控制变量初始化;条件判断表达式;控制变量的修正表达式));do

                 循环体命令

            done

                控制变量初始化:仅在运行到循环代码段时执行依次;

                控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后在做条件判断;

               示例:

                  1 #!/bin/bash

                 2 #zheng

                 3

                 4 for (( i=0;i<=100;i++ ));do

                 5

                 6     let sum+=$i

                 7

                 8 done

                 9

                10 echo "$sum"

                11

                12 unset sum

 select 循环与菜单:

       select  变量名 in  listdo

            循环体命令

      done

             select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入;

             用户输入菜单中的某个数字,执行相应的命令

             用户输入被保存在内置变量REPLY中;

        select case

               select 是个无限循环体,因此要记住使用break命令退出循环,或使用exit命令终止脚本。也可以按ctrl+c退出循环。

              select 经常和case联合使用

              for循环类似。可以省略 in list。此时使用位置参量;

~            示例:

                1 #!/bin/bash

               2 #zheng

               3 #菜单

               4 PS3="你好,想吃点什么,请点序号:"

               5 select menu in 凉菜 热菜 土豆 梅菜扣肉 鸡蛋面;do

               6         echo -n "你点的菜是: "

               7

               8           case $menu in

               9

              10        凉菜)

              11            echo -e "\033[31m凉菜\033[0m"

              12            ;;

              13        热菜)

              14            echo -e "\033[31m热菜\033[0m"

              15            ;;

              16        土豆)

              17            echo -e "\033[31m土豆\033[0m"

              18            ;;

              19    梅菜扣肉)

              20            echo -e "\033[31m梅菜扣肉\033[0m"

              21            ;;

              22      鸡蛋面)

              23            echo -e "\033[31m鸡蛋面\033[0m"

              24            ;;

              25           *)

              26            echo -e "\033[31m sorry,你想吃的本店没有!\033[0m"

              27            ;;

              28         esac

              29           break

              30

              31

              32 done

 函数介绍:

            函数function是由若干条shell命令组合成的语句块,实现代码重用和模块化编程。

            函数functionshell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

            函数和shell程序比较相似,区别在于:

            shell程序在子shell中运行;

            shell函数在当前shell中运行。因此在当前shell中,函数可以对shell中的变量进行修改;

   定义函数:

           函数由两部分组成:函数名和函数体

    语法一:

   function f_name {

        函数体…….

   }

    语法二:

    f_name() {

          函数体…….

     }

 函数的使用:

     函数的定义和使用:

          可在交互式环境下定义函数

         可将函数放在脚本文件中作为它的一部分

         可放在只包含函数的单独文件中

     调用:

           函数只有被调用才会执行;

          调用:给定函数名

          函数名出现的地方,会被自动替换为函数代码

  函数的生命周期:

           函数被调用时创建,返回时终止;

     函数返回值:

          函数有两种返回值:

          函数的执行结果返回值:

              使用echoprintf命令进行输出

             函数体中调用命令的输出结果

 函数的退出状态码:

               默认取决于函数中执行的最后一条命令的退出状态码

              自定义退出状态码,其格式为:

               return 从函数中返回,用最后状态命令决定返回值

              return 0 无错误返回;

              return 1-255 有错误返回;

  使用函数文件:

               可以将经常使用的函数存入函数文件,然后将函数文件载入shell

              函数文件名可以任意选取,但最好与相关任务有某种联系。例如:function.main

              一旦函数文件载入shell,就可以在命令行或脚本中调用函数,可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。

              若要改动函数,首先使用unset命令从shell中删除函数,改动完毕后,在重新载入此文件;

  载入函数:

            函数文件已创建好,要将它载入shell

            定义函数文件并载入shell的格式:

            . function.main   source function.main要使用正确的路径

                set命令检查函数是否已载入,set命令将在shell中显示所有的载入函数。

  删除shell函数:

                现在对函数做一些改动,首先删除函数,使其对shell不可用。使用unset命令完成此功能;

             命令格式:

                unset  function_name

  函数参数:

       函数可以接受参数:

            传递参数给函数:调用函数时,在函数名后以空白分隔给定参数列表即可;例如:testfunc arg1 arg2 arg3

             在函数体中,可以使用$1$2 ……. 调用这些参数;还可以使用$@,$#等特殊变量;

  函数变量:

       变量作用域:

           环境变量:当前shell和子shell有效;

          本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用域范围是当前shell脚本进程文件,包括脚本中函数。

          局部变量:函数的生命周期;函数结束时变量被自动销毁;

         注意:如果函数中有局部变量,如果其名同本地变量,使用局部变量;

            在函数中定义局部变量的方法:

            local  name=value  

 函数递归实例:

         函数递归:

             函数直接或间接调用自身

            需注意递归层数

              示例:

                 函数递归阶乘运算

                    1 #!/bin/bash

                   2 #

                   3

                   4 fact () {

                   5     if [ $1 -eq 0 -o $1 -eq 1 ];then

                   6        echo 1

                   7     else

                   8        echo $(($1*`fact $[$1-1]`))

                   9       fi

                  10   }

                  11

                  12 fact $1

          示例:

             在脚本中定义及使用函数

 

               1 #!/bin/bash

               2 #fun1

               3 #zheng

               4 #加减乘除函数库!

               5

               6 jia() {

               7   sum=$[$1+$2]

               8   echo "$sum"

               9 }

              10

              11 jian() {

              12   sum=$[$1-$2]

              13   echo "$sum"

              14 }

              15

              16 cheng() {

              17   sum=$[$1*$2]

              18   echo "$sum"

              19 }

              20

              21

              22 chu() {

              23   sum=$[$1/$2]

              24   echo "$sum"

              25 }

 定义数组:

   程序=指令+数据

变量:存储单个元素的内存空间;

数组:存储多个元素的连续的内存空间;

数组名:整个数组只有一个名字;

数组索引:标号从0开始;

    数组名[索引]

    ${ARRAY_NAME[INDEX]}

注:bash-4及之后的版本,支持自定义索引格式,而不仅仅是0,1,2,3….数组格式,此类数组称之为关联数组;

 声明数组:

    declare  -a ARRAY_NAME  声明索引数组

    declare  -A ARRAY_NAME  声明关联数组

 数组中元素的赋值方式;

    1)一次只赋值一个元素;

         ARRAY_NAME[INDEX]=value

         例:

           [root@centos7 ~]# dongwu[0]=pig

           [root@centos7 ~]# dongwu[1]=dog

           [root@centos7 ~]# echo $dongwu

            pig

           [root@centos7 ~]# echo ${dongwu[1]}

            dog

           [root@centos7 ~]# echo ${dongwu[0]}

            pig

           [root@centos7 ~]#

     2)一次赋值全部元素;

          ARRAY_NAME=val1 val2 val3 val4…….

          例:

           [root@centos7 ~]# weekday=("monday" "tuesday" "wednesday")

           [root@centos7 ~]# echo ${weekday[0]}

           monday

           [root@centos7 ~]# echo ${weekday[1]}

     3)只赋值特定元素    

          ARRAY_NAME=[0]=val1 [3]=val2…..

          注:bash支持稀疏格式的数组;

          例:

           [root@centos7 ~]# gongsi=([1]=baidu [3]=tengxun [4]=ali)

           [root@centos7 ~]# echo ${gongsi[3]}

            tengxun

           [root@centos7 ~]#

      4read  -a  ARRAY_NAME

          例:

           [root@centos7 ~]# read  -a  jiaotong

           huoche qiche feiji  kunchuan

           [root@centos7 ~]# echo ${jiaotong[0]}

           huoche

           [root@centos7 ~]#

       引用数组中的元素:${ARRAY_NAME[INDEX]}

           注意:引用时,只给数组名,表示引用下标为0的元素;

 数组的长度(数组中元素的个数)

      ${#ARRAY_NAME[*]} 表示查看数组中的元素个数;

 ${#ARRAY_NAME[@]}表示查看数组中的元素个数;

 例:

   [root@centos7 ~]# echo ${#jiaotong[*]}

   4

   [root@centos7 ~]#

 ${ARRAY_NAME[*]}  表示查看数组中的所有元素

 ${ARRAY_NAME[@]} 表示查看数组中的所有元素

  例:

   [root@centos7 ~]# echo ${jiaotong[*]}

    huoche qiche feiji kunchuan

   [root@centos7 ~]#  

注意:如果写成${#ARRAY_NAME} 表示查看数组中第一元素的字符长度;

 示例:生成10个随机数,并找出其中的最大值;

       1 #!/bin/bash

       2 #zheng

       3 #

       4

       5 declare -a rand

       6 declare -i max=0

       7 for i in {0..9};do

       8

       9      rand[$i]=$RANDOM

      10      echo ${rand[$i]}

      11      if [ ${rand[$i]} -gt $max ];then

      12          max=${rand[$i]}

      13      fi

      14 done

      15 echo "max : $max"

      16 unset rand

      17 unset i

示例:定义一个数组,数组中的元素是/var/log目录下所有以*.log结尾的文件,统计其下标为偶数的文件中的行数之和;

       1 #!/bin/bash

       2 #zheng

       3 #

       4 declare -a files

       5 files=(/var/log/*.log)

       6 declare -i lines=0

       7

       8 for i in $(seq 0 $[${#files[@]}-1]);do

       9

      10      if [ $[$i%2] -eq 0 ];then

      11         let lines+=$(wc -l ${files[$i]} | cut -d " " -f1)

      12      fi

      13 done

      14 echo "lines :$lines"

      15 unset files

      16 unset lines

      17 unset i

 数组元素切片:

    ${ARRAY_NAME[@]:offset:number}

offset:要跳过的元素个数;

number:要取出的元素个数;省略number时,表还取偏移量之后的所有元素;

 向非稀疏格式数组中追加元素:

ARRAY_NAME[${#array_name[]*}]=value

例:

[root@centos7 testdir]# echo ${weekday[*]}

monday tuesday wednesday

[root@centos7 testdir]# weekday[${#weekday[@]}]=sunday

[root@centos7 testdir]# echo ${weekday[*]}

monday tuesday wednesday sunday

[root@centos7 testdir]#

删除数组中的某个元素:

unset ARRAY[INDEX]

例:

[root@centos7 testdir]# unset weekday[3]

 关联数组:

declare  -A ARRAY_NAME (使用关联数组必须提前声明)

ARRAY_NAME=[index_name1]=value1  [index_name2]=value2

bash的内置字符串处理工具:

 字符串切片:

   ${var:offset:number}

   offset:要跳过的元素个数;

   number:要取出的元素个数;省略number时,表还取偏移量之后的所有元素;

   取自符串的字串;

   取字符串的最右侧的几个字符:${var:  -length}

   注意:冒号后必须有一个空白字符;

  例:

  [root@centos7 testdir]# echo ${weekday[*]}

   monday tuesday wednesday sunday

  [root@centos7 testdir]# echo ${weekday[@]:1:3}

   tuesday wednesday sunday

  [root@centos7 testdir]# echo ${weekday[@]: -1}

   sunday

  [root@centos7 testdir]#

  基于模式取字串:

      ${var#*word}:其中Word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;

     ${var##*word}:其中Word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;

 示例:

 [root@centos7 testdir]# path=/etc/init.d/functions

 [root@centos7 testdir]# echo ${path#*/}

 etc/init.d/functions

 [root@centos7 testdir]# echo ${path##*/}

 functions

 [root@centos7 testdir]#

      ${var%word*}:其中Word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word分隔符,删除此字符串至尾部的所有字符;

     ${var%%word*}:其中Word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除此字符串至尾部的所有字符;

   示例:

  [root@centos7 testdir]# path=/etc/init.d/functions

  [root@centos7 testdir]# echo ${path%/*}

  /etc/init.d

  [root@centos7 testdir]# echo ${path%%/*}

 

  [root@centos7 testdir]#

 查找替换:

     ${var/PATTERN/SUBSTI}:查找var所表示的字符串,第一次被PATTERN所匹配的字符串,将其替换为SUBSTI所表示的自符串;

${var//PATTERN/SUBSTI}:查找var所表示的字符串,所有被PATTERN所匹配的字符串,将其全部替换为SUBSTI所表示的自符串;

  示例:

  [root@centos7 testdir]# name="root:x:0:0::root:bashroot"

  [root@centos7 testdir]# echo ${name/root/ROOT}

  ROOT:x:0:0::root:bashroot

  [root@centos7 testdir]# echo ${name//root/ROOT}

  ROOT:x:0:0::ROOT:bashROOT

  [root@centos7 testdir]#

 ${var/#PATTERN/SUBSTI} 查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;

${var/%PATTERN/SUBSTI} 查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;

  示例:

 [root@centos7 testdir]# name="root:x:0:0::root:bashroot"

 [root@centos7 testdir]# echo ${name/#root/ROOT}

 ROOT:x:0:0::root:bashroot

 [root@centos7 testdir]# echo ${name/%root/ROOT}

 root:x:0:0::root:bashROOT

 [root@centos7 testdir]#

   注意:PATTERN中使用glob风格的通配符;

 查找删除:

    ${var/PATTERN}:以PATTERN为模式查找var字符串中第一次的匹配,并删除;

   ${var//PATTERN}:以PATTERN为模式查找var字符串中所有的匹配,并删除;

   ${var/#PATTERN}:以PATTERN为模式查找var字符串中行首匹配,并删除;

   ${var/%PATTERN}:以PATTERN为模式查找var字符串中行尾匹配,并删除;

  示例:

   [root@centos7 testdir]# name="root:x:0:0::root:bashroot"

   [root@centos7 testdir]# echo ${name/root}

    :x:0:0::root:bashroot

   [root@centos7 testdir]# echo ${name//root}

   :x:0:0:::bash

   [root@centos7 testdir]# echo ${name/#root}

   :x:0:0::root:bashroot

   [root@centos7 testdir]# echo ${name/%root}

   root:x:0:0::root:bash

   [root@centos7 testdir]#

 字符大小写转换:

    ${var^^}:把var中的所有小写字符转换为大写;

${var,,}:把var中的所有大写字符转换为小写;

 示例:

[root@centos7 testdir]# name="root:x:0:0::root:bashroot"

[root@centos7 testdir]# echo ${name^^}

ROOT:X:0:0::ROOT:BASHROOT

[root@centos7 testdir]# name1=${name^^}

[root@centos7 testdir]# echo $name1

ROOT:X:0:0::ROOT:BASHROOT

[root@centos7 testdir]# echo ${name,,}

root:x:0:0::root:bashroot

[root@centos7 testdir]#

 变量赋值:

    ${var:-VALUE}:如果var变量为空,或未设置,那么返回value,否则返回var变量的值;

   ${var:=VALUE}:如果var变量为空,或未设置,那么返回value,并将value赋值给var变量;否则,则返回var变量的值;

   ${var:+VALUE}:如果var变量不空,则返回value

   ${var:?ERROR_INFO}:如果var为空,或未设置,那么返回ERROR_INFO为错误提示,否则,返回var值;

 高级变量用法:

   shell变量一般是无类型的,但是bash shell提供了declaretypeset两个命令用于指定变量的类型,两个命令是完全等价的

declare [options] 变量名

         -r:将变量设置为只读变量;

         -i:将变量定义为整数型变量;

         -a:将变量定义为数组;

         -f:显示此脚本前定义过的所有函数名及其内容;

         -F:仅显示此脚本前定义过的所有函数名;

         -x:将变量声明为环境变量;

         -l:将变量值转为小写字母;

         -u:将变量值转换为大写字母;

 间接变量引用:

     如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值,就称为间接变量引用;

     variable1=variable2

     variable2=value

 分析:variable1的值时variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过variable1获得变量值value的行为;

bash shell提供了两种格式实现间接变量引用;

eval  tempvar=\$$variable1

tempvar=${!variabe1}

 示例:

[root@centos7 testdir]# v1=v2

[root@centos7 testdir]# v2=mage

[root@centos7 testdir]# echo ${!v1}

mage

[root@centos7 testdir]#

     

 [root@centos7 testdir]# v1=v2

[root@centos7 testdir]# v2=mage

[root@centos7 testdir]# eval v3=\$$v1

[root@centos7 testdir]# echo $v3

mage

[root@centos7 testdir]#

eval命令:

eval命令将会首先扫描命令行进行所有的置换,然后在执行该命令。该命令适用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描;

eval命令:先将变量替换成命令,然后在执行该命令)

示例:

[root@centos7 testdir]# host=hostname

[root@centos7 testdir]# eval $host

centos7

[root@centos7 testdir]#

创建临时文件:

    mktemp命令:创建的临时文件可以避免冲突,文件名后要至少跟三个大写的XXX

mktemp  [options]  [TEMPLATE]

           -d:创建临时目录;

           –tmpdir=/DIR :指明临时文件所存放的目录位置;

   示例:

 创建临时指定目录下的文件:

  root@centos7 testdir]# mktemp –tmpdir=/testdir test.XXX

  /testdir/test.7WV

  [root@centos7 testdir]#

创建临时目录:

[root@centos7 testdir]# mktemp -d dir.XXX

dir.lKU

[root@centos7 testdir]#

安装复制文件:

install命令:

     install  [options]  source directory

              -mmode设置权限;默认755

              -oowner 设置属主;

              -ggroup 设置属组;

 bash如何展开命令行:

      把命令行分成单个命令词;

     展开别名;

     展开大括号中的声明({});

     展开波浪符声明({});

     命令替换$()

     再次把命令行分成命令词;

     展开文件通配(* [abc]等等);

     准备I/O重定向(< >);

     运行命令;

 防止扩展:

 反斜线(\)会使随后的字符按愿意解释

加引号来防止扩展

 单引号防止所有的扩展;

 双引号也防止所有的扩展,但是以下情况例外:

 $ ——变量扩展

 `——–命令替换

 \——–禁止单个字符扩展

 !——–历史命令替换

 bash的配置文件:

 按生效范围划分,可分为两类:

全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置:

~/.bash_profile

~/.bashrc

 shell登录两种方式:

 交互式登录:

 1)直接通过终端输入用户名密码登录;

 2)使用 su – username 切换的用户;

   交互式登录系统依次所执行的文件:

  /etc/profile—–>/etc/profile.d/*.sh——->~/.bash_profile——>~/.bashrc——>/etc/bashrc

非交互式登录:

      1su  username

      2)图形界面下打开终端;

      3)执行脚本;

       非交互式登录系统依次所执行的文件:

       ~/.bashrc—–>/etc/bashrc——–>/etc/profile.d/*.sh

 profile类文件:

      profile类:为交互式登录的shell提供配置:

     全局:/etc/profile  /etc/profile.d/*.sh

     个人:~/.bash_profile

     功能:

         1)用于定义环境变量;

         2)运行命令或脚本;

  bashrc类文件:

       bashrc类:为非交互式和交互式登录的shell提供配置:

       全局:/etc/bashrc

       个人:~/.bashrc

       功能:

          1)定义本地变量

          2)定义命令别名和函数

 编辑配置文件生效:

 修改profilebashrc文件后需要生效

两种生效方法:

(1)重新启动shell进程;

(2)使用 . source 使配置文件重新加载;

 bash 退出任务:

 当退出登录的shell时系统会执行~/.bash_logout文件中的内容

功能:

   1)可以创建自动备份;

   2)删除临时文件;

 

      

 

 

 

 

 

 

 

 

 

 

原创文章,作者:zhengyibo,如若转载,请注明出处:http://www.178linux.com/42395

(0)
zhengyibozhengyibo
上一篇 2016-09-01
下一篇 2016-09-01

相关推荐

  • 位运算符及其应用

    一、C语言的六种位运算符: & 按位与 | 按位或 ^ 按位异或 ~ 取反 << 左移 >> 右移 1.   按位与运算 按位与运算符"&"是双目运算符。     &nb…

    Linux干货 2015-11-18
  • 一次css页面加载异常的折腾

    1       原始需求 近期在搭建平台,因多域名会分割流量,所以希望将类似 ansible.178linux.com  salt.178linux.com qa.178linux.com 这些平台整合为一个平台,所示如下 ansible.178linux.com =è www.178li…

    系统运维 2015-06-10
  • HTTP详解(3)-http1.0 和http1.1 区别

    翻了下HTTP1.1的协议标准RFC2616,下面是看到的一些它跟HTTP1.0的差别。 1. Persistent Connection持久连接        在HTTP1.0中,每对Request/Response都使用一个新的连接。      …

    Linux干货 2015-04-04
  • 全球敏捷运维峰会Gdevops 2017成都站嘉宾主题提前看!

    2017年全球敏捷运维峰会(Gdevops, Global Devops Summit)将于2017年在成都、上海、北京、广州四城全面启动,本次峰会由上海市经济和信息化委员会指导,上海市云计算产业促进中心、DBAplus社群主办,数十家媒体单位共同支持,活动家提供全球敏捷运维峰会在线报名服务。 成都站即将于13日启航,搭车地址:https://www.huo…

    Linux干货 2017-05-11
  • shell 脚本 之循环 for while until 和 软件包的管理 【上】

    shell 脚本 之循环 for while until 和 软件包的管理 【上】 循环执行     将某代码段重复运行多次     重复运行多少次:             循环次数事先已知    &nbsp…

    系统运维 2016-08-18
  • Java输入输出流

    1.什么是IO       Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。 &nb…

    Linux干货 2015-04-10