【Shell】Shell脚本语言 学习笔记


1. shell 脚本语言

  讲解 bash命令;

  • Shell 是一种弱类型语言;
  • 在Shell脚本中可以使用所有的Linux命令;

参考

  1. shell 教程    //菜鸟教程
  2. [部分学习案例](./90_Operation System/10_Linux/shell/shell_document.sh)

1.1. 准备

  1. #!/bin/bash
    • #!  是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
    • echo   用于向窗口输出文本。

1.1.1. 脚本的运行

  • 作为可执行程序
    chmod +x ./test.sh   #使脚本具有权限;
    ./test.sh            #执行脚本
    #./test.sh    ./保证在当前目录中查找文件,防止搜索 PATH 中查找;
    
  • 直接使用解释器
    /bin/sh filename #第一行解释器信息 无效

1.1.2. VSCode 中运行bash

Windows 端使用VSCode运行shell文件;

参考:

  1. 如何在windows下使用vscode畅快的调试bash shell
  2. VSCode 编写 Shell 脚本

//注:还是Linux上方便些;

1.1.3. 注释

  shell 注释;
  单行与多行注释;

  • 单行注释

    • # 开头 注释一行;
    • 注释大段代码时,可以使用 { } 写成函数,不做调用;
  • 多行注释
    可以使用以下格式:

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

    其他符号:

    #注释 2
    :<<'
    注释内容...        
    注释内容...
    注释内容...
    '
    #注释 3
    :<<!
    注释内容...
    注释内容...
    注释内容...
    !
    

1.2. shell 输出

echo、 print 等 输出命令;

1.2.1. echo

  输出字符串:
  格式:echo string

  • 输出 普通字符串
    echo "It is a test"

  • 输出 转义字符

      echo "\"  "    
      #输出 转义字符 \
    
  • 显示 变量

    echo '$name\"'  #不转换变量;
    #转换变量
    read name 
    echo "$name It is a test"
    
  • 显示 换行 不换行

    echo -e "OK! \n" # -e 开启转义
    echo "It is a test"
    echo -e "OK! \c" # -e 开启转义 \c 不换行
    echo "It is a test"
    
    ### 结果:
    OK!
    
    It is a test     #换行;
    OK! It is a test #不换行;
    
  • 显示 结果定向至文件

    echo "It is a test" > myfile
    

注意:

  1. > 重定向输出到某个位置,替换原有文件的所有内容。
  2. >> 重定向追加到某个位置,在原有文件的末尾添加内容。
  3. < 重定向输入某个位置文件。
  4. 2> 重定向错误输出。
  5. 2>> 重定向错误追加输出到文件末尾。
  6. &> 混合输出错误的和正确的都输出。
  • 显示 命令执行结果
    echo `date`  #显示当前时间;
    

1.2.2. printf()

  1. 概述

    1. printf 命令模仿 C 程序库(library)里的 printf() 程序。
    2. printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo  移植性好
    3. printf 使用 引用文本 或 空格 分隔的参数,外面可以在 printf 中使用 格式化字符串;
      • 还可以制定字符串的宽度、左右对齐方式等;
      • 默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n。
  2. 格式
    printf format-string [arguments...]
    #format-string: 格式控制字符串;
    #argument: 参数列表;

    #!/bin/bash
    # author:菜鸟教程
    # url:www.runoob.com
    
    printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
    printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
    printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
    printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876 
    
    # %-10s 表示10个字符;
       -    表示 左对齐;
    
    ##结果
    姓名     性别   体重kg
    郭靖     男      66.12
    杨过     男      48.65
    郭芙     女      47.99
    
  3. 转移字符

    序列说明
    \a警告字符,通常为ASCII的BEL字符
    \b后退
    \c抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
    \f换页(formfeed)
    \n换行
    \r回车(Carriage return)
    \t水平制表符
    \v垂直制表符
    \一个字面上的反斜杠字符
    \ddd表示1到3位数八进制值的字符。仅在格式字符串中有效
    \0ddd表示1到3位的八进制值字符

1.2.3. 输入输出 重定向

  1. 命令符说明

    命令说明
    command > file将输出重定向到 file。
    command < file将输入重定向到 file。
    command >> file将输出以追加的方式重定向到 file。
    n > file将文件描述符为 n 的文件重定向到 file。
    n >> file将文件描述符为 n 的文件以追加的方式重定向到 file。
    n >& m将输出文件 m 和 n 合并。
    n <& m将输入文件 m 和 n 合并。
    << tag将开始标记 tag 和结束标记 tag 之间的内容作为输入。

    注意:
    一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

    1. 标准输入文件(stdin): stdin 的文件描述符为0,Unix程序默认从stdin读取数据;
    2. 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据;
    3. 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
  2. Here Document
    将输入 重定向到一个交互式shell脚本或程序;特殊的重定向方式;

    格式:

    # 将 document 的内容传递给command;
    command << delimiter
        document
    delimiter
    
    # 注意
    #  1. 结尾的 delimiter,顶格写;前后不能有任何字符;
    #  2. 开始的 delimiter 前后的 空格 会被忽略掉;
    

    例:

    #!/bin/bash
    # author:菜鸟教程
    # url:www.runoob.com
    
    cat << EOF
    欢迎来到
    菜鸟教程
    www.runoob.com
    EOF
    
    ##  结果
    欢迎来到
    菜鸟教程
    www.runoob.com
    
  3. /dev/null 文件

    • 想执行某个命令,但不希望结果输出在屏幕上
    • 该文件特殊,会丢弃写入的内容,也无法读出;
    • 即:禁止输出
    $ command > /dev/null
    
    # 屏蔽 stdout 和 stderr
    # 2>&1 表示 stderr 重定向到 stdout
    $ command > /dev/null 2>&1   # 2>&1 的含义见注释
    
    

    注释:

    1. & :表示重定向的目标不是一个文件,而是一个文件描述符;
    2. 2>1 代表将stderr重定向到当前路径下文件名为1的regular file中,而2>&1代表将stderr重定向到文件描述符为1的文件(即/dev/stdout)中,这个文件就是stdout在file system中的映射;
    3. 而&>file是一种特殊的用法,也可以写成>&file,二者的意思完全相同;

参考:

  1. 菜鸟教程 重定向

1.3. shell 变量

  1. 命名规则
    yourname="VK-Link"

    • 变量名不需要加 $,使用时加 $;
    • 变量名和 = 之间不能有空格;
    • 不能使用 bash 中的 关键字;
    • 英文、数字、下划线;
  2. 变量操作

    • {} 用于识别、区分变量;
    • 可以被重定义,。新值代替旧值;
  • 变量类型

    • 局部变量
      :在脚本或命令中定义,仅在当前有效;
    • 环境变量
      :所有程序包括shell均可访问,shell中也可定义;
    • shell变量
      :包括环境和局部变量;
  • 只读变量

    url="VK-Link"
    readonly url   #只读,不可修改;
                   #先赋值,再readonly;
    
  • 删除变量
    unset variable_name   #不能删除只读变量

1.4. shell 字符串

   shell字符串是最常用的,使用 " "、’ ’ 或不使用;

1.4.1. 字符串规则

格式:

#单引号
str='this is a string;'   #
#双引号
your_name=VK-link
str="Hello, \"$your_name\"! "  #可以直接使用变量 $your_name;
  • 单引号
    • 变量无效;
    • 单引号无法单独使用;
  • 双引号
    • 可以包含变量;
    • 可以含 转义字符; \
    • " y o u r n a m e " 、 your_name"、 yourname"{your_name}均可用于 " " 中;

1.4.2. 字符串操作

  拼接、获取长度、查找、提取字符串;

  • 拼接 greeting
    greeting用于连接字符串;

     your_name="runoob"
     # 使用双引号拼接
     greeting="hello, "$your_name" !"
     greeting_1="hello, ${your_name} !"
     echo $greeting  $greeting_1
     # 使用单引号拼接
     greeting_2='hello, '$your_name' !'  #变量不在''中;
     greeting_3='hello, ${your_name} !'
     echo $greeting_2  $greeting_3
    
  • 获取字符串长度

    • $(#variable_name)
      string="abcd"
      echo ${#string}        #输出 4
      
    • length 命令
        #string 中含有空格,故使用 "";
        string="hello,everyone my name is VK-Link"
        expr length "$string"
        #结果: 33;
      
      其中 expr
      • 表达式中的运算符左右必须包含 空格,如果不包含空格,将会输出表达式本身;
        expr 5+6      #直接输出 5+6
        expr 5 + 6    #输出 11
        expr 5 \* 6   #输出30      //使用转义字符;
        
  • 提取 子字符串
    string:num1:num2   #从num1开始的num2个字符;

    #从第2个字符开始,截取4个字符   
    #第1个位置 为0;
    string="runoob is a great site"
    echo ${string:1:4}      # 输出 unoo    
    
  • 查找 子字符串
    `expr index “$string” 字符`  查找string中的字符;

    #查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
    string="runoob is a great site"
    echo `expr index "$string" io`  # 输出 4
    
    # 注意: 以上脚本中 ` 是反引号,而不是单引号 ';  
    

参考

  1. 笔记:Linux 的字符串截取很有用。有八种方法。   
    //字符串中字符的截取:#、%、: 等;

1.4.3. 字符输入

  • read [-oprions] (variable…)
    读取键盘 输入赋值给 shell变量;
      # -p 键盘输入时,用于终端显示 提示信息;
      read -p "input a val:" a    #获取键盘输入的 a 变量数字
      read -p "input b val:" b    #获取键盘输入的 b 变量数字
      r=$[a+b]                    #计算a+b的结果 赋值给r  不能有空格
      echo "result = ${r}"        #输出显示结果 r
    
      #输入 及 结果    
      input a val:1
      input b val:2
      result = 3
    
    注意:
    1. -p 输入提示文字
    2. -n 输入字符长度限制(达到6位,自动结束)
    3. -t 输入限时
    4. -s 隐藏输入内容
     read -p "请输入一段文字:" -n 6 -t 5 -s password
     echo -e "\npassword is $password"
     
     ##结果
     $ sh test.sh 
     请输入一段文字:
     password is asdfgh
    

1.5. shell 数组

 bash 支持一维数组,不限定数组的大小;其他类似于 C 语言;

1.5.1. 定义数组

数组名=(num1 num2 num3 … num)

array_name=(value0 value1 value2 value3)
#或者
array_name=(
value0
value1
value2
value3
)
#单个变量赋值;
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

1.5.2. 读取数组

格式

#读取 数组元素
${数组名[下标]}
valuen=${array_name[n]}

##读取 所有元素
echo ${array_name[@]}

1.5.3. 数组长度

与获取 字符串长度 的方法相同;

# 取得数组元素的 个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组 单个元素的长度
lengthn=${#array_name[n]}

  1. 数组的值 可以写入变量;
  2. 数组的下标 可以为变量;

参考菜鸟教程笔记

1.6. shell 运算符

  算术运算符、关系运算符、布尔、逻辑、字符串、文件测试运算符。

1.6.1. 算数运算符

  awk 和 expr 进行简单的数学运算,expr 最常用。

1.6.2. 关系运算符

   关系运算符仅支持 数字,除非字符串的值是 数字,否则不支持字符串;

运算符说明举例
-eq检测两个数是否相等,相等返回 true。[ $a -eq $b ] 返回 false。
-ne检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。[ $a -gt $b ] 返回 false。
-lt检测左边的数是否小于右边的,如果是,则返回 true。[ $a -lt $b ] 返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 false。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true。

注:

  1. e (equal): 相等; less、great;

1.6.3. 布尔

   与(-a)或(-o)非(!)

:当连接test测试条件时,先级为:"!“最高,”-a"次之,"-o"最低;

1.6.4. 逻辑运算符

  逻辑 AND(&&)、逻辑OR(||)

a=10
b=20
[[ $a -lt 100 && $b -gt 100 ]]    #返回 false
[[ $a -lt 100 || $b -gt 100 ]]    #返回 true

1.6.5. 字符串

符号说明:

运算符说明举例
=检测两个字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=检测两个字符串是否相等,不相等返回 true。[ $a != $b ] 返回 true。
-z检测字符串长度是否为0,为0返回 true。[ -z $a ] 返回 false。
-n检测字符串长度是否不为 0,不为 0 返回 true。[ -n “$a” ] 返回 true。
$检测字符串是否为空,不为空返回 true。[ $a ] 返回 true。

1.6.6. 文件测试

文件测试运算符用于检测 Unix 文件的各种属性

  1. 基本文件测试符

    运算符说明举例
    -b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
    -c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
    -d file检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
    -f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。[ -f $file ] 返回 true。
    -g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
    -k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。[ -k $file ] 返回 false。
    -p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ] 返回 false。
    -u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
    -r file检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
    -w file检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
    -x file检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
    -s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true。
    -e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true。
  2. 其他文件测试符
    -S: 判断某文件是否 socket。
    -L: 检测文件是否存在并且是一个符号链接。

注:

  1. 菜鸟教程 的该部分笔记还要看;

1.7. 函数

  函数必须在使用前定义;直接使用函数名 调用;

1.7.1. 函数格式:

  1. 格式:
    [ function ] funname [()]
    {
        action;
        [return int;]
    }   
    ###
    1、函数可以用 function fun() 定义,也可以直接fun() 定义,不带任何参数。
    2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
    
    

1.7.2. 传递参数

函数参数的传递;

参数处理说明
$?获取调用函数后的 返回值
$n函数体内部,获取第 n 个参数的值
$#传递到脚本或函数的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数。
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

1.8. 文件包含

  Shell也可以包含外部脚本;可以封装公用代码作为一个独立的文件;

  • 文件包含 格式
    . filename   # 注意点号(.)和文件名中间有一空格source filename
    
    ## 示例
    #### test1.sh
    #!/bin/bash
    url="http://www.runoob.com"
    
    #### test2.sh
    #!/bin/bash
    # 方法1. 使用 . 号来引用test1.sh 文件
    . ./test1.sh
    # 方法2. 或者使用以下包含文件代码
    # source ./test1.sh
    
    echo "菜鸟教程官网地址:$url"
    
    #### 结果
    chmod +x test2.sh      # 赋予执行权限
    ./test2.sh 
    菜鸟教程官网地址:http://www.runoob.com
    
    ## 注:被包含的文件 不需要执行权限;
    

1.9. test 命令

  用于检查某个条件是否成立,可以对数值、字符、文件进行测试;

1.9.1. 数值测试

参数说明:

参数说明含义
-eq等于则为真equal
-ne不等于则为真not equal
-gt大于则为真greater than
-ge大于等于则为真greater&equal
-lt小于则为真lower than
-le小于等于则为真lower&equal

示例:

num1=100
num2=100
if test $[num1] -eq $[num2]
then
    echo '两个数相等!'
else
    echo '两个数不相等!'
fi

1.9.2. 字符串测试

参数说明:

参数说明
=等于则为真
!=不相等则为真
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真

示例:

num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
    echo '两个字符串相等!'
else
    echo '两个字符串不相等!'
fi

1.9.3. 文件测试

参数说明:

参数说明
-e 文件名如果文件存在则为真
-r 文件名如果文件存在且可读则为真
-w 文件名如果文件存在且可写则为真
-x 文件名如果文件存在且可执行则为真
-s 文件名如果文件存在且至少有一个字符则为真
-d 文件名如果文件存在且为目录则为真
-f 文件名如果文件存在且为普通文件则为真
-c 文件名如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真

示例:

cd /bin
if test -e ./notFile -o -e ./bash
then
    echo '至少有一个文件存在!'
else
    echo '两个文件都不存在'
fi

1.10. 流程控制

1.10.1. if else

  当else中没有语句执行,不写else;

  1. if
  2. if else
  3. if else-if else
#if    ###写成一行(适合终端提示符)
  if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

# if else-if else 
  if condition1
  then
      command1
  elif condition2 
  then 
      command2
  else
      commandN
  fi

1.10.2. for

for var in item1 item2 ... itemN; do command1; command2… done;

注意:

  1. 命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。
  2. in列表是可选的,如果不用它,for循环使用命令行的位置参数。

1.10.3. while

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"   #let 命令中,变量不需要使用$;
done

1.10.4. 无限循环

无限循环 格式:

## 1
while true
do
    command
done
## 2
while :
do
    command
done
## 3
for (( ; ; ))

1.10.5. until 循环

  • until 循环执行一系列命令直至条件为 true 时停止。

  • until 循环与 while 循环在处理方式上刚好相反。

  • 一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

    #!/bin/bash
    a=0
    
    until [ ! $a -lt 10 ]  #条件;
    do
      echo $a
      a=`expr $a + 1`
    done
    

1.10.6. case

  • 取值后面必须为单词in,每一模式必须以右括号结束。
  • 取值可以为变量或常数。
  • 匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;; 。
    echo '输入 1 到 4 之间的数字:'
    echo '你输入的数字为:'
    read aNum
    case $aNum in
        1)  echo '你选择了 1'
        ;;                      #;;  结束标志;
        1)  echo '你选择了 2'
        ;;
        1)  echo '你选择了 3'
        ;;
        1)  echo '你选择了 4'
        ;;
        *)  echo '你没有输入 1 到 4 之间的数字'  #无匹配
        ;;
    esac
    
    注:
    • case esac 命令
      • case 后为取值,值可以为变量或常数;
      • 选择模式支持 正则表达式;
      #!/bin/sh
      site="runoob"
      
      case "$site" in
        "runoob") echo "菜鸟教程"
        ;;                        #表示break;
        "google") echo "Google 搜索"
        ;;
        "taobao") echo "淘宝网"
        ;;
      esac         #case 倒着写;
      

1.10.7. 跳出循环

  1. break :跳出所有循环,终止后面的所有循环;

  2. continue :仅跳出当前循环;

    ## break 命令
    #!/bin/bash
    while :
    do
        echo -n "输入 1 到 5 之间的数字:"
        read aNum
        case $aNum in
            1|2|3|4|5) echo "你输入的数字为 $aNum!"
            ;;
            *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
                break
            ;;
        esac
    done
    
    ## continue 命令
    #!/bin/bash
    while :
    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值