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

Shell脚本编程及示例和例题解析

[复制链接]

尚未签到

发表于 2018-8-18 09:49:33 | 显示全部楼层 |阅读模式
  sed及awk命令的总结地址:
  http://10267776.blog.51cto.com/10257776/1696869
  
  Shell脚本的说明:
  shell脚本编程,实际上就是用vim编辑器编辑一个以.sh为结尾的脚本文件,在此脚本文件中使用Linux内部的一个或多个命令,通过编程语言以脚本运行的方式,一次性运行一次一个、一次多个或多次多个命令进行运算,并输出结果,及添加直观的注释。
  Shell脚本的编辑标准格式:
  使用vim编辑器编辑一个自定义创建的文件名并以.sh格式结尾—>
  #!/bin/bash  \\#!是一个约定的标记,他告诉系统这个脚本需要用什么解释权来执行。
  #
  脚本主体  
  \\脚本主体可直接编辑输入参数、命令、函数、shell编程语言等。且脚本主体所编辑的命令是依照顺序执行,即逐个执行。
  \\ bash过程式编程:
  顺序执行:逐个执行
  选择执行:只执行其中一个分支
  循环执行:一段代码要执行0,1或多遍
  编程元素:变量、流程、函数
  脚本编辑结束在末行输入:wq保存退出。
  编辑结束首先要测试我们所编辑的脚本中是否有语法错误:
  bash  -n 脚本名;
  测试语法无误,运行脚本:
  bash  -x 脚本名;
  -------------------------------------------------------------------------------------------
  -------------------------------------------------------------------------------------------
  shell环境中的变量及参数:
  变量:可变化的量,命名内存空间,bash的变量使用特点:弱类型、无须事先声明;
  bash环境:
  本地变量:当前shell进程;
  环境变量:当前shell进程及其子进程;
  局部变量:某个函数执行过程;
  位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;
  特殊变量:
  $$
  Shell本身的PID(ProcessID)
  $!
  Shell最后运行的后台Process的PID
  $?
  最后运行的命令的结束代码(返回值)
  $-
  使用Set命令设定的Flag一览
  $*
  所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
  $@
  所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
  $#
  添加到Shell的参数个数
  $0
  Shell本身的文件名
  $1~$n
  添加到Shell的各参数值。$1是第1参数、$2是第2参数…。
  
  变量类型:
  变量类型的作用:存储空间、运算、存储格式
  数值,字符;
  数值:整数、浮点数;
  字符:ASCII
  变量的具体说明:
  本地变量:
  name=value;
  name: 我们自定义的变量名—>只能包含数字、字母和下划线;且不能以数字开头;
  =:赋值符号;
  value:我们需要给变量名赋予的值;
  引用我们定义的变量:${name}在定义的变量名中含有下划线等特殊字符时必须使用{}来引用变量, $name
  引用:
  弱引用: ""双引号, 其内部的变量引用会被替换为变量值;
  强引用:''单引号,其变量的变量引用会保持原有字符;
  命令引用:`COMMAND`反引号, 也可使用$(COMMAND),引用命令的执行结果;
  声明为整型:
  declare -i name[=value]
  let name=value
  查看所有本地变量:set
  变量的生命周期:
  创建
  销毁:
  自动销毁:shell进程终止;
  手动销毁:unset name
  环境变量:
  被“导出”的本地变量
  export name[=value]
  declare -x name[=value]
  查看所有环境变量:env, printenv, export
  销毁:
  unset name
  脚本:文本文件标准命名—>name.sh
  
  运行脚本:事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,而后由bash进程负责解析并运行此逻辑;
  启动脚本:
  (1) # bash  /PATH/TO/SCRIPT_FILE
  (2) 给脚本一个执行权限即可直接通过脚本路径运行脚本:
  # ./PATH/TO/SCRIPT_FILE
  脚本格式我们在开始已经提过了,可回到首部查看;
  我们在开始说过如何执行脚本,那执行脚本就必然会有成功或失败,当我们执行脚本以后可以使用 $? 命令查看上一条命令执行状态结果:
  命令状态结果:
  bash进程用于追踪执行的命令成功与否的状态:
  0: 成功
  1-255:失败
  $?:上一条命令的执行状态结果;
  我们可在脚本中自定义脚本的状态结果:
  在脚本中敲入命令exit [n]—>n为我们想要输出的数字
  注意:脚本中任何位置执行了exit命令即会终止当前shell进程;
  条件测试:
  界定程序执行环境;
  (1) 根据运行的命令的状态结果;
  (2) 测试表达式: EXPR 表达式
  test EXPR
  [ EXPR ]
  ` EXPR`
  整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;
  $A -gt $B:是否大于;是则为“真”,否则为“假”;
  $A -ge $B: 是否大于等于;
  $A -lt $B:是否小于;
  $A -le $B: 是否小于等于;
  $A -eq $B: 是否等于;
  $A -ne $B:是否不等于;
  字符串测试:ASCII数值越大,字符比较时其值越大;
  "$A" > "$B":是否大于;
  "$A" < "$B":是否小于;
  "$A" == "$B":是否等于;
  "$A" != "$B":是否不等于;
  -z "$A":是否为空;空则为“真”,否则为“假”
  -n "$A":是否不空;不空则“真”,空则为“假”
  注意:应该使用` EXPRESSION `
  文件测试:测试文件的存在性以及属性;
  -e $file: 是否存在;存在则为“真”,否则为“假”;
  -f $file:文件是否存在且为普通文件;
  -d $file:文件是否存在且为目录;
  -h $file:是否存在且为符号链接文件;
  -b $file:是否存在且为块设备文件;
  -c $file:是否存在且为字符设备文件;
  -S $file:是否存在且为套接字文件;
  -p $file: 是否存在且为管道文件;
  -r $file: 当前用户对文件是否拥有读权限;
  -w $file:当前用户对文件是否拥有写权限;
  -x $file:当前用户对文件是否拥有执行权限;
  -u $file:文件是否拥有SUID权限;
  -g $file:文件是否拥有SGID权限;
  -k $file:文件是否拥有sticky权限;
  注:SUID,SGID,sticky为文件特殊权限,如果有同学不熟悉,可以自行复习。为了方便理解,我们这里还是列出来:
  sticky bit (粘贴位)就是:除非目录的属主和root用户有权限删除它,除此之外其它用户不能删除和修改这个目录。
  suid就是:让普通用户拥有可以执行“只有root权限才能执行”的特殊权限,sgid同理指”组“
  -O $file: 当前用户是否为指定文件的属主;
  -G $file: 当前用户是否为指定文件的属组;
  双目操作符:
  $file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的;
  $file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的;
  $file1 -ef $file2:file1与file2是否指向了同一个inode,
  测试二者是否为同一个文件的硬链接;
  特殊设备:
  /dev/null: 空,bit buckets,吞下所有数据,并直接丢弃;
  /dev/zero:吐出一堆0;
  bash之条件判断(选择执行):
  if/then ;case
  if CONDITION; then
  if-true-分支
  fi
  if CONDITION; then
  if-true-分支
  else
  if-false-分支
  fi
  ! CONDITION: 取反
  -----------------------------------------------------------------------------------------------------------------
  脚本参数(位置参数变量):
  # ./script.sh  /etc/fstab  /etc/grub2.cfg
  $0       $1        $2
  注:为了更易于理解,我们进行下面说明:
  参数$0—>shell自身文件,$1—>shell中定义的第一个参数,$2—>shell中定义的第二个参数,以此类推。
  特殊变量:
  $?: 命令的状态结果;
  $#: 传递给脚本或函数的参数的个数;
  $*和$@: 引用传递给脚本或函数的参数列表;
  为了更直观的理解这些特殊变量,我们来做一个脚本小测试:
DSC0000.jpg

  与用户交互:
  read命令:
  read [options] VAR...
  -p "PROMPT"
  -t timeout
  示例:-t5 5秒后超时退出交互。
DSC0001.jpg

  引用命令的执行结果;
  (1) ls `which cat`
  (2) lines=$(wc -l /etc/fstab | cut -d' ' -f1)
DSC0002.jpg

  --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  循环语句:循环就是通过循环编程对循环体进行多次运行,直到结果匹配给定的退出循环条件。
  循环语句有:for, while, until
  VARIABLE 定义的变量
  for VARIABLE in LIST; do
  循环体
  done
  LIST:是由一个或多个空格或换行符分隔开的字符串组成;
  即 可使用LIST 给一个变量进行多次逐个赋值;
  LIST 不为空时进入循环,LIST逐个赋值直到最后一个结束后循环结束,即退出循环;
  for username in user1 user2 user3; do
  循环体
  done
  示例:
  添加10个用户,user1-user10;
DSC0003.jpg

  LIST的生成方法:
  (1) 整数列表
  (a) {start..end}
  (b) $(seq [start `step` end)
  (2) 直接给出列表
  (3) glob
  (4) 命令生成
  示例:数值列表
DSC0004.jpg

  
  示例:glob,即定义参数变量为绝对路径下的文件:
  #!/bin/bash
  #
  for filename in /var/log/*; do
  file $filename
  done
DSC0005.jpg

  
  示例:命令生成列表
  #!/bin/bash
  #
  for username in $(cut -d: -f1 /etc/passwd); do
  echo "$username primary group: $(id -n -g $username)."
  Done
DSC0006.jpg

  Shell脚本中的算术运算:
  +, -, *, /, %, **
  (1) $[$A+$B]
  (2) $(($A+$B))
  (3) let VARIABLE=$A+$B
  (4) VARIABLE=$(expr $A + $B)
  示例:求100以内所以正整数之和;
DSC0007.jpg

  增强型赋值:
  +=
  sum=$[$sum+$i]可写为:let sum+=$i
  -=, *=, /=, %=
  let count=$[$count+1]   --> let count+=1 --> let count++
  let count=$[$count-1]  --> let count-=1 --> let count--
  示例:显示/etc目录下所有普通文件列表,而后统计一共有多少个文件;
DSC0008.jpg

  测试表达式:
  整数测试:-gt, -lt, -ge, -le, -eq, -ne
  字符串测试:==, >, 比较命令hostname的结果是否为localhost;
  (2) 模式匹配测试:[[ "STRING" =~ PATTERN ]]
  组合测试条件:
  条件间逻辑运算:
  与:多个条件要同时满足;
  或:多个条件满足其一即可;
  非:对指定的条件取反;
  表达式组合:
  与:` CONDITION1 -a CONDITION2 `
  或:` CONDITION1 -o CONDITION2 `
  非:[ ! CONDITION ]
  命令组合:
  与:COMMAND1 && COMMAND2   /dev/null; then
  echo "$username is logged."
  break
  else
  let count++
  echo "$count $username is not login."
  fi
  sleep 3
  done
  #!/bin/bash
  #
  declare -i count=0
  username=$1
  if [ $# -lt 1 ]; then
  echo "At lease one argument."
  exit 1
  fi

  if !>  echo "No such user."
  exit 2
  fi
  until who | grep "^$username" &> /dev/null; do
  let count++
  echo "$count $username is not login."
  sleep 3
  done
  echo "$username is logged on."
  while循环的特殊用法:
  遍历文件的每一行:
  while read VARIABLE; do
  循环体
  done < /PATH/FROM/SOME_FILE
  示例:找出UID为偶数的所有用户,显示其用户名和ID号;
  #!/bin/bash
  #
  while read line; do
  userid=$(echo $line | cut -d: -f3)
  if [ $[$userid%2] -eq 0 ]; then
  echo $line | cut -d: -f1,3
  fi
  done < /etc/passwd
  for循环的特殊用法:
  for ((expr1;expr2;expr3)); do
  循环体
  done
  expr1: 定义控制变量,并初始赋值;
  expr2: 循环控制条件;
  进入条件:控制条件为“真”
  退出条件:控制条件为“假”
  expr3: 修正控制变量
  示例:求100以内所有正整数之和;
  #!/bin/bash
  #
  declare -i sum=0
  for ((i=1;i  return 2
  fi
  userid=$(id -u $1)
  if [ $[$userid%2] -eq 0 ]; then

  echo "$1, Even user>  else

  echo "$1, Odd user>  fi
  }
  evenid root
  evenid
  echo $?
  evenid rooooooooooooot
  echo $?
  -------------------------------------------------------------------------------------------
  模块化编程
  功能:把脚本文件中的代码分隔为多段,放在不同的文件中
  假设/root/bin/srv目录有两个文件:
  (1) 函数文件
  (2) 脚本文件
  为脚本使用配置文件
  一个文件中只定义变量
  脚本文件source此变量定义的文件
  可将脚本分为两个文件,在运行的文件中使用source PATH引用另一个配置文件;
  变量的作用域:
  局部变量:在当脚本中存在其他变量与函数中定义的变量重复时时,需要使用local命令来使函数中的变量变为局部变量:
  local VARIABLE=value
  局部变量存活时间:
  函数执行开始,至函数返回结束;
  -------------------------------------------------------------------------------------------
  -------------------------------------------------------------------------------------------
  作业:
  1写一个脚本
  如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;
DSC0009.jpg

  2 写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:脚本参数,命令交互;
DSC00010.jpg

  3.求100以内所有偶数之和;
  使用至少三种方法实现;
  1).seq语法表示0 2 100:0-100 每次隔2.
DSC00011.jpg

  2).与上个方法不同的就是变量i的赋值方式不同:
DSC00012.jpg

  3).此方法使用函数调用法:
DSC00013.jpg

  4.写一个脚本(1) 传递两个文本文件路径给脚本;
  (2) 显示两个文件中空白行数较多的文件及其空白行的个数;
  (3) 显示两个文件中总行数较多的文件及其总行数;
DSC00014.jpg

  5.写一个脚本
  (1) 提示用户输入一个字符串;
  (2) 判断:
  如果输入的是quit,则退出脚本;
  否则,则显示其输入的字符串内容;
DSC00015.jpg

  6.写一个脚本,打印2^n表;n等于一个用户输入的值;
  Resolution:这题主要思路就是首先定义一个循环变量i,然后使用read读取交互输入的$num,接着进行循环运算,定义退出循环条件:使循环变量$i小于$num,i从0开始赋值,然后进行数值运算:2**$i。
DSC00016.jpg

  7.写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、两个数值的大小都将通过交互式输入来提供。
  由于此处脚本过长,所以此处给出编程代码,并附上脚本运行结果:
  此处本人写出两套方案,一个简单易懂,一个细化分类:
  #!/bin/bash
  #
  if [[ $# -le 2 ]];then
  echo "plz input two number and use space to isolation them!"
  fi
  function add() {
  echo "The two num sum:$1+$2=`expr $1 + $2`"
  }
  add $1 $2
  declare -i big
  declare -i sma
  if [ $1 -gt $2 ];then
  big=$1
  sma=$2
  else
  big=$2
  sma=$1
  fi
  gcdlcm(){
  i=1      #定义一个循环变量
  GCD=1    #定义最大公约数
  LCM=1    #定义最小公倍数
  btmp=1   #定义用户输入的较大的一个变量除以循环变量的值
  stmp=1   #定义用户输入的较小的一个变量除以循环变量的值
  while [ $i -le $sma ];do     #定义循环条件,循环变量小于或等于用户输入的较小的变量
  btmp=`expr $big % $i`      #求值
  stmp=`expr $sma % $i`      #求值
  if [ $btmp -eq 0 ];then  #判断值得余数是否为0
  if [ $stmp -eq 0 ];then  #同上
  gcd=$i    #如果值得余数为0,则获取最大公约数的值
  fi   #判断结束
  fi
  i=`expr $i + 1`   #i变量循环,直到i等于用户输入的较小的数为止退出循环。
  done   #当i=$sma,退出循环
  lcm=`expr $sma / $gcd`   #根据最小公倍数公式求值
  lcm=`expr $lcm \* $big`  #同上,求最小公倍数公式为:lcm=$sma*$big%gcd
  echo "lcm:$lcm"    #输出lcm值
  echo "gcd:$gcd"    #输出gcd值
  }
  第二种方法:
  #!/bin/bash
  #
  if [[ $1 -eq "" ]];then
  echo 'plz input the first number'
  exit 1
  fi
  if [[ $2 -eq "" ]];then
  echo 'plz input the second number'
  exit 2
  fi
  function add() {
  sum=$[$1+$2]
  echo "the sum is $sum"
  }
  add $1 $2
  declare -i max
  declare -i min
  if [[ $1 -gt $2 ]];then
  max=$1
  min=$2
  elif [[ $1 -lt $2 ]];then
  max=$2
  min=$1
  else
  max=$1
  min=$2
  fi
  function gong() {
  r=$[$max%$min]
  temp=$min
  declare -i a
  declare -i b
  if [[ $r -eq 0 ]];then
  echo "gongyue is $min"
  echo "gongbei is $max"
  else
  while [[ $r -ne 0 ]];do
  a=$2
  b=$r
  r=$[$a%$b]
  done
  gongyue=$b
  gongbei=$[$1*$2/$b]
  echo "gongyue is $gongyue"
  echo "gongbei is $gongbei"
  fi
  }
  gong $1 $2
DSC00017.jpg



运维网声明 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.iyunv.com/thread-553319-1-1.html 上篇帖子: 如何使windows下的bat文件调用linux下的shell脚本的方法 下篇帖子: JS + shell 批量下载 喜马拉雅FM 的音频
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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