• Linux Shell编程参考大全


      

    本文记录Linux Shell编程中常用基本知识,方便快速入门以及查询使用。

    本文主要分为以下几个部分:

    一、Shell中的变量

    任何编程语言中,有关变量的定义,作用范围,赋值等都是最最基本的知识。

    0、默认变量

    首先介绍几个shell中的默认变量。

    变量 含义
    $0 当前脚本名称
    $1 脚本接收的第一个参数
    $2 脚本接收的第二个参数
    $# 脚本接收的所有参数个数
    $@ 脚本接收的所有参数
    $* 脚本接收的所有参数
    $? 前一行命令的执行状态

    示例如下:

    default_var.sh脚本内容

    echo $0
    echo $1
    echo $2
    echo $#
    echo $@
    echo $*
    echo $?
    1 hadoop@client:~$ sh default_var.sh a b c d
    2 
    3 $0           ==>         default_var.sh
    4 $1           ==>         a
    5 $2           ==>         b
    6 $#           ==>         4
    7 $@          ==>         a b c d
    8 $*           ==>         a b c d
    9 $?           ==>         0

    1、变量定义及赋值

    hadoop@client:~$ v1=hello
    hadoop@client:~$ echo $v1
    hello

    但是要注意的是,赋值处必须为一个整体,不能有空格。

    1 hadoop@client:~$ v2=hello world
    2 No command 'world' found,did you mean:
    3    Command 'tworld' from package 'tworld' (universe)
    4 world: command not found

    想要包含空格,需要用单引号或者双引号包围,如:

    1 hadoop@client:~$ a="hello"
    2 hadoop@client:~$ b="$a world"
    3 hadoop@client:~$ echo $b
    4 hello world
    5 hadoop@client:~$ c='$a world'
    6 hadoop@client:~$ echo $c
    7 $a world

    可以看到,单引号中的$a保持原样输出。而双引号中的$a会替换成其变量值。

    3、`符号

    这个符号在数字键1的的左侧,与单引号很类似。但是其功能与单引号双引号都有不同。在该符号中的命令会被执行。

    hadoop@client:~$ d=`date`
    hadoop@client:~$ echo $d
    Wed Dec 28 06:31:13 PST 2019

    如果不想使用这个符号,可以用$()替换

    1 hadoop@client:~$ e=$(date)
    2 hadoop@client:~$ echo $e
    3 Wed Dec 28 06:31:48 PST 2019

    4、命令行交互read

    有时候我们希望在脚本运行时能根据用户的输入决定脚本后续执行逻辑,比如在安装插件的时候经常会让用户选择输入[N/Y]的时候。

    比如有一个脚本script_test.sh

    read -p "Please input [Y/N]: " yn
    
    if ["$yn" == "N" -o "$yn" == "n" ]; then
        echo "NO"
    elif ["$yn" == "Y" -o "$yn" == "y"]; then
        echo "YES"
    fi

    在运行时根据用户的输入决定if分支走向。运行结果如下:

    hadoop@client:~$ sh script_test.sh
    
    Please input [Y/N]: y
    
    YES

    read命令的使用形式为:

    read [-pt] variable
            参数p: 后面可以接提示符
            参数t: 后面可以接秒数

    例如,

    read -p "Please input name" -t 5 name

    表示将输入内容赋值给变量name,用户有5秒钟的输入时间。

    5、定义变量类型declare

      默认情况下,变量的赋值内容都是字符类型的。例如以下代码,我们期待的是输出一个求和值,但是输出的是一个求和表达式。

    hadoop@client:~$ sum=100+300+500
    hadoop@client:~$ echo $sum
    100+300+500

    如果想要输出求和后的值,可以使用declare命令。

    hadoop@client:~$ declare -i sum=100+300+500
    hadoop@client:~$ echo $sum
    900

    declare命令的使用形式如下:

    declare [-aixr] variable
          参数a: 将variable定义为数组
          参数i: 将variable定义为整型(integer)
          参数x:将variable设置成环境变量,类似于export的作用
          参数r: variable为readonly类型,值不能被更改

    二、Shell中的集合类型

    1、数组(array)

     (1)数组定义和赋值

     数组中的元素用括号包围,各元素之间空格隔开。例如

    hadoop@client:~$ array_name=(v0 v1 v2 v3)

    可以重新设置指定元素的内容,如下所示

    hadoop@client:~$ array_name[2]=v22
    hadoop@client:~$ echo ${array_name[2]}
    v22

    (2)数组元素访问

      输出该数组中所有元素:

    hadoop@client:~$ echo ${array_name[*]}
    v0 v1 v22 v3
    hadoop@client:~$ echo ${array_name[@]}
    v0 v1 v22 v3

    数组元素下标从0开始,想要访问指定位置的元素,使用[]指定下标值,如下所示

    hadoop@client:~$ echo ${array_name[0]}
    v0
    hadoop@client:~$ echo ${array_name[1]}
    v1
    hadoop@client:~$ echo ${array_name[2]}
    v2
    hadoop@client:~$ echo ${array_name[3]}
    v3

    (3)获取数组长度

    获取数组长度使用如下命令

    hadoop@client:~$ echo ${#array_name[@]}
    4
    hadoop@client:~$ echo ${#array_name[*]}
    4

    获取数组中单个元素的长度如下命令

    hadoop@client:~$ echo ${#array_name[2]}
    3

    2、map

    map类型中存储的都是键值对。

    在Shell中定义map变量如下所示:

    declare -A m=(["a"]="1" ["b"]="2")

    输出所有的key值

    hadoop@client:~$ echo ${!m[@]}
    a b

    输出所有的value

    hadoop@client:~$ echo ${m[@]}
    1 2

    输出指定key对应的value

    hadoop@client:~$ echo ${m["a"]}
    1
    hadoop@client:~$ echo ${m["b"]}
    2

    添加元素

    hadoop@client:~$ m["c"]=3
    hadoop@client:~$ echo ${m["c"]}
    3

    map中键值对的个数

    hadoop@client:~$ echo ${#m[@]}

    三、Shell中的字符串操作

    在任何语言中对字符串的操作都是非常频繁的。字符串的操作主要包括,字符串截取,字符串替换等。

    接下来的示例中,都以字符串http://blog.csdn.net/dabokele作为初始字符串。

    str="http://blog.csdn.net/dabokele"

    1、字符串删除

    删除前面的http://

    hadoop@client:~$ echo ${str#http://}
    blog.csdn.net/dabokele

    #从前往后截取,%从后往前截取。

    示例中表示将符合的最短数据删除,如果使用两个#,或者两个%,则表示将符合的最长数据删除。

    如下所示,匹配最短时,会将https://csdn.ne删除,匹配最长时,会将全部字符删除。

    hadoop@client:~$ echo ${str#http://b*e}
    t/daboleke
    hadoop@client:~$ echo ${str##http://b*e}

    2、字符串截取

    可以从字符串的指定位置开始截取,同时可以指定截取的位数,如下所示:

    hadoop@client:~$ echo ${str:2}   //从第二位开始截取到最末尾,第一个字符下标为0
    tp://blog.csdn.net/dabokele
    hadoop@client:~$ echo ${str:2:3}   //从第二位开始顺序截取三个字符
    tp:
    hadoop@client:~$ echo ${str:(-6):3}  //从倒数第六位开始,截取三个字符,最后一个字符
    bok

    3、字符串替换

    将http替换成HTTP

    hadoop@client:~$ echo ${str/http/HTTP}
    HTTP://blog.csdn.net/dabokele
    • 使用一个斜杠(/)表示只替换成第一个遇到的字符。
    • 使用两个斜杠(//)则表示替换全部符合的字符。
    • 使用#匹配以指定字符开头的字符串。
    • 使用%匹配以指定字符串结尾的字符串。
    hadoop@client:~$ echo ${str/e/E}
    http://blog.csdn.nEt/dobokele
    hadoop@client:~$ echo ${str//e/E}
    http://blog.csdn.nEt/dobokele
    hadoop@client:~$ echo ${str/#h/H}   //匹配开头的那个h
    Http://blog.csdn.net/dobokele
    hadoop@client:~$ echo ${str/%e/E}  //匹配最后那个e
    http://blog.csdn.net/dobokelE

    4、字符串默认值

    假设以下这个场景,如果变量name没有赋过值,则给一个默认值default,否则使用指定的值。

    hadoop@client:~$ echo $name
    
    hadoop@client:~$ echo ${name-default}
    default
    hadoop@client:~$ name="ckm"
    hadoop@client:~$ echo ${name-default}
    ckm

    但是,如果已经将变量name设置成“”,则结果如下:

    hadoop@client:~$ name=""
    hadoop@client:~$ echo ${name-default}

    如果变量内容为“”或者变量未初始化则给默认值,可以在-前加个冒号,使用:-

    hadoop@client:~$ name=""
    hadoop@client:~$ echo ${name-default}
    
    hadoop@client:~$ echo ${name:-default}
    default

    5、字符串拼接

    字符串拼接如下所示

    hadoop@client:~$ echo "aaa""bbb"
    aaabbb
    hadoop@client:~$ echo "aaa"$str
    aaahttp://blog.csdn.net/dabokele
    hadoop@client:~$ echo "aaa$str"
    aaahttp://blog.csdn.net/dobokele

    6、字符串长度

    求字符串长度用#操作,如下所示

    hadoop@client:~$ echo ${#str}
    29

    7、字符串split成数组

    在以空格为分割字符串成数组时操作最简单。

    hadoop@client:~$ s="a b c d e"
    hadoop@client:~$ a=($s)
    hadoop@client:~$ echo ${a[*]}
    a b c d e
    hadoop@client:~$ echo $a[2]
    c

    所以,如果需要指定特定字符进行分割,而原字符串中没有空格时,可以先将特定字符替换成空格,然后按照上述进行分割,如下所示,

    hadoop@client:~$ s="a,b,c,d,e"
    hadoop@client:~$ a=(${str//,/ })
    hadoop@client:~$ echo ${a[*]}
    a b c d e
    hadoop@client:~$ echo ${a[2]}
    c

    如果字符串中本身已有空格,并且期望的分割符不是空格,按如下方法进行分割。首先将IFS变量替换成指定字符,分割后将IFS更新为原字符。

    hadoop@client:~$ s="a b,c,d,e"
    hadoop@client:~$ old_ifs="$IFS"
    hadoop@client:~$ IFS=","
    hadoop@client:~$ a=($s)
    hadoop@client:~$ IFS="$old_ifs"
    hadoop@client:~$ echo ${a[*]}
    a b c d e
    hadoop@client:~$ echo ${a[0]}
    a b
    hadoop@client:~$ echo ${#a[*]}
    4

    8、字符串包含

    有时候需要判断字符串str1中是否包含字符串str2,使用=~操作符。

    str1="hello"
    str2="ell"
    if [ [$str1 =~ $str2] ];then
        echo "$str1 contains $str2"
    fi

    查看运行结果

    hadoop@client:~$ sh script_test.sh
    hello contains ell

    四、Shell中的控制结构

    0、循环接受脚本参数shift

    测试脚本如下:

    echo '原始参数:  ' $*
    shift
    echo 'shift后参数:  ' $*
    shift 2
    echo 'shift 2后参数: ' $*

    查看脚本运行结果

    hadoop@client:~$ sh script_test.sh a b c d e f g
    原始参数: a b c d e f g
    shift后参数: b c d e f g     // 移除第一个参数a
    shift 2后参数:  d e f g      // 继续移除前两个参数b和c

    1、条件表达式

    (1) if ... then

    判断表达式是经常用到的。整体结构如下所示,其中if和fi是必须的,中间的elif和else是可选的。

    if [ 判断条件1 ];then
        执行内容1
    elif [ 判断条件2 ];then
        执行内容2
    else
        执行内容3
    fi

    a)算术运算符

    算术运算符的使用格式如下

    a=10
    b=20
    val=`expr $a + $b`

    expr命令一般用于整数值,但也可用于字符串。一般格式为: 
    expr argument operator argument 
    expr也是一个手工命令行计数器。 
    expr 10 + 10 
    20 

    (注意运算符左右都有空格 ,如果没有空格表示是字符串连接) 

    使用乘号时,必须用反斜线屏蔽其特定含义。因为shell可能会误解显示星号的意义。

    expr 30 * 3 
    90

    常用的算术运算符包括

    运算符 说明 举例
    + 加法 expr $a + $b 结果为 30。
    - 减法 expr $a - $b 结果为 10。
    * 乘法 expr $a * $b 结果为 200。
    / 除法 expr $b / $a 结果为 2。
    % 取余 expr $b % $a 结果为 0。
    = 赋值 a=$b将把变量 b 的值赋给 a。
    == 相等 用于比较两个数字,相同则返回 true。[ $a == $b ] 返回 false。
    != 不相等 用于比较两个数字,不相同则返回 true。[ $a != $b ] 返回 true。

    b)关系运算符

     关系运算符的使用格式如下:

    a=10
    b=20
    $a -eq $b

    常用的关系运算符包括

    运算符 说明 举例
    -eq 检测两个数是否相等,相等返回true。 [ $a -eq $b ] 返回true。
    -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。

    c)布尔运算符

    常用的布尔运算符如下

    运算符 说明 举例
    ! 非运算,表达式为true则返回false,否则返回true。 [ ! false ] 返回 true。
    -o 或运算,有一个表达式为true则返回true。 [ $a -lt 20 -o $b -gt 100 ] 返回true。
    -a 与运算,两个表达式都为true才返回true。 [ $a -lt 20 -a $b -gt 100 ] 返回false。


    d)字符串运算符

      常用的字符串运算符如下

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


    e)文件测试运算符

    常用的文件测试运算符如下

    运算符 说明 举例
    -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)case...esac

      case表达式的使用格式如下

    case $变量 in
        "内容1")
            程序1
        ;;
        "内容2")
            程序2
        ;;
        *)        #匹配其他所有情况
            程序3
        ;;
    esac

    看一个示例,如果第一个参数为hello,则打印hello world。如果第一个参数是bye,则打印bye bye。如果是另外的情况,则输出该参数。

    case $$1 in
        "hello")
            echo "hello world"
        ;;
        "bye")
            echo "bye bye"
        ;;
        "*")
            echo $1
        ;;
    esac

    运行结果如下

    hadoop@client:~$ sh script_test.sh hello
    hello world
    hadoop@client:~$ sh script_test.sh bye
    bye bye
    hadoop@client:~$ sh script_test.sh hehe
    hehe

    2、循环表达式

    (1)while do done,until do done

          while循环的格式如下

    while [ condition ]
    do 程序 done

         while循环相反的是until循环。

    until [ condition ]
    do 程序 done

     在while循环中,当条件满足时,就执行其中的程序。而条件不成立时就终止循环。

     下面举例用两种循环来实现当输入为yes时跳出循环。

    a) while循环示例如下

    while [ "$yn" != "yes" ]
    do
      read -p "Please input yes to stop: " yn
    done
    
    echo "stop!"

    运行结果

    hadoop@client:~$ sh script_test.sh
    Please input yes to stop: no
    Please input yes to stop: no
    Please input yes to stop: yes
    Stop!

    b) until循环示例如下

    until [ "$yn" == "yes" ]
    do
        read -p "Please input yes to stop: " yn
    done
    
    echo "Stop!"

    运行结果如下:

    hadoop@client:~$ sh script_test.sh
    Please input yes to stop: no
    Please input yes to stop: yes
    Stop!

    (2)for ... do ... done

      for循环的格式如下

    for var in con1 con2 con3 ...
    do
      程序
    done

    下面这个示例循环打印输入参数列表

    for arg in $*
    do
      echo $arg
    done

    运行结果如下

    hadoop@client:~$ sh script_test.sh a b c d e
    a
    b
    c
    d
    e

     (3)for ... do ... done的另一种形式

    for ((初始值;目标值;步长))
    do
        程序
    done

    循环输出1到10中的奇数

    for((i=1;i<=10;i=i+2))
    do
        echo $i
    done

    运行结果如下

    hadoop@client:~$ bash script_test.sh
    1
    3
    5
    7
    9

    五、Shell中的函数

      在shell中也可以像其他编程语言那样,将代码封装成函数。Shell中的函数,需要注意以下两点:

    1、函数定义

    由于Shell是从上往下执行的,所以在定义函数之前就调用该函数的话,会提示command not found,例如:

    echo "Before :" `printFunc`
    
    function printFunc(){
        echo "print function !"  
    }
    
    echo "After :" `printFunc`

    运行结果如下,前一个函数调用处提示command not found

    hadoop@client:~$ sh script_test.sh
    2_script_test.sh: line 3: printFunc: command not found
    Before :
    After : print function !

    2、函数参数与shell参数

      在Shell定义的函数,是可以传递和接受参数的。在子函数中,$1表示接受的第一个参数...,这里需要注意与shell参数的区别。

      但是测试后发现$0表示的仍然是shell名称。如果想要显示当前函数名,可以使用$FUNCNAME参数,如下所示,

    function printStr(){
       echo "printStr function print: $FUNCNAME"
       echo "printStr function print: $*"    
    }
    
    echo "main print: $0"
    echo "main print: $*"
    
    printStr f1 f2 f3

    运行结果如下:

    [hadoop@client ~]$ sh script_test.sh m1 m2 m3
    main print: script_test.sh
    main print: m1 m2 m3
    printStr function print: printStr
    printStr function print: f1 f2 f3

    六、vi快捷操作

       下面操作中出现大写字母,比如G表示需要同时按住Shift和G键。n表示输入的数字。其他比如text则表示字符串。

    1、跳转

    按键 说明
    gg 跳转到第一行
    G 跳转到最后一行
    ngg/nG 跳转到最后一行
    Ctrl+f 向下翻页
    Ctrl+b 向上翻页
    h 光标左移
    j 光标下移
    k 光标上移
    l 光标右移
    w 移到下一个单词的开头
    W 移到下一个单词的开头,忽略标点
    b 移到上一个单词的开头
    B 移到上一个单词的开头,忽略标点
    e 移到下一个单词的末尾
    E 移到下个单词的末尾,忽略标点
    nw/nW/nb/nB 跳转n个单词
    L 移到当前屏幕最后一行
    M 移到当前屏幕中间行
    $ 到当前行最后一个字符
    ^ 到当前行第一个字符
    0 到当前行第一个字符
    n  
    ( 到句子的开头
    ) 到句子的结尾
    { 到段落的开头
    } 到段落的结尾

    2、查找和替换

    (1)查找

    按键 说明
    /text 向后查找text字符
    ?text 向前查找text字符
    n 跳转至下一个text字符
    N 跳转至上一个text字符
    :set ic 查找时忽略大小写
    :set noic 查找时对大小写敏感

    (2)替换

    按键 说明
    :s/oldtext/newtext/ 替换当前行第一个oldtext为newtext
     :s/oldtext/newtext/g 替换当前行所有oldtext为newtext 
     :m,ns/oldtext/newtext/ 在m行到n,用newtext替换第一个oldtext 
     :1,$s/oldtext/newtext/ 在1行到最后一行,用newtext替换第一个oldtext 
     :m,ns/oldtext/newtext/g 在m行到n,用newtext替换oldtext 
     :1,$s/oldtext/newtext/g 在1行到最后一行,用newtext替换oldtext 

    在最后输入一个c(confirm),表示替换前弹出确认提示。按y则逐一替换当前光标处匹配的字符,n则跳出当前光标处字符,a替换全部匹配的字符。

    3、复制、删除、撤销、重复

     (1)复制

    按键 说明
    yy 复制当前行
     nyy 复制光标所在的向下n行内容
     p  将复制内容黏贴到下一行
    P 将复制内容黏贴到上一行

             另外,输入y+跳转中的操作,可以为复制指定方向。比如yw,从当前位置复制到下一个单词的开头。这样可以进行复制一个单词的操作。

    (2)删除

    按键 说明
    dd 删除当前行(按p可黏贴)
    ndd 从当前行向下删除n行
    dG 从当前行删除最最后一行
    dgg 从当前行删除到第一行
    :n,md 从第n行删除到第m行
    x 删除当前字符
    nx 删除当前向后n个字符
    X 删除光标前的字符
    nX 删除当前向前n个字符

      另外,输入d+跳转中的操作,可以为删除指定方向。比如dw,从当前位置删除至下一个单词开头。

    (3)撤销

    按键 说明
    u 撤销上一次操作
    U 撤销当前行所有操作
    . 重复最后一次操作

    (4)重复

    按键 说明
    . 重复最后一次操作

    4、其他

    按键 说明
    J 将下一行连接到本行末尾
    nJ 将下n行连接到本行末尾
    ~ 将当前字符切换大小写
    n~ 将当前向后n个字符切换大小写
    g~~ 切换当前行大小写
    u 列编辑模式下,选中列转换成小写
    U 列编辑模式下,选中列转换成大写
    guu 当前行转换成小写
    gUU 当前行转换成大写
    guw 当前单词转换成小写
    gUw 当前单词转换成大写
       

    5、列编辑

      按Ctrl+V,进入列编辑模式

    (1)删除列

      进入列编辑模式,

      移动光标,选中需要删除的列,

      按d,则会删除选中内容。

    (2)插入列

      进入列编辑模式,

      移动光标选中需要插入内容的列。

      按shift+i,会在选中列的第一行输入想要插入的内容。

      连续按两次ESC,则会在选中的列处全部插入输入字符。

  • 相关阅读:
    ExtJs 之 ComboBox级联使用
    JavaScript 面向对象(三) —— 高级篇
    JavaScript 面向对象(二) —— 案例篇
    JavaScript 面向对象(一) —— 基础篇
    手机进销存系统/供应链管理系统
    jQuery查找——parent/parents/parentsUntil/closest
    Echarts实现今日头条疫情地图和用户画像
    简版在线聊天Websocket
    推荐几个程序员常用的工具
    SpringBoot+Vue+ElementUI+动态菜单模版
  • 原文地址:https://www.cnblogs.com/jiangjian123/p/11418490.html
Copyright © 2020-2023  润新知