加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_新乡站长网 (https://www.0373zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

UNIX Shell变量 万字总结 | 完全掌握Shell编程

发布时间:2022-12-19 11:25:05 所属栏目:Unix 来源:
导读:  对于Linux平台下的开发者和维护人员来说,Shell编程是必须要掌握的一个知识点。通过Shell脚本能够将十分复杂的操作进行简化,从而大大的提高我们工作效率。

  什么是Shell?

  实际上,Shell是一个比
  对于Linux平台下的开发者和维护人员来说,Shell编程是必须要掌握的一个知识点。通过Shell脚本能够将十分复杂的操作进行简化,从而大大的提高我们工作效率。
 
  什么是Shell?
 
  实际上,Shell是一个比较宽泛的概念,它可以有多种含义。比如,一个终端或命令行软件我们可以称为Shell,实际上它就是一个应用程序,是人与系统进行交互的一个操作界面;它也是一种程序语言或者命令语言,可以通过它编译一系列的脚本。
 
  作为Shell终端软件来说,它实际上也是属于泛指。之所以这么说是因为Shell终端软件也有多种。不过,基本上所有的Linux和大多数的Mac OS X里默认用的都是Bourne Again Shell,也就是平时我们说的bash。它早在1987年由Brian Fox开发。
 
  除bash之外,还有其他的Shell应用程序:
 
  Shell应用程序
 
  然而,今天我们要学习的实际上是在Shell上执行的脚本语言,所以我们说Shell脚本编程。由于它是一种解释性语言,Shell脚本编程不需要额外的安装编译器,它可以直接用编辑器直接编辑,然后直接在Shell上直接运行即可。通常,我们在编写脚本时,在第一行需要用#!来指定解释器来运行Shell脚本,比如,#!/bin/sh。
 
  下面我们将为大家从如下几个方面全面系统的为大家梳理Shell编程的相关知识点。
 
  Shell编程
 
  输入输出
 
  shell中有两种输出命令:echo和printf。学习程序,生硬的文字始终没有代码来的直接易懂。我们就直接通过例子来学习吧。
 
  echo "hello world"
  printf "%s %s" "hello" "world"
  printf "!!!\n"
  output
 
  从上面的例子很容易发现,echo命令默认带有换行符的,而printf则不是。与C语言中类似,printf是可以进行格式化输出的,其中,%s就是格式控制符,还有%c %d %f等控制符。另外,还可以通过在控制符中添加数字来制定字符的长度,比如,%3s表示三个字符长度;%4.3f表示4位整数,3位小数。
 
  #!/bin/sh
  printf "%6s %3s %4s %5s\n" 公司名 评级 销售额 市场占比
  printf "%6s %3c %4d %5f\n" 公司A A 5001 0.5001
  printf "%6s %3c %4d %5f\n" 公司B C 1999 0.1999
  printf "%6s %3c %4d %5f\n" 公司B B 3000 0.3
  printf
 
  如果需要字符对齐,还可以使用-进行字符左对齐,省略不加默认右对齐。
 
  在shell中是使用read命令作为输入,它可以接受标准键盘的输入;除此之外,也可以作为文件描述符的输入,对文件进行操作。
 
  read命名的格式如下:
 
  read [选项名] [变量名]
  read命令在执行时,会将输入的数据放到变量中,通常,我们会指定一个自定义的变量,如果不指定变量的话,则就会把输入的数据保存到REPLY变量中。关于变量的一些具体信息可以在下面的变量章节了解。
 
  read命令的选项名有下面几种参数,我们可以选择一种或几种进行设置。
 
  具体的使用方法大家可以参考下面的例子:
 
  #!/bin/sh
  read -p "input a name:" name
  read -p "input a password:" -s passwd
  echo ""
  echo $name
  echo $passwd
  read
 
  注释
 
  每种语言都少不了注释,对于Shell也是一样。一个好的注释可以让代码更容易阅读和维护。shell脚本里也可以使用两种注释:单行注释和多行注释。单行注释可以直接在所在行使用#,多行注释就需要:!。
 
  # 这是一行内容
  # 这是一行内容
  :<
  对于多行注释除了用!符号外,还可以用EOF '等符号。
 
  除了这两种方法之外,还可以通过条件语句来实现。
 
  变量
 
  Shell可以定义变量,并通过=给变量赋值,与其他语言不同的是,在=和变量及被赋的值之间不能有空格。习惯了其他语言的同学可能会有些不适应,不过要注意这一点。
 
  对于命名的规则,其实是与其他语言是类似的:
 
  v1=1234 #正确
  v2="hello" #正确
  v3_1="world" #正确
  v4_1 = "world" #错误,‘=’符前后不能有空格
  除此之外,在访问变量时需要在变量前$符来访问,如果需要区分变量的边界,还需要在变量前后加上{}用来区分变量名的边界,建议在使用变量时加上{}。
 
  a="hell world:"
  b="一个敲代码的厨子"
  echo ${a}${b}
  Shell的数据类型比较简单,变量的默认数据类型是字符串类型。我们可以使用单引号或双引号,因此,也是可以不用引号的。
 
  我们再来看一个例子:
 
  a=1
  b=2
  echo ${a}+${b}
  大家觉得最后应该输出多少呢?
 
  答案是不是超出了大家的预料?这样大家应该理解了为什么说Shell定义变量时默认是字符串类型。
 
  那么问题来了,该怎么表示数字呢?其实,这里我们稍微进行特殊处理一下就可以了,在数据运算的时候我们用$[运算表达式]形式就可以了。
 
  a=1
  b=2
  echo $[${a}+${b}]
  a+b
 
  除了这种方法,还有其他的方法可以进行数据运算,我们在后面的数据运算章节在详细展开,我们接着说变量。
 
  我们可以将变量分成局部变量和环境变量:
 
  在一些特殊的场景,我们不希望我们定义的变量数值被改变,这时,我们可以使用readonly命令将变量设置成只读。
 
  a="hello world"
  readonly a
  echo ${a}
  a="hahah"
  还有一些场景需要清除一个变量,我们可以使用unset命令将变量删除,需要注意的是对于只读变量是不能删除的。
 
  a="hello world"
  b="一个敲代码的厨子"
  readonly b
  unset a
  unset b
  echo ${a}
  echo ${b}
  字符串变量操作
 
  了解了上面变量的内容之后,我们知道变量模式是字符串类型的。那字符串的操作有哪些呢?
 
  一般我们可以会对字符串变量进行如下操作:
 
  下面,我们可以从下面的例子更直观的了解这些操作。
 
  a="Hello World"
  echo "${#a}" #获取字符串长度
  echo "${a:6:3}" #从下标6开始截取3字符
  echo "${a/ll/hh}" #将字符串中的ll替换为hh
  echo "${a/or/}" #删除子字符串or
  echo "${a^^}" #全部转化成大写
  echo "${a,,}" #全部转化成小写
  字符串操作
 
  数字运算
 
  在上面的变量章节,我们学习到了可以使用$[运算表达式]形式,使数字变量进行运算。这一章节,我们将会详细了解数字运算。实际上Shell可以使用命令和运算表达式的方式进行数字运算,它们可以支持+ - * / %等算术运算。
 
  命令方式主要有let declare expr等命令,下面我们一一通过例子来学习他们的使用。
 
  通过let命令进行数字运算,let命名后直接跟上运算表达式即可。
 
  #!/bin/sh
  a="4"
  b="2"
  let c1=${a}+${b}
  let c2=${a}-${b}
  let c3=${a}*${b}
  let c4=${a}/${b}
  let c5=${a}%${b}
  echo "a + b =" ${c1}
  echo "a - b =" ${c2}
  echo "a * b =" ${c3}
  echo "a / b =" ${c4}
  echo "a % b =" ${c5}
  let命令
 
  通过expr命令进行数字运算,可以查看下面的示例代码,但是需要注意两点:
 
  #!/bin/sh
  a=4
  b=2
  c1=$(expr ${a} + ${b})
  echo "a + b =" ${c1}
  c2=$(expr ${a} - ${b})
  echo "a - b =" ${c2}
  c3=$(expr ${a} \* ${b})
  echo "a * b =" ${c3}
  c4=$(expr ${a} / ${b})
  echo "a / b =" ${c4}
  c5=$(expr ${a} % ${b})
  echo "a % b =" ${c5}
  expr
 
  declare命令也可以进行数字运算,它的参数选项中有一个-i选项,它可以将变量声明为整数型,因此,我们也可以通过declare实现数字的运算。
 
  #!/bin/sh
  a="4"
  b="2"
  declare -i c1=${a}+${b}
  declare -i c2=${a}-${b}
  declare -i c3=${a}*${b}
  declare -i c4=${a}/${b}
  declare -i c5=${a}%${b}
  echo "a + b =" ${c1}
  echo "a - b =" ${c2}
  echo "a * b =" ${c3}
  echo "a / b =" ${c4}
  echo "a % b =" ${c5}
  declare命令 declare命令
 
  通过运算表达式实现数字运算的方式,主要有$((运算表达式))和$[运算表达式],我们依次来看看他们的使用方法。
 
  #!/bin/sh
  a=4
  b=2
  c1=$((${a}+${b}))
  c2=$((${a}-${b}))
  c3=$((${a}*${b}))
  c4=$((${a}/${b}))
  c5=$((${a}%${b}))
  echo "a + b =" ${c1}
  echo "a - b =" ${c2}
  echo "a * b =" ${c3}
  echo "a / b =" ${c4}
  echo "a % b =" ${c5}
  表达式方式1
 
  #!/bin/sh
  a=4
  b=2
  c1=$[${a}+${b}]
  c2=$[${a}-${b}]
  c3=$[${a}*${b}]
  c4=$[${a}/${b}]
  c5=$[${a}%${b}]
  echo "a + b =" ${c1}
  echo "a - b =" ${c2}
  echo "a * b =" ${c3}
  echo "a / b =" ${c4}
  echo "a % b =" ${c5}
  表达式方式2
 
  除了这些运算之外,shell也支持自增和自减运算,这里以let命令为例:
 
  #!/bin/sh
  c1=2
  c2=2
  c3=2
  let c1++
  let c2--
  let c3+=1
  echo "c1 =" ${c1}
  echo "c2 =" ${c2}
  echo "c3 =" ${c3}
  自增和自减
 
  上面的这些运算方法都有各自的要求,在使用的时候我们一定要清楚它们的使用方法。另外,在默认情况下shell是不支持小数运算,大家可以发现上面的运算都是整数运算,怎么进行小数运算呢?
 
  我们可以借助Linux平台下的bc计算器进行小数运算。
 
  #!/bin/sh
  a=1.411
  b=1.332
  c1=`echo "$a+$b"|bc`
  c2=`echo "$a-$b"|bc`
  c3=`echo "$a*$b"|bc`
  c4=`echo "scale=3;$a/$b"|bc` #scale用来指定小数的位数
  echo $c1
  echo $c2
  echo $c3
  echo $c4
  小数运算
 
  数组
 
  Shell可以定义数组用来存放多个数据,格式如下,数组中的各个元素需要使用空格隔开,数组在定义时可以不用指定数组的大小。
 
  array=(value1 value2 value3 ...)
 
  在访问数组时,可以使用中括号和下标([下标])访问各个元素,它的下标也是从0开始的。
 
  #!/bin/sh
  a=(hello world code)
  echo ${a[0]}
  echo ${a[1]}
  echo ${a[2]}
  数组访问
 
  除了用下标访问单个元素之外,是否有其他方法获取所有元素呢?我们可以使用*和@符号获取数组的所有元素。这两个符号是不是很熟悉?我们在字符串变量操作章节用到过这两个符号。
 
  #!/bin/sh
  a=(hello world code)
  echo ${a[*]}
  echo ${a[@]}
  获取数组所有元素
 
  同样的,与获取字符变量长度类似,我们也可以使用#符号来获取数组的长度。
 
  #!/bin/sh
  a=(hello world code)
  echo ${#a[*]}
  获取数组长度
 
  关系运算
 
  关系运算也就是比较运算,因为在shell里都是字符串类型,我们怎么比较数字的大小呢?shell中专门提供了一些专门用来关系运算的运算符。如下:
 
  这里要注意变量和中括号两边是有空格隔开,运算符和变量之间也有空格隔开,具体我们可以通过一个例子来进一步了解它们的使用。
 
  #!/bin/sh
  a=1
  b=2
  if [ $a -eq $b ];then
   echo "yes"
  else
   echo "no"
  fi
  if [ $a -ne $b ];then
   echo "yes"
  else
   echo "no"
  fi
  if [ $a -gt $b ];then
   echo "yes"
  else
   echo "no"
  fi
  if [ $a -lt $b ];then
   echo "yes"
  else
   echo "no"
  fi
  这里用到了判断语句if...else,详细内容可以在条件语句章节再深入了解。
 
  关系运算
 
  上面的是数值关系运算,当然,对于字符串同样也有类似的元素符。
 
  #!/bin/sh
  a="hello"
  b="hello"
  c="world"
  d=""
  echo "a = b ?"
  if [ $a = $b ];then
   echo "yes"
  else
   echo "no"
  fi
  echo "a != b ?"
  if [ $a != $b ];then
   echo "yes"
  else
   echo "no"
  fi
  echo "a != c ?"
  if [ $a != $c ];then
   echo "yes"
  else
   echo "no"
  fi
  echo "len(c) = 0 ?"
  if [ -z $c ];then
   echo "yes"
  else
   echo "no"
  fi
  echo "len(d) != 0 ?"
  if [ -n "$d" ];then
   echo "yes"
  else
   echo "no"
  fi
  echo "len(a) = 0 ?"
  if [ $a ];then
   echo "yes"
  else
   echo "no"
  fi
  字符串
 
  逻辑运算
 
  除了我们上面介绍的算术运算和关系运算,Shell还有逻辑运算。逻辑运算主要有逻辑与和逻辑或运算。
 
  我们通过一个例子来对逻辑运算进一步了解。
 
  #!/bin/sh
  a=1
  b=2
  c=1
  echo "a = c && a != b ?"
  if [[ $a -eq $c && $a -ne $b ]];then
   echo "yes"
  else
   echo "no"
  fi
  echo "a = b || a = c ?"
  if [[ $a -eq $b || $a -eq $c ]];then
   echo "yes"
  else
   echo "no"
  fi
  逻辑运算
 
  条件语句
 
  与其他语言一样,shell脚本编程也可以进行流程控制,比如,条件语句,循环语句等,这一章节我们学习条件语句。
 
  条件语句中主要通过if else then elif fi等关键字组成,主要可以组成下面几种情况:
 
  单分支这种情况UNIX Shell变量,结构比较简单,一个条件一个执行分支。
 
  a=1
  if [ $a == 1 ];then
      echo "a = 1"
  fi
  单分支
 
  双分支的情况,比单分支多一个执行分治。
 
  a=1
  if [ $a == 2 ];then
      echo "a = 1"
  else
   echo "a != 1"
  fi
  双分支
 
  多分支结构比较适合多种条件,多个执行分支的情况。
 
  a=2
  if [ $a == 1 ];then
      echo "a = 1"
  elif [ $a == 2 ];then
   echo "a = 2"
  else
   echo $a
  fi
  多分支
 
  对于if的分支语句大家要注意格式问题,在[]里的条件表达式一定要和两边中括号符号用空格隔开。
 
  此外,还有一种多分支语句case语句,格式为:
 
  case $变量 in
      "value1")
          执行语句1
          ;;
      "value2")
          执行语句2
          ;;
      *)
          执行其他语句
          ;;
  esac
  我们看一个case语句的示例:
 
  #!/bin/sh
  read -p "please in put a number:" num
  case $num in
  "1")
   echo "Start 1th flow"
   ;;
  "2")
   echo "Start 2th flow"
   ;;
  *)
   echo "Do nothing"
  esac
  case语句
 
  上面的这些只是一些简单的语句结构,大家只要掌握了这几种分支语句的用法,就可以组成更加复杂的分支语句,比如,多个判断条件,多个分支嵌套等。
 
  循环语句
 
  用于流程控制的另一种方式是循环语句,Shell中常见有for while until select这四种循环语句。下面我们依次来了解这四种循环方式。
 
  for循环for(())和for...in这两种形式,我们可以根据自己的需要进行选择。
 
  先来看看for(())这种循环格式:
 
  for((ex1;exp2;exp3))
  do
    循环体
  done
  这里我们可以结合的数组的知识来举个循环的栗子。
 
  a=("hello" "world" "hello" "shell")
  for((i=0;i<4;i++))
  do
   echo ${a[i]}
  done
  for循环
 
  我们通过定义一个递增变量i,依次访问数组各个元素。有没有更简单的变量方法呢?我们再看下面一个例子。
 
  a=("hello" "world" "hello" "shell")
  for v in ${a[*]}
  do
   echo $v
  done
  for...in
 
  上面的例子用的是第二种for...in的循环格式,其格式如下,它可以方便的遍历一个列表或数组,而不需再定义递增/递减变量。
 
  for var in list
  do
    循环体
  done
  接下来我们看while循环,while循环的格式如下,
 
  while [ 条件表达式 ]
  do
    循环体
  done
  再看一个例子:
 
  a=("hello" "world" "hello" "shell")
  i=0
  while [ $i -lt 4 ]
  do
   echo ${a[i]}
   let i++
  done
  while
 
  while循环需要注意条件表达的写法,相信看了上面的关于条件语句的同学已经很清楚了。
 
  在shell中有一个与while循环恰好相反的循环until循环;在while循环中条件表达式成立就会进入循环体,而在until循环中条件表达式不成立才会进入循环,until循环的格式如下:
 
  until [ 条件表达式 ]
  do
    循环体
  done
  我们将上面while循环例子的条件表达式稍加改动。
 
  a=("hello" "world" "hello" "shell")
  i=0
  until [ $i -ge 4 ]
  do
   echo ${a[i]}
   let i++
  done
  until
 
  对于until循环语句来说,一般没有上面的几种循环语句较为常用。
 
  最后,还有一种较为特殊的循环select,我们先看一下它的格式:
 
  select var in list
  do
      statements
  done
  为什么说它是一种特殊的循环?我们看下面这个例子:
 
  a=("hello" "world" "hello" "shell")
  i=0
  select v in ${a[*]}
  do
   echo $v
  done
  select
 
  从这里例子上,我们可以发现在每行打印前面都有一个序号,我们还可以选择其中一个序号,会输出对应需要的结果。它是shell中特有的一种结构,通常和case...in语句一起使用,通过根据选择的序号不同,可以选择执行case...in里不同的动作。
 
  a=("公司A" "公司B" "公司C" "公司D")
  select v in ${a[*]}
  do
   case $v in
    "公司A")
     echo "恭喜您,你选择了公司A !"
     break
     ;;
    "公司B")
     echo "恭喜您,你选择了公司B !"
     break
     ;;
    "公司C")
     echo "恭喜您,你选择了公司C !"
     break
     ;;
    "公司D")
     echo "恭喜您,你选择了公司D !"
     break
     ;;
    *)
     echo "您没有选择任何一个公司,请重新选择!"
    esac
  done

  select in 和 case in
 
  函数
 
  在一个复杂的功能的脚本程序中,会有很多重复或相似的功能,为了避免大量的重复代码,这个时候函数的作用体现出来了。一般的我们会将一些相似的或重复的操作抽象成一个函数,并根据参数的不同返回相应的结果。这样程序将更具模块化,逻辑也更加清楚,便于开发和维护。
 
  当然,在shell中也可以使用函数。其格式如下:
 
  function name() {
      # 函数体
      return value
  }
  这里function是用来定义函数的关键字,name是需要我们自定义的函数名,return value是函数的返回值。现在我们来定义一个函数:
 
  function test1() {
   echo "this is a function"
  
   return 0
  }
  该怎么调用函数呢?直接写函数名即可,我们看一个完整版程序:
 
  function test1() {
   echo "this is a function"
  
   return 0
  }
  test1 #调用函数
  函数1
 
  上面函数没有带参数的,那如果有参数怎么办呢?我们继续看例子:
 
  function test2() {
   echo "parameter1 : $1"
   echo "parameter2 : $2"
  
   return 3
  }
  test2 1 2 #调用函数
  echo $? #获取函数返回值
  函数2
 
  实际上,函数中是不要定义形参的,在调用时在函数后面加上实参就可以了。而函数体中可以通过$加参数编号访问参数,比如,第一个参数$1,到第十个参数以上就需要加上{}符号,比如${10},而函数返回值需要在调用该函数后通过$?获得。
 
  文件包含
 
  有的时候某个功能可能被多个脚本使用,这时就需要在将这个功能放到一个公共的文件中,需要这个功能的脚本直接包含这个公共的文件即可,这就是文件的包含,同样的Shell也是支持文件包含的。
 
  在Shell中可以使用.或source加上文件名来包含文件。直接来看例子:
 
  先建一个文件test_one.sh:
 
  #test_one.sh
  var1=1
  再建一个文件test_two.sh:
 
  #test_two.sh
  var2=2
  下面我们在建一个文件包含test_one.sh和test_two.sh这两个文件。
 
  . ./test_one.sh
  source ./test_two.sh
  echo "file one var1=${var1}"
  echo "file two var2=${var2}"
  文件包含
 
  这里需要注意.和./test_one.sh文件之间是有一个空格。
 
  最后
 
  至此,我们已经学会了shell编程的一些基本知识。文中使用的都是一些简单的例子,在实际的shell脚本中往往都是比较复杂的逻辑。不过,再复杂的代码也是有这些简单的结构组成。因此,大家一定要有一个扎实基础和掌握一个完整的shell知识体系。
 

(编辑:开发网_新乡站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章