设为首页 收藏本站
查看: 490|回复: 0

第14章,Shell脚本编程进阶

[复制链接]

尚未签到

发表于 2018-8-20 09:56:39 | 显示全部楼层 |阅读模式
  更多内容请点击:
  Linux学习从入门到打死也不放弃,完全笔记整理(持续更新,求收藏,求点赞~~~~)
  http://blog.51cto.com/13683480/2095439
  第14章,Shell脚本编程进阶
  本章内容:
  条件判断
  循环
  信号捕捉
  函数
  数组
  高级字符串操作
  高级变量
  Expect
  过程式编程语言执行方式:
  顺序执行,选择执行,循环执行
  条件选择-----------------------------------------------------------------------
  if语句:
  结构:     可嵌套
  单分支:
  if 判断条件;then
  条件判断为真的执行代码
  fi
  双分支:
  if 判断条件;then
  条件判断为真的执行代码
  (此段若想为空,使用":")
  else
  条件判断为假的执行代码
  fi
  多分支:
  if 条件判断1;then
  cmd..
  elif  条件判断2;then
  cmd..
  elif  条件判断3;then
  cmd..
  else
  以上条件全为假的分支代码
  fi
  case语句:
  格式:
  case  变量引用 in
  pat1)
  分支1
  ;;
  pat2)
  分支2
  ;;
  ...
  *)
  默认分支
  ;;
  esac
  注意:     case支持glob风格的通配符
  *             任意长度任意字符
  ?           任意单个字符
  [abc]       指定范围内的任意单个字符
  a|b          a或b
  循环执行------------------------------------------------------------------------
  将某代码段重复多次运行
  重复运行多少次
  循环次数事先已知
  循环次数事先未知
  有进入条件和退出条件
  for,while,until
  for循环
  格式:
  for 变量名 in 列表;do
  循环体代码
  done
  机制:
  依次将列表中的元素赋值给"变量名"
  每次赋值后即执行一次循环体,直到列表中的元素耗尽,循环结束
  列表生成方式:
  1     直接给出列表
  2     整数列表
  {1..10..2}
  $(seq  1 2 10)
  3     返回列表的命令
  $(cmd)
  4     使用glob,如:*.sh
  5     变量引用
  $@,$*
  while循环
  格式:
  while CONDITION;do
  循环体
  done
  CONDITION :
  循环控制条件
  进入循环之前,先做一次判断
  每一次循环之后会再次做判断
  条件为true,则执行一次循环,直到条件测试状态为false 终止循环
  因此:     CONDITION一般应该有循环控制变量,而此变量的值会在循环体不断的被修正
  进入条件:CONDITION为true
  退出条件:CONDITION为false
  until循环
  格式:
  until CONDITION;do
  循环体
  done
  进入条件:CONDITION 为  false
  退出条件:CONDITION 为  true
  循环控制语句:
  用于循环体中
  continue [N] 默认为1
  用于循环体中,提前结束第N层的本轮循环,而直接进入下一轮判断
  所在层为第1层
  break [N] 默认为1
  用于循环体中,提前结束第N层循环,所在层为第1层
  shift [N] 默认为1
  用于将参数列表list 左移指定的次数,默认1次
  参数列表list 一旦被移动,最左端的那个参数就从列表中删除。
  while循环遍历位置参数列表时,常用到shift
  创建无限循环:
  1     while true;do
  循环体代码
  done
  2     until false;do
  循环体
  done
  特殊用法:
  while 循环的特殊用法(遍历文件的每一行)
  while read  变量名;do
  循环体代码
  done <  /file
  一次读取file 文件中的每一行,且将行赋值给变量
  PS:   也可以使用   cmd |while read;do
  循环体
  done
  但是循环中的数组值貌似不能输出,即如在done之后echo 数组中的值为空 ,需要注意
  双小括号方法,即((....))格式,也可以用于算术运算
  也可以是bash实现C语言风格的变量操作
  i=10
  ((i++))
  for 循环 的特殊格式:
  for((控制变量初始化;条件判断表达式;控制标量的修正表达式));do
  循环体代码
  done
  如:       for ((i=1;i  echo nihao
  >  echo wohenhao
  >  ping  -c1 -w1  192.168.0.1
  >  }
  [root@centos6 ~/bin]$func_name1
  nihao
  wohenhao
  connect: Network is unreachable
  可将函数放在脚本文件中作为它的一部分
  可放在只包含函数的单独文件中
  函数调用:
  函数只有被调用才会执行
  函数名出现的地方,会被自动替换为函数代码
  函数的生命周期:
  被调用时创建,返回时终止
  在脚本中用户前必须定义,因此应该将函数定义放在脚本开始部分,直至shell首次
  发现它之后才能使用
  调用函数仅使用其函数名即可
  函数返回值:
  函数由两种返回值:
  函数的执行结果返回值:
  1     使用echo等命令进行输出
  2     函数体中调用命令的输出结果
  函数的退出状态码:
  1      默认取决于函数中执行的最后一条命令的退出状态码
  2     自定义退出状态码,return命令
  return  :        从函数中返回,用最后状态命令决定返回值
  return 0 无错误返回
  return 1-255 有错误返回
  删除函数:
  unset  func_name1
  函数文件:
  创建函数文件:
  #!/bin/bash
  # function.main
  f_hello()
  {
  echo  helio
  }
  f_func2(){
  ...
  }
  ...
  系统自带函数文件:/etc/rc.d/init.d/functions
  使用函数文件:
  可以将进程使用的函数存入函数文件,然后将函数文件载入shell
  文件名可任意选取,但最好与相关任务有某种联系,如  function.main
  一般函数文件载入shell,就可以在命令行或脚本中调用函数,
  可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数
  若要改动函数,首先用unset命令从shell中删除函数,改动完毕后,再重新载入此文件
  载入函数:
  要想使用已创建好的函数文件,要将他载入shell
  使用
  .  /path/filename
  source  /path/filename
  如果使用source 载入函数之后,对函数文件的某个函数做了修改,需要unset函数之后重新载入
  unset  func_name1
  或者exit 重新登录然后再次source
  默认本shell进程有效,如需函数子进程有效,需声明
  export -f func_name
  declare  -xf
  如需查看当前所有的全局函数
  export -f  或 declare -xf
  例如:
  [root@centos6  ~/bin]$export -f func_release
  [root@centos6  ~/bin]$export -f
  func_release ()
  {
  declare  rel=$(cat /etc/centos-release|tr -dc [0-9]|cut  -c1);
  echo  $rel
  }
  declare -fx  func_release
  [root@centos6  ~/bin]$
  函数参数:
  函数可以接受参数:
  调用函数时,在函数名后面以空白分隔给定参数列表即可;
  例如 func_name arg1 arg2 ...
  在函数体当中,可以使用$1,$2..调用这些参数;还可以使用$@,$*,$# 等特殊变量
  注意区分脚本的位置参数和传递给函数的位置参数
  函数变量:
  变量作用域:
  环境变量:    当前shell和子shell有效
  本地变量:    只在当前shell进程有效,为执行脚本会启动专用shell进程;
  因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数
  局部变量:     函数的生命周期;函数结束时变量会被自动销毁
  注意:     如函数中的变量名同本地变量,使用局部变量
  函数中定义局部变量:
  local  name=
  declare name=            declare自带局部变量属性
  declare -ig  在函数中定义普通变量,centos6不支持
  函数递归:
  函数直接或间接调用自身
  注意递归层数
  函数递归示例:
  阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语
  一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0的
  阶乘为1,自然数n的阶乘写作n!
  n!=1×2×3×...×n
  阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n
  n!=n(n-1)(n-2)...1
  n(n-1)! =  n(n-1)(n-2)!
  示例:
  fact.sh
  #!/bin/bash
  func_factorial()
  {
  if [ $1 = 0 ];then
  echo  1
  else
  echo  $[$1*`func_factorial $[$1-1]`]
  fi
  }
  func_factorial  $1
  fork×××:
  fork×××是一种恶意程序,它的内部是一个不断fork进程的无限循环,实质是一个简单
  的递归程序。由于程序是递归的,如果没有任何显示,这会导致整个简单的程序迅速
  耗尽系统所有资源
  函数实现:
  :(){  :|:&};:
  bomb(){ bomb|bomb&};bomb
  脚本实现:
  cat  bomb.sh
  #!/bin/bash
  ./$0|./$0&
  多种语言版本
  数组---------------------------------------------------------------------------------
  变量:     存储单个元素的内存空间
  数组:     存储多个元素的连续的内存空间,相当于多个变量的集合
  数组名和索引:
  索引:编号从0开始,属于数值索引
  bash4.0版本之后,索引可以支持使用自定义的格式,而不仅是数值格式,即为关联索引
  bash中的数组支持稀疏格式(索引不连续)
  声明数组:
  declare -a array_name
  declare -A  ARRAY_NAME 关联索引
  彼此不可互相转化
  数组赋值:
  数组元素的赋值:
  1     一次只赋值一个元素
  array_name[index]=VALUE
  如:
  weekdays[0]=&quot;sunday&quot;
  weekdays[4]=&quot;thursday&quot;
  2     一次赋值全部元素
  array_name=(&quot;VAL1&quot; &quot;val2&quot; &quot;val3&quot;...)
  3     只赋值特定元素
  array_name=([0]=varl [3]=val2...)
  4     交互式数组值对赋值
  read -a array_name1
  如:
  [root@centos7 ~]$read -a  array_name1
  monday  tusday wensday thursday
  [root@centos7 ~]$echo  ${array_name1[@]}
  monday  tusday wensday thursday
  注意:
  如果先赋值单个元素array[0]=a,
  再使用赋值全部 array=(b c d) 或者特定赋值 array=([1]=e [2]=f  [3]=g)
  会使之前单个元素array[0]被覆盖消失
  索引数组可以无需声明直接赋值使用
  关联数组必须先声明之后才能赋值使用
  如:[root@centos7 ~]$array3[0]=mage
  [root@centos7 ~]$array3[1]=zhangsir
  [root@centos7 ~]$echo  ${array3
  • }
      mage  zhangsir
      [root@centos7 ~]$echo  ${array3[1]}
      zhangsir
      [root@centos7 ~]$echo  ${array3[0]}
      mage
      [root@centos7 ~]$array4[ceo]=mage
      [root@centos7 ~]$array4[cto]=zhangsir
      [root@centos7 ~]$echo  ${array4
  • }
      zhangsir
      直接赋值使用关联数组会赋值失败,只显示最后一个值
      数组引用:
      引用数组元素:
      ${array_name[index]}
      注意:省略[index表示引用下标为0的元素]
      引用数组所有元素
      ${array_name[@]}
      ${array_name
  • }
      数组的长度(数组中元素的个数)
      ${#array_name
  • }
      ${#array_name[@]}
      删除数组中的某元素:导致稀疏格式
      unset  array[index]
      删除整个数组
      unset  array
      数组数据处理
      引用数组中的元素:
      数组切片:${array[@]:offset:number}
      offset:     要跳过的元素个数
      number:要取出的元素个数
      ${array[0]:offset}            取偏移量之后的所有元素
      ${array[0]: -n}              取最后n个元素
      ${array[0]::2}                 取开头2个元素
      ${array[0]:  -m:-n}         跳过最后第n+1个到第m个元素间的所有元素
      向数组中追加元素:
      array[${#array
  • }]=
      关联数组:
      declare -A  array_name
      array_name=([idx_name1]=val1 [idx_name2]=val2  ...)
      字符串处理-------------------------------------------------------------------------
      字符串切片:
      ${#var}:                         返回字符串变量var的长度
      ${var:offset}:                  返回字符串变量var中从第off个字符后(不包括第offset个字符)的字符
      开始,到最后的部分,offer的取值在0到${#var}-1之间(bash4.2之后允许为负值)
      ${var:offset:number}:     返回字符串变量var中第off个之后的num个字符(不包含off)
      ${var: -n}:                            取字符串最右侧那个字符(冒号后需加一个空格)
      ${var: -n:-m}:                取倒数第m+1个字符 到 倒数第n个字符
      基于模式取子串:
      ${var#*word}        其中var为变量名,不需要加$引用,word可以是指定的任意字符串
      功能:自左而右,查找var变量所存储的字符串中,第一次出现的word,删除字符串开头
      至第一次出现word字符之间的所有字符
      ${var##*word}
      贪婪模式,删除字符串开头到最后一次”word“指定的字符之间的所有内容
      ${var%word*}         其中word可以是指定的任意字符串
      功能:    自右边而左,查找var变量所存储的字符串中,第一次出现word,删除字符串最后一个字符
      向左至第一次出现word字符之间的所有字符
      ${var%%word*}
      自右而左,删除至最后一个word所指定的字符串
      查找替换:
      ${var/pattern/substr}:
      查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之
      ${var//pattern/substr}:
      替换所有能被pattern所匹配到的字符串,以substr替换
      ${var/#pattern/substr}
      行首被pattern匹配,并替换
      ${var/%pattern/substr}:
      行尾被pattern匹配,并替换
      查找删除:
      ${var/pattern}:               删除第一次被pattern匹配到的字符串
      ${var//pattern}:       删除所有被pattern匹配到的字符串
      ${var/#pattern}:     删除pattern为行首所匹配到的字符串
      ${var/%pattern}:     删除pattern为行尾所匹配到的字符串
      字符串大小写转换:
      ${var^^} 把var中所有的小写字母转换为大写
      ${var,,}    把var中所有的大写字母转换为小写
      高级变量用法:-------------------------------------------------------------------
      变量赋值:
      var=${str-expr}      str为变量,expr为字符串
      如果str没有没配置,var=expr
      如果str配置且为空,var=
      如果str配置且非空,var=$str
      var=${str:-expr}
      如果str没有配置或者为空,var=expr
      如果str已配置且非空:      var=$str
      其他诸多用法,此处不一一列举,如有需要查看相关表格查询
      高级变量用法:有类型变量
      shell变量一般是无类型的,但是bash  shell提供了declare和同样typeset两个命令
      用于指定变量的类型,两个命令是等价的
      declare:
      declare [option] [var]
      -r           声明或显示只读变量
      -i           整型数
      -a          数组
      -A          关联数组
      -f           显示已定义的所有函数名及其内容
      -F           仅显示已定义的所有函数名
      -x          声明或显示环境变量和函数
      -xf 全局函数
      -l           声明变量为小写字母
      -u          声明变量为大写字母
      declare -ig   在函数中定义普通变量,centos6不支持
      eval:
      eval命令将会首先扫描命令进行所有的置换,然后再执行该命令。该命令适用于那些一次
      扫描无法实现其功能的变量:该命令对变量进行两次扫描
      示例:    eval  echo {1..$i}
      间接变量引用:
      如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值
      就称为间接变量引用
      如:
      var1=var2
      var2=nnn
      bash 提供了两种格式实现间接变量引用
      eval  var=\$$var1
      var3=${!var1}
      如:
      var1=var2
      var2=nnn
      var3=${!var1} 或者 eval var3=\$$var1
      echo  $var3
      nnn
      创建临时文件:---------------------------------------------------------------------
      mktemp :
      创建并显示临时文件,可避免冲突
      mktemp [option]..[template]
      template:       filenameXXX
      -d          创建临时目录
      -p DIR 或 --tmpdir=DIR     指明临时文件所存放目录位置
      示例:
      tmpfile1=`mktemp  httptmp-XXX`
      tmpdir=`mktemp -d  /tmp/roottmp-XXXX`
      tmpdir=`mktemp  --tmpdir=/tmp roottmp-XXXX`
      安装复制文件:
      install       命令:
      install [options] source  dest       单文件
      install [] source dir                    单文件
      install [] -t dir source           单文件
      install [] -d  dir            创建空目录
      选项:
      -m mode 默认755
      -o  owner
      -g  group
      示例:
      expect介绍-----------------------------------------------------------------------
      expect 是由Don Libes 基于Tcl(Tool Command Language)语言开发的
      主要应用于自动化交互式操作的场景,借助expect处理交互的命令,可以将交互过程
      如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台
      服务器执行相同操作的环境中,可以大大提供系统管理人员的工作效率
      expect命令:
      expect [选项] [-c cmds] [[ -f[f|b]] cmdfile ]  [args]
      选项:
      -c          从命令行执行expect脚本,默认expect是交互地执行的
      示例:expect -c 'expect &quot;hello&quot; { send &quot;you said  hello\n&quot; }'
      -d          可以输出调试信息
      示例:expect -d ssh.exp
      expect中的相关命令
      spawn           启动新的进程
      send              用户向进程发送字符串
      expect            从进程接受字符串
      interact   允许用户交互
      exp_continue 匹配多个字符串,在执行动作后加此命令
      expect最常用的语法(tcl语言:模式-动作)
      单一分支模式语法:
      expect &quot;hi&quot;  { send &quot;you said hi \n&quot;}
      匹配到hi后,会输出&quot;you said  hi&quot;,并换行
      多分支模式语法:
      expect &quot;hi&quot;  { send &quot;You said hi\n&quot; } \
      &quot;hehe&quot; { send &quot;Hehe yourself\n&quot; } \
      &quot;bye&quot; { send &quot;Good bye\n&quot; }
        匹配hi,hello,bye任意字符串时,执行相应输出。等同如下:
      expect  {
      &quot;hi&quot;  { send &quot;You said hi\n&quot;}
      &quot;hehe&quot;  { send &quot;Hehe yourself\n&quot;}
      &quot;bye&quot;  { send &quot;Good bye\n&quot;}
      }
      expect 示例:
      ssh自动键入密码
      #!/usr/bin/expect
      spawn ssh  192.168.65.132
      expect  {
      &quot;yes/no&quot;  { send &quot;yes\n&quot;;exp_contunue }
      &quot;password&quot;  { send &quot;112233\n&quot;; }
      }
      interact
      #expect  eof
      scp自动键入密码
      #!/usr/bin/expect
      spawn scp /etc/passwd  192.168.65.132:/data
      expect  {
      &quot;yes/no&quot;  { send &quot;yes\n&quot;;exp_continue }
      &quot;password&quot;  {send &quot;112233\n&quot; }
      }
      expect eof
      自动从文件获取ip地址,且登录ip地址机器的root账号,并创建账号
      也可以不用条用,直接在bash脚本中引用expect代码
      cat ssh.exp
      #!/usr/bin/expect
      set ip [lindex $argv  0]
      set user [lindex  $argv 1]
      set password [lindex  $argv 2]
      spawn ssh  $user@$ip
      expect  {
      &quot;yes/no&quot; { send &quot;yes\n&quot;;exp_continue  }
      &quot;password&quot; { send &quot;$password\n&quot;  }
      }
      expect &quot;]#&quot; { send &quot;useradd user1\n&quot; }
      expect &quot;]#&quot; { send &quot;echo nagedu |passwd --stdin  user1\n&quot;}
      send  &quot;exit\n&quot;
      #interact
      expect eof
      cat   sshauto.sh
      #!/bin/bash
      while read ip;do
      user=root
      password=112233
      ssh.exp $ip $user  $password
      done <  /root/bin/ip.txt
      自动从文件获取ip地址,并scp同一文件到所有主机的root目录.txt
      #!/bin/bash
      declare  password=112233
      while read ip;do
      expect

  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-554134-1-1.html 上篇帖子: Linux学习总结(十七) 下篇帖子: Linux shell 编程(七):流程控制语句
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表