暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Shell脚本基础(大全)

阿Q正砖 2023-01-06
389

1.shell脚本基础

1.1 shell环境

shell分类

Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Linux 的 Shell 种类众多,常见的有:

  • Bourne Shell(/usr/bin/sh或/bin/sh)

  • Bourne Again Shell(/bin/bash)

  • C Shell(/usr/bin/csh)

  • K Shell(/usr/bin/ksh)

  • Shell for Root(/sbin/sh)

  • ……

Mac系统默认的是zsh环境,ubuntu下默认的shell环境是bash环境,可以通过执行命令查看:

    # ubuntu终端
    xq@ubuntu:~$ echo $SHELL
    /bin/bash


    # mac电脑终端
    ➜ ~ echo $SHELL
    /bin/zsh

    一般系统都会内置几种shell,可以通过命令chsh
    修改系统默认的shell环境,在下次打开终端生效,修改示例如下:

      # 查看系统中已安装的shell类型
      xq@ubuntu:~$ cat etc/shells
      # etc/shells: valid login shells
      /bin/sh
      /bin/bash
      /usr/bin/bash
      /bin/rbash
      /usr/bin/rbash
      /bin/dash
      /usr/bin/dash
      /bin/zsh
      /usr/bin/zsh


      # 切换默认的shell环境到zsh
      xq@ubuntu:~$ chsh -s bin/zsh


      # 切换默认的shell环境到bash
      xq@ubuntu:~$ chsh -s bin/bash

      shell配置文件

      我们开发环境用的最多的就是bash和zsh了,下面就介绍这两个shell为例介绍对应的配置文件。

      Bash的配置文件

      • /etc/profile:为系统的每个用户设置环境信息,当用户第一次登录时会执行该文件里的命令。默认会直接调用/etc/bashrc。该文件的改动需要重启才能生效。

      • /etc/bashrc:为每一个运行bash shell的用户执行此文件。当bash shell被打开时,会读取并执行该文件中的命令。所以修改该文件后,重新打开Shell即可生效。

      • ~/.bash_profile:和/etc/profile类似,但是只对当前用户生效。

      • ~/.bashrc:和/etc/bashrc类似,但是只对当前用户生效。

      • ~/.bash_logout:当每次退出bash shell时,执行该文件。

      • ~/.bash_history:保存了历史命令。在Shell为Bash时,每次敲击命令时,都会保存在这个文件里

      加载顺序:/etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc

      Zsh的配置文件

      • ~/.zshenv:存放的环境变量配置项在任何场景下都能被读取,这里通常把$PATH等变量写在这里,这样无论是在交互shell,或者运行程序都会读取此文件。个人理解对标Bash的profile。

      • ~/.zprofile:和.zlogin类似,但是是在.zshrc之前加载。

      • ~/.zshrc:在交互式shell中会读取并执行该文件,包含设置别名、函数、选项、键绑定等命令。对标bashrc。

      • ~/.zlogin:在login shell的时候读取。

      • ~/.zlogout:退出终端的时候读取,用于做一些清理工作。对标bash_logout。

      • ~/.zsh_history:保存了历史命令。在Shell为Zsh时,每次敲击命令时,都会保存在这个文件里。

      加载顺序:zshenv、zprofile、zshrc、zlogin

      1.2 shell脚本

      由于bash脚本使用场景更广泛,如android源码build目录中各种shell脚本,下面就以bash脚本为例进行讲述。

      shell没有官方的ide支持,可以通过vscode + shellman插件来实现高效编写。shellman插件有进行命令与模版提示的功能。

      脚本文件一般以.sh
      结尾(扩展名并不影响脚本执行),文件第一行指定运行的shell解释器类型。

      #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。

        #!/bin/bash
        echo "Hello World !"

        还有一种指定shell解释器的写法是通过env来声明

          #!/usr/bin/env bash
          echo "Hello World !"

          运行方式

          • 作为可执行程序

          以脚本中声明的shell解释器运行,示例如下:

            chmod +x ./test.sh  #使脚本具有执行权限
            ./test.sh #执行脚本
            • 作为解释器参数

            这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,会忽略脚本中指定的解释器信息

            如:

              # 以zsh解析运行
              zsh test.sh
              # 以bash解析运行
              bash test.sh

              调试

              shell脚本不能像android studio里面可以打断点方式调试,但是可以通过特定方式把执行过程都打印出来来排查问题。

              对整个脚本加调试可以通过在指定解释器的地方添加-x
              参数

                #!/usr/bin/env bash -x
                echo "Hello World !"

                或者

                  bash -x test.sh

                  如果是针对特定的代码块加调试可以通过下面的方式实现:

                    set -x
                    调试内容
                    set +x

                    示例代码如下:

                      set -x
                      echo "hello"
                      echo "world"
                      set +x


                      # 输出结果,带+的为执行过程打印
                      + echo hello
                      hello
                      + echo world
                      world
                      + set +x

                      1.3 注释

                      单行以 # 开头的行就是注释,会被解释器忽略。

                      多行以:
                      <<EOF
                      开始,以EOF
                      结束,中间的都为注释,示例如下:

                        # 注释内容...


                        :<<EOF
                        注释内容...
                        注释内容...
                        注释内容...
                        EOF

                        1.4 变量

                        定义变量

                        格式如下,“=”左右两边不能有空格

                        变量名=值

                        其中变量名的要求为:

                        • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。

                        • 中间不能有空格,可以使用下划线 _。

                        • 不能使用标点符号。

                        • 不能使用bash里的关键字

                        值的话没有要求,可以为整数、字符串、数组等,赋值完某个类型后,后面还可以继续再赋值为其他类型,示例如下:

                          # 定义一个字符串变量
                          var="hello word"
                          # 定义一个值为1的变量
                          var=1
                          # 定义一个包含a、b、c的数组变量
                          var=(a b c)

                          使用变量

                          使用一个定义过的变量,只要在变量名前面加美元符号$
                          即可,示例如下:

                            var="hello word"
                            # 打印变量var的值,
                            echo $var
                            # 如果变量没有定义过,则值为空
                            echo $test


                            # 输出结果
                            hello word

                            只读变量

                            使用 readonly
                            命令可以将变量定义为只读变量,只读变量的值不能被改变。示例如下:

                              readonly val="ready only"
                              # 给只读变量再次赋值会报错
                              val="test"


                              # 输出结果
                              -bash: val:只读变量

                              删除变量

                              使用 unset 命令可以删除变量。语法:

                                unset variable_name

                                变量被删除后不能再次使用。unset 命令不能删除只读变量。示例如下:

                                  var="hello word"
                                  unset var
                                  echo $var


                                  # 输出结果为空

                                  1.5 字符串

                                  字符串定义

                                  字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号(不用引用的情况中间不能有空格)。

                                    str="this is string"
                                    str='this is string'


                                    # 正确示例,无引号无空格
                                    str=thisisstring
                                    # 错误示例,无引号有空格
                                    str=this is string

                                    获取字符串长度

                                    通过${#variable_name}
                                    方式获取,示例如下:

                                      string="abcd"
                                      echo ${#string}


                                      # 输出结果
                                      4

                                      1.6 索引数组

                                      索引数组定义

                                      数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。数组元素的下标由 0 开始。

                                      Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:

                                        array_name=(value1 value2 ... valuen)

                                        赋值也支持指定索引位置赋值,示例如下:

                                          # 数组赋值常见的两种方式
                                          array_name=("abc" "def")


                                          array_name[0]="abc"
                                          array_name[1]="def"

                                          获取数组长度

                                          同获取字符串长度一样,也是通过${#variable_name}
                                          方式获取,示例如下:

                                            array_name=("abc" "def")
                                            # 打印数组长度
                                            echo ${#array_name}


                                            # 输出结果:
                                            2

                                            读取数组元素

                                            指定索引位置的使用${array_name[index]}
                                            ,全部的使用${array_name[*]}
                                            ,示例如下:

                                              array_name=("abc" "def")
                                              # 读取数组指定索引元素
                                              echo ${array_name[0]}
                                              # 读取数组全部的元素
                                              echo ${array_name[*]}


                                              #输出结果
                                              abc
                                              abc def

                                              1.7 关联数组

                                              关联数组定义

                                              Bash 支持关联数组,可以使用任意的字符串、或者整数作为下标来访问数组元素。与其他语言中的map是类似的,它是无序的。

                                              关联数组使用 declare
                                              -A
                                              命令来声明,语法格式如下:

                                                declare -A map=(["key1"]="value1" ["key2"]="value2")

                                                和索引数组一样,也支持指定key赋值,示例如下:

                                                  declare -A map=(["key1"]="value1" ["key2"]="value2")


                                                  declare -A map2
                                                  map2["key3"]="value3"


                                                  # 获取指定key的值
                                                  echo ${map["key1"]}
                                                  # 获取关联数组的所有键
                                                  echo ${!map[*]}


                                                  echo ${map[*]}

                                                  获取关联数组长度

                                                  同获取字符串长度一样,也是通过${#variable_name}
                                                  方式获取,示例如下:

                                                    declare -A map=(["key1"]="value1" ["key2"]="value2")
                                                    #获取关联数组长度
                                                    echo ${#map[*]}


                                                    # 输出结果
                                                    2

                                                    获取key与value

                                                    通过${map[key]}
                                                    方式获取指定key的值,通过${map[*]}
                                                    获取所有的值,通过${!map[*]}
                                                    获取所有的键,示例如下:

                                                      map=(["key1"]="value1" ["key2"]="value2")
                                                      # 获取指定key的值
                                                      echo ${map["key1"]}
                                                      echo ${map[*]}
                                                      echo ${!map[*]}


                                                      # 输出结果
                                                      value1
                                                      value2 value1
                                                      key2 key1

                                                      1.8 流程控制

                                                      If else

                                                      判断某个条件成立或者不成立时要执行的动作,中间的elif 和else都是可选,格式如下:

                                                        if condition1; then
                                                        command1
                                                        elif condition2; then
                                                        command2
                                                        else
                                                        command3
                                                        fi

                                                        常见的判断操作符如下:

                                                        文件/目录

                                                        -f

                                                        文件是否存在


                                                        -d

                                                        目录是否存在


                                                        -x

                                                        文件存在且可执行


                                                        -r

                                                        文件存在且可读


                                                        -w

                                                        文件存在且可写


                                                        字符串

                                                        -z

                                                        字符串为空


                                                        -n

                                                        字符串不为空


                                                        =

                                                        字符串相等


                                                        !=

                                                        字符串不相等


                                                        =~

                                                        字符串包含


                                                        数字比较

                                                        -eq

                                                        相等


                                                        -ne

                                                        不相等


                                                        -lt

                                                        小于


                                                        -le

                                                        小于等于


                                                        -gt

                                                        大于


                                                        -ge

                                                        大于等于


                                                        if
                                                        使用示例如下:

                                                          # 判断文件是否存在
                                                          if [ -f ~/.bashrc ]; then
                                                          echo "~/.bashrc exist"
                                                          fi
                                                          # 判断字符串是否为空
                                                          if [ -z $str ];then
                                                          echo "str is empty"
                                                          else
                                                          echo "str is not empty"
                                                          fi
                                                          # 数字大小判断
                                                          if [ "$var" -eq 1 ];then
                                                          echo "var equal 1"
                                                          elif [ "$var" -gt 4 ];then
                                                          echo "var great than 4"
                                                          else
                                                          echo "other case"
                                                          fi

                                                          for 循环

                                                          for循环格式如下,item列表值可以分别单独写出来,也可以是一个列表

                                                            for var in item1 item2 ... itemN
                                                            do
                                                            command1
                                                            command2
                                                            ...
                                                            commandN
                                                            done

                                                            代码示例:

                                                              for loop in 1 2 3
                                                              do
                                                              echo "The value is: $loop"
                                                              done
                                                              list=(a b c)
                                                              for var in ${list[*]}
                                                              do
                                                              echo "var is $var"
                                                              done


                                                              # 输出结果
                                                              The value is: 1
                                                              The value is: 2
                                                              The value is: 3
                                                              var is a
                                                              var is b
                                                              var is c

                                                              while

                                                                while condition
                                                                do
                                                                command
                                                                done

                                                                代码示例:

                                                                  a=1
                                                                  while (( $a<=3 ));do
                                                                  echo $a
                                                                  let a++
                                                                  done


                                                                  # 结合read可以实现常见的按行读取文件内容
                                                                  echo "aa" > 1.text
                                                                  echo "bb" >> 1.txt
                                                                  while read line;do
                                                                  echo $line
                                                                  done < 1.text


                                                                  # 输出结果
                                                                  1
                                                                  2
                                                                  3
                                                                  aa
                                                                  bb

                                                                  case ... esac

                                                                  为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。

                                                                  可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

                                                                  语法格式如下:


                                                                    casein
                                                                    模式1)
                                                                    command1
                                                                    command2
                                                                    ;;
                                                                    模式2)
                                                                    command1
                                                                    command2
                                                                    ;;
                                                                    esac
                                                                    echo -n "Enter the name of an animal: "
                                                                    read ANIMAL
                                                                    echo -n "The $ANIMAL has "
                                                                    case $ANIMAL in
                                                                    horse | dog | cat) echo -n "four";;
                                                                    man | kangaroo ) echo -n "two";;
                                                                    *) echo -n "an unknown number of";;
                                                                    esac
                                                                    echo " legs."

                                                                    break与continue

                                                                    与其他编程相同里的概念相同,代码示例如下:

                                                                      # break示例:
                                                                      while true
                                                                      do
                                                                      echo -n "输入 1 到 5 之间的数字:"
                                                                      read aNum
                                                                      case $aNum in
                                                                      1|2|3|4|5) echo "你输入的数字为 $aNum!"
                                                                      ;;
                                                                      *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
                                                                      break
                                                                      ;;
                                                                      esac
                                                                      done
                                                                      # 输出结果
                                                                      输入 1 到 5 之间的数字:3
                                                                      你输入的数字为 3!
                                                                      输入 1 到 5 之间的数字:7
                                                                      你输入的数字不是 1 到 5 之间的! 游戏结束




                                                                      # continue示例
                                                                      while true
                                                                      do
                                                                      echo -n "输入 1 到 5 之间的数字:"
                                                                      read aNum
                                                                      case $aNum in
                                                                      1|2|3|4|5) echo "你输入的数字为 $aNum!"
                                                                      ;;
                                                                      *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
                                                                      continue
                                                                      echo "游戏结束"
                                                                      ;;
                                                                      esac
                                                                      done
                                                                      # 输出结果,无法结束
                                                                      输入 1 到 5 之间的数字:3
                                                                      你输入的数字为 3!
                                                                      输入 1 到 5 之间的数字:7
                                                                      你输入的数字不是 1 到 5 之间的! 游戏结束
                                                                      输入 1 到 5 之间的数字:

                                                                      select

                                                                      选择一个列表中的一个值,item列表值可以分别单独写出来,也可以是一个列表

                                                                      语法格式如下:

                                                                        select var in item1 item2..itemN
                                                                        do
                                                                        command
                                                                        done

                                                                        代码示例如下:

                                                                          list=(a b)
                                                                          PS3="Please select the value:"
                                                                          select var in ${list[*]};do
                                                                          break
                                                                          done
                                                                          echo "your select is $var"


                                                                          # 输出结果
                                                                          1) a
                                                                          2) b
                                                                          Please select the value:1
                                                                          your select is a

                                                                          1.9 函数

                                                                          函数定义

                                                                          shell中函数的定义格式如下,其中return的返回值在[0-225]之间,如果不加return将以最后一条命令运行结果,作为返回值.


                                                                            [ function ] funname()
                                                                            {
                                                                            action;
                                                                            [return int;]
                                                                            }

                                                                            示例代码:

                                                                              # 完整格式定义函数
                                                                              function test1() {
                                                                              echo "hello world1"
                                                                              return 0
                                                                              }
                                                                              # 简写的函数定义
                                                                              test2() {
                                                                              echo "hello world2"

                                                                              }


                                                                              # 函数调用
                                                                              test1
                                                                              # 获取上一条指令的返回值,紧接着test1之后就是代表获取test1函数的返回值
                                                                              echo $?
                                                                              test2




                                                                              # 输出结果
                                                                              hello world1
                                                                              0
                                                                              hello world2

                                                                              函数参数

                                                                              在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $$$$n 的形式来获取参数的值,例如, $$$$$1表示第一个参数,$2表示第二个参数,依此类推。$*
                                                                              表示所有的参数,$#
                                                                              表示参数的个数

                                                                              带参数的函数示例:

                                                                                add() {
                                                                                echo "parmas: $*"
                                                                                echo "params count:$#"
                                                                                return $(($1+$2))
                                                                                }
                                                                                add 1 2
                                                                                echo "sum is $?"


                                                                                # 输出结果
                                                                                parmas: 1 2
                                                                                params count:2
                                                                                sum is 3

                                                                                根据上面的定义来看shell函数只能返回整形且为0-255之间,那么我们想返回字符串或者数组有没有其他办法呢?

                                                                                我们可以通过其他方法来实现类似的效果的,示例代码如下:

                                                                                获取字符串结果,调用的时候通过$(function_name param)
                                                                                方式来调用,那这个函数里面所有echo
                                                                                出来的字符串就会赋值给你的变量,示例如下:

                                                                                  hello() {
                                                                                  echo "say hello to $1"
                                                                                  }
                                                                                  result=$(hello world)
                                                                                  echo $result


                                                                                  # 输出结果
                                                                                  say hello to world

                                                                                  获取数组,这个可以通过定义全局变量,在函数里面对其赋值

                                                                                    arr=()
                                                                                    testArray() {
                                                                                    arr[0]=1
                                                                                    arr[1]=2
                                                                                    }


                                                                                    testArray
                                                                                    echo "arr content is ${arr[*]}"
                                                                                    echo "arr size is ${#arr[*]}"


                                                                                    # 输出结果
                                                                                    arr content is 1 2
                                                                                    arr size is 2

                                                                                    2.参考

                                                                                    bash手册:https://www.gnu.org/software/bash/manual/bash.html

                                                                                    Zsh手册: https://zsh.sourceforge.io/Doc/Release/index.html#Top


                                                                                    文章转载自阿Q正砖,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                                                    评论