• Shell脚本中常用的特殊符号


    #    井号

    这几乎是个shell满场都有的符号,用在shell脚本的开头,如"#!/bin/bash"
    
    井号也常出现在一行的开头,或者位于完整指令之后,这类情况表示符号后面的是注解文字,不会被执行。
    由于这个特性,当临时不想执行某行指令时,只需在该行开头加上 # 就行了。这常用在撰写过程中。
    如果被用在指令中,或者引号双引号括住的话,或者在倒斜线的后面,那他就变成一般符号,不具上述的特殊功能。

    ~    用户家目录
    算是个常见的符号,代表使用者的 home 目录:cd ~;也可以直接在符号后加上某帐户的名称:cd ~user或者当成是路径的一部份:~/bin
    ~+ 当前的工作目录,这个符号代表当前的工作目录,她和内建指令 pwd的作用是相同的。

    [root@VM_16_9_centos ~]# pwd
    /root
    [root@VM_16_9_centos ~]# echo ~+/var/log       
    /root/var/log

    ~- 上次的工作目录,这个符号代表上次的工作目录。

    [root@VM_16_9_centos ~]# pwd
    /root
    [root@VM_16_9_centos ~]# echo ~+/var/log       
    /root/var/log
    [root@VM_16_9_centos ~]# echo ~-/etc/httpd/logs
    /root/test/etc/httpd/logs

    ;    分号
    在 shell 中,担任"连续指令"功能的符号就是"分号"。譬如以下的例子:

    [root@VM_16_9_centos ~]# mkdir test;cd test;echo "safd" >test1;cat test1;pwd
    safd
    /root/test

    ;;    连续分号
    专用在 case 的选项,担任 Terminator 的角色。

    [root@localhost ~]# cat a.sh 
    #!/bin/bash
    
    read -p "please write:" fop
    
    case ${fop} in
    help)
       echo "Usage: Command -help -version filename";;
    version)
       echo "version 0.1" ;;
    esac
    
    [root@localhost ~]# sh a.sh  
    please write:help
    Usage: Command -help -version filename

    .    点号 (dot,就是“点”)
    在 shell 中,使用者应该都清楚,一个 dot 代表当前目录,两个 dot 代表上层目录。

    [root@ss-server ~]# cd /usr/local/src/
    [root@bz3aomsmsap1002 src]# cd ../
    [root@bz3aomsmsap1002 local]# pwd
    /usr/local
    
    [root@ss-server ~]# cd /usr/local/src/
    [root@bz3aomsmsap1002 src]# cd ../../
    [root@bz3aomsmsap1002 usr]# pwd
    /usr

    如果档案名以 dot 开头,该档案就属特殊档案,用 ls指令必须加-a 选项才会显示(即查看隐藏文件)。除此之外,在 regularexpression 中,一个 dot 代表匹配一个字元。

    ' '    单引号 (single quote)
    被单引号用括住的内容,将被视为单一字串。在引号内的代表变数的$符号,没有作用,也就是说,他被视为一般符号处理,防止任何变量替换。

    [root@localhost ~]# heyyou=homeecho
    [root@localhost ~]# echo '$heyyou'
    $heyyou

    " "    双引号 (double quote)
    被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引数的处理方式不同。

    [root@VM_16_9_centos ~]# heyyou=homeecho
    [root@VM_16_9_centos ~]# echo ${heyyou}
    homeecho
    [root@VM_16_9_centos ~]# echo '${heyyou}'
    ${heyyou}
    [root@VM_16_9_centos ~]# echo "${heyyou}"
    homeecho

    ``     倒引号,相当于$(),表示命令替换,将里面命令执行结果传给变量参数。
    在前面的单双引号,括住的是字串,但如果该字串是一列命令列,会怎样?答案是不会执行。要处理这种情况,我们得用倒单引号``来做。

    [root@VM_16_9_centos ~]# fdv=`date +%F`
    [root@VM_16_9_centos ~]# echo "Today $fdv" 
    Today 2019-11-28

    在倒引号内的 date +%F 会被视为指令,执行的结果会带入 fdv 变数中。

    ,     逗点 (标点中的逗号)
    这个符号常运用在运算当中当做"区隔"用途。如下例:

    [root@VM_16_9_centos ~]# cat a.sh
    #!/bin/bash
    let "t1 = ((a = 5 + 3, b = 7 - 1, c = 15 / 3))"
    echo "t1= $t1, a = $a, b = $b"
    [root@VM_16_9_centos ~]# sh a.sh
    t1= 5, a = 8, b = 6

    /    斜线
    在路径表示时,代表目录。

    [root@VM_16_9_centos ~]# cd /etc/rc.d
    [root@VM_16_9_centos rc.d]# cd ../..
    [root@VM_16_9_centos /]# 

    通常单一的 / 代表 root 根目录的意思;在四则运算中,代表除法的符号。

    [root@VM_16_9_centos ~]# let "num1 = ((a = 10 / 2, b = 25 / 5))"
    [root@VM_16_9_centos ~]# echo ${num1}
    5

    \     双倒斜线 和 单倒斜线 

    \  双倒斜线:放在指令前,有取消 aliases的作用
    =======================================
    [root@localhost ~]# alias kevin="ls"
    [root@localhost ~]# kevin 
    a  anaconda-ks.cfg
    [root@localhost ~]# kevin -l
    total 4
    -rw-r--r--  1 root root    0 Nov 28 22:56 a
    -rw-------. 1 root root 1850 Oct 22 12:11 anaconda-ks.cfg
    
    [root@localhost ~]# \kevin 
    -bash: kevin: command not found
    
    [root@localhost ~]# \kevin -l
    -bash: kevin: command not found
    
      单倒斜线:放在特殊符号前,则该特殊符号的作用消失。即转义符号
    =======================================
    [root@VM_16_9_centos ~]# bkdir=/home             
    [root@VM_16_9_centos ~]# echo "this is ${bkdir}" 
    this is /home
    [root@VM_16_9_centos ~]# echo "this is ${bkdir}"
    this is ${bkdir}
    [root@VM_16_9_centos ~]# echo "this is ${bkdir}"
    "this is /home"
    [root@VM_16_9_centos ~]# echo "this is ${bkdir}"
    "this is ${bkdir}"

    |    管道 (pipeline)
    pipeline 是 Linux系统中基础且重要的观念。连结上个指令的标准输出,做为下个指令的标准输入。

    [root@VM_16_9_centos ~]# who
    root     pts/0        2019-11-28 22:49 (115.171.60.14)
    root     pts/1        2019-11-28 23:01 (115.171.60.14)
    [root@VM_16_9_centos ~]# who | wc -l 
    2

    善用这个观念,对精简 script 有相当的帮助。

    !    惊叹号(negate or reverse)
    通常它代表反逻辑的作用,譬如条件侦测中,用 != 来代表"不等于"

    [root@VM_16_9_centos ~]# cat a.sh
    #!/bin/bash
    
    if [ "$?" != 0 ];then
      echo "Executes error"
      exit 1
    fi 
    [root@VM_16_9_centos ~]# sh a.sh 
    "Executes error"

    在规则表达式中她担任 "反逻辑" 的角色

    [root@VM_16_9_centos ~]# touch bo{0,1,2,3,4,5,6,7,8,9}
    [root@VM_16_9_centos ~]# ls
    bo0  bo1  bo2  bo3  bo4  bo5  bo6  bo7  bo8  bo9
    [root@VM_16_9_centos ~]# ls bo{0,1,2,3}
    bo0  bo1  bo2  bo3
    [root@VM_16_9_centos ~]# ls bo[0-3]
    bo0  bo1  bo2  bo3
    
    显示除了bo0-bo3之外的其他文件
    [root@VM_16_9_centos ~]# ls bo[!0-3]
    bo4  bo5  bo6  bo7  bo8  bo9
    
    显示除了bo5-bo8之外的其他文件
    [root@VM_16_9_centos ~]# ls bo[!5-8]
    bo0  bo1  bo2  bo3  bo4  bo9

    :    内奸指令 
    在 bash 中,这是一个内建指令:"什么事都不干",但返回状态值 0。

    什么都不干,返回状态值 0
    [root@VM_16_9_centos ~]# echo $?
    0
    
    [root@VM_16_9_centos ~]# : > a.txt
    上面这一行,相当于 
    [root@VM_16_9_centos ~]# cat /dev/null >a.xtt
    不仅写法简短了,而且执行效率也好上许多。

    ?      问号  
    在文件名扩展(Filename expansion)上扮演的角色是匹配一个任意的字元,但不包含 null 字元。

    [root@VM_16_9_centos ~]# ls
    a12e.txt  aae_txt  agte.txt  akte.txt  aste.txt
    [root@VM_16_9_centos ~]# ls a?te.txt
    agte.txt  akte.txt  aste.txt
    [root@VM_16_9_centos ~]# ls a1?e.txt
    a12e.txt 
    [root@VM_16_9_centos ~]# ls aae?txt
    aae_txt

    善用她的特点,可以做比较精确的档名匹配。

    *    任意个任意字符。任意的单个或多个字符  
    相当常用的符号。在文件名扩展(Filename expansion)上,她用来代表任何字元,包含 null 字元

    [root@VM_16_9_centos ~]# ls
    a12e.txt  aae_txt  agte.txt  akte.txt  a.sh  aste.txt
    [root@VM_16_9_centos ~]# ls a*e.txt
    a12e.txt  agte.txt  akte.txt  aste.txt
    [root@VM_16_9_centos ~]# ls a*te.txt
    agte.txt  akte.txt  aste.txt
    
    在运算时,它则代表 "乘法"。 
    [root@VM_16_9_centos ~]# let "fmult=2*3"   
    [root@VM_16_9_centos ~]# echo ${fmult}
    6
    
    除了内建指令 let,还有一个关于运算的指令expr,星号在这里也担任"乘法"的角色。不过在使用上得小心,他的前面必须加上escape字元(即转义符)。
    [root@VM_16_9_centos ~]# expr 2 * 3
    6

    **    次方运算

    [root@ss-server ~]# let sum=2**4
    [root@ss-server ~]# echo ${sum}
    16
    [root@ss-server ~]# echo $((3*3))
    9
    [root@ss-server ~]# let sum=2**4 
    [root@ss-server ~]# echo ${sum}  
    16
    [root@ss-server ~]# echo $((3**3))
    27
    [root@ss-server ~]# echo $[3**4]
    81

    $     变量符号、正则里表示"行尾"

    $是变量替换的代表符号。 
    [root@ss-server ~]# var="wang lao hu"
    [root@ss-server ~]# echo $var
    wang lao hu
    [root@ss-server ~]# echo ${var}
    wang lao hu
    
    另外:
    在Regular Expressions里被定义为 "行" 的最末端。这个常用在grep、sed、awk 以及 vim(vi) 当中。
    
    ^ 表示行首
    $ 表示行尾

    ${}    变量的正规表达式    
    bash 对 ${} 定义了不少用法,如下,具体说明可参考: https://www.cnblogs.com/kevingrace/p/5996133.html 
    ${parameter:-word} ${parameter:=word} ${parameter:?word} ${parameter:+word} ${parameterffset} ${parameterffset:length} ${!prefix*} ${#parameter} ${parameter#word} ${parameter##word} ${parameter%word} ${parameter%%word} ${parameter/pattern/string} ${parameter//pattern/string}

    $*    所有引用的变量 
    $* 引用script的执行引用变量,引用参数的算法与一般指令相同,指令本身为0,其后为1,然后依此类推。引用变量的代表方式如下:
    $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, ${10}, ${11}.....
    个位数的,可直接使用数字,但两位数以上,则必须使用 {} 符号来括住 具体使用含义后面有详细说明
    $*  则是代表所有引用变量的符号。使用时,得视情况加上双引号。

    [root@ss-server ~]# echo "$*"                 
    ""
    [root@ss-server ~]# echo "$*"                   
    
    [root@ss-server ~]# cat test.sh                 
    #!/bin/bash
    USER=$1
    AGE=$2
    ADD=$3
    HE=$4
    
    echo "$1 is $2,come from $3,and $4"
    echo "$*"
    
    [root@ss-server ~]# sh test.sh 张阳 20 安徽 帅气
    张阳 is 20,come from 安徽,and 帅气
    张阳 20 安徽 帅气

    $@    所有引用的变量
    $@ 与 $* 具有相同作用的符号,不过它们两者有一个不同点。
    符号 $* 将所有的引用变量视为一个整体。但符号 $@ 则仍旧保留每个引用变量的区段观念。 [ $@ 与 $* 二者的区别在下面会详细提到]

    $#    参数变量的总数量  
    这也是与引用变量相关的符号,它的作用是告诉你,引用变量的总数量是多少。

    [root@ss-server ~]# cat a.sh            
    #!/bin/bash
    USER=$1
    AGE=$2
    ADD=$3
    HE=$4
    
    echo "$1 is $2,come from $3,and $4"
    echo "$*"
    echo "$@"
    echo "$#"
    [root@ss-server ~]# sh a.sh 黄涛 30 杭州
    黄涛 is 30,come from 杭州,and 
    黄涛 30 杭州
    黄涛 30 杭州
    3
    [root@ss-server ~]# echo "$#"
    "0"
    [root@ss-server ~]# echo "$#"  
    0

    $?    状态值 (status variable)
    一般来说,Linux 系统的进程以执行系统调用exit()来结束的。这个回传值就是status值。回传给父进程,用来检查子进程的执行状态。
    一般指令程序倘若执行成功,其$?回传值为 0若执行失败,则$?回传值为 1

    [root@ss-server ~]# ls a.sh 
    a.sh
    [root@ss-server ~]# echo $?
    0
    [root@ss-server ~]# ls aa.sh
    ls: cannot access aa.sh: No such file or directory
    [root@ss-server ~]# echo $? 
    2

    $$    当前shell的PID
    由于进程的ID是唯一的,所以在同一个时间,不可能有重复性的 PID。有时,script会需要产生临时文件,用来存放必要的资料。而此script亦有可能在同一时间被使用者们使用。在这种情况下,固定文件名在写法上就显的不可靠。唯有产生动态文件名,才能符合需要。符号$$或许可以符合这种需求。它代表当前shell 的 PID。

    [root@ss-server ~]# echo "hello world" 
    hello world
    [root@ss-server ~]# echo $$
    78520
    [root@ss-server ~]# echo "hello world" > aa.$$
    [root@ss-server ~]# cat aa.78520 
    hello world
    
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    USER=$1
    AGE=$2
    ADD=$3
    HE=$4
     
    echo "$1 is $2,come from $3,and $4"
    echo "$#"
    echo "$*"
    echo "$@"
    echo "$$"
    echo "$0"
    [root@bz3aomsmsap1002 ~]sh a.sh 张阳 20 安徽 帅气
    张阳 is 20,come from 安徽,and 帅气
    4
    张阳 20 安徽 帅气
    张阳 20 安徽 帅气
    90261
    a.sh

    使用它来作为文件名的一部份,可以避免在同一时间,产生相同文件名的覆盖现象。
    基本上,系统会回收执行完毕的 PID,然后再次依需要分配使用。所以 script 即使临时文件是使用动态档名的写法,如果script 执行完毕后仍不加以清除,会产生其他问题。

    ( )    指令群组 (command group)
    用括号将一串连续指令括起来,这种用法对 shell 来说,称为指令群组。如下面的例子:

    [root@ss-server ~]# (cd ~ ; pwstr=`pwd` ;echo ${pwstr})
    /root

    指令群组有一个特性,shell会以产生 subshell来执行这组指令。因此,在其中所定义的变数,仅作用于指令群组本身。来看个例子:

    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    a=wang
    b=zhang
    (a=han ; echo -e "
     $a 
    ")
    (b=xiaoru; echo -e "this is $b")
    echo $a
    echo $b
    
    [root@ss-server ~]# sh a.sh
    
     han 
    
    this is xiaoru
    wang
    zhang
    
    由上面可知:shell的指令群组所定义的变数,仅作用于指令群组本身。
    
    来看看echo的几个操作效果
    =============================================================
    [root@ss-server ~]# echo "aa"
    aa
    [root@ss-server ~]# echo "aa"
    "aa"
    [root@ss-server ~]# echo -e "
     wang 
    "  
    
     wang 
    
    [root@ss-server ~]# echo -e "
     wang 
    "    # 这种情况下,
    就不是换行符了,因为双引号也被转义了。
    "n wang n"

    除了上述的指令群组,括号也用在 array数组变数的定义上;另外也应用在其他可能需要加上escape字元才能使用的场合,如运算式。

    (( ))
    这组符号的作用与 let 指令相似,用在算数运算上,是 bash 的内建功能。所以,在执行效率上会比使用 let指令要好许多

    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    
    (( a = 10 ))
    echo -e "inital value, a = $a
    "
    
    (( a++))
    echo "after a++, a = $a"
    
    [root@ss-server ~]# sh a.sh
    inital value, a = 10
    
    after a++, a = 11

    请记住:
    $(())、$[]    这两个效果是一样的,都是运算符号,显示运算结果。
    let     也是运算符号,设置运算

    [root@ss-server ~]# echo $((4*9))
    36
    [root@ss-server ~]# echo $[4*9]
    36
    [root@ss-server ~]# let a=4*9
    [root@ss-server ~]# echo $a  
    36
    [root@ss-server ~]# let "a=4*9"
    [root@ss-server ~]# echo $a    
    36
    [root@ss-server ~]# let a="3+5"       
    [root@ss-server ~]# echo $a    
    8
    
    [root@ss-server ~]# a=10
    [root@ss-server ~]# let a++         #表示变量a数值加1
    [root@ss-server ~]# echo $a
    11

    { } 大括号 
    这种大括号的组合,常用在字串的组合上,来看个例子

    [root@ss-server ~]# mkdir aa{1,2,3}
    [root@ss-server ~]# ls 
    aa1 aa2 aa3
    [root@ss-server ~]# ll -d bb1*
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 bb1-k01
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 bb1-k02
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 bb1-k03
    [root@ss-server ~]# ll -d cc1*
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 cc1-k01
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 cc1-k02
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 cc1-k03
    [root@ss-server ~]# ll -d dd1*
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 dd1-k01
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 dd1-k02
    drwxr-xr-x 2 root root 4096 Dec  5 11:37 dd1-k03
    [root@ss-server ~]# touch {wan,han}_{1,2,3}
    [root@ss-server ~]# ls wan*
    wan_1  wan_2  wan_3
    [root@ss-server ~]# ls han*
    han_1  han_2  han_3
    [root@ss-server ~]# chmod 755 /root/wan_{1,2,3}
    [root@ss-server ~]# ll /root/wan_{1,2,3}
    -rwxr-xr-x 1 root root 0 Dec  5 11:39 /root/wan_1
    -rwxr-xr-x 1 root root 0 Dec  5 11:39 /root/wan_2
    -rwxr-xr-x 1 root root 0 Dec  5 11:39 /root/wan_3

    这组符号在适用性上相当广泛。能加以善用的话,回报是精简与效率。像下面的例子

    ?表示任意单个字符!!!
    [root@ss-server ~]# chown app.app /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} 

    如果不是因为支援这种用法,我们得写几行重复几次呀!

    [ ] 中括号
    常出现在流程控制中,扮演括住判断式的作用。

    [root@ss-server ~]# ls hahaha
    ls: cannot access hahaha: No such file or directory
    [root@ss-server ~]# echo $?  
    2
    
    [root@ss-server ~]# cat a.sh 
    #!/bin/bash
    
    ls hahaha >/dev/null 2>&1
    if [ "$?" != 0 ];then
       echo "Executes error"
       exit 1
    fi 
    
    [root@ss-server ~]# sh a.sh
    Executes error

    这个符号在正则表达式中担任类似 "范围" 或 "集合" 的角色

    [root@ss-server ~]# touch aaa{1,2,3,4}
    [root@ss-server ~]# ls aaa*
    aaa1  aaa2  aaa3  aaa4
    [root@ss-server ~]# rm -f aaa[1234]
    [root@ss-server ~]# ls aaa*
    ls: cannot access aaa*: No such file or directory
    
    注意:
    rm -f aaa[1234]  表示删除aaa1、aaa2、aaa3、aaa4
    相当于
    rm -f aaa{1,2,3,4}
    
    注意:
    只有在删除文件的时候,[]可以起到上面类似 "范围" 或 "集合" 的角色!
    在其他操作都不会起到该作用!
    
    如下,在touch的时候,[]并没有起到范围或集合的作用!
    [root@ss-server ~]# touch aa[123]
    [root@ss-server ~]# touch aa[123]_[xyz]
    [root@ss-server ~]# ls aa*
    aa[123]  aa[123]_[xyz]

    [[ ]]
    这组符号与先前的 [] 符号,基本上作用相同,但它允许在其中直接使用 || 与&& 逻辑等符号||表示"或",&&表示"和" 。双中括号[[]]和单中括号[]的区别,在下面会详细提到。

    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    read -p "请输入一个数字: " num
    if [[ ${num} > 10 && ${num}< 30 ]];then
       echo "你输入的数字是${num}"
    else
       echo "输入的数字不符合要求"
    fi
    
    [root@ss-server ~]# sh a.sh 
    请输入一个数字: 16
    你输入的数字是16
    [root@ss-server ~]# sh a.sh
    请输入一个数字: 56
    输入的数字不符合要求
    
    上面脚本还可以改写为下面内容,效果是一样的!
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    
    #echo -n表示不换行
    echo -n "输入一个数字: "
    read num
    if [[ ${num} > 10 && ${num}< 30 ]];then
       echo "你输入的数字是${num}"
    else
       echo "输入的数字不符合要求"
    fi
    
    [root@ss-server ~]# sh a.sh
    输入一个数字: 19
    你输入的数字是19
    [root@ss-server ~]# sh a.sh
    输入一个数字: 48
    输入的数字不符合要求
    
    ===============================================
    需要注意:
    if判断语句中如果使用[[]],可以在[[]]中直接使用&&、||符号,表示"和"、"或"。可以用于字符串对比符号,也可以用于整数对比符号。
    if判断语句中如果使用[],在[]中可以使用-a、-o,表示"和"、"或",但是这个用于整数比较时只能使用"-eq、-ne、-ge、-gt、-lt、-le",不能使用>、>=、<、<=、=、!=。
    
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    read -p "请输入一个数字: " num
    if [ ${num} -gt 10  -a  ${num} -le 30 ];then
       echo "你输入的数字是${num}"
    else
       echo "输入的数字不符合要求"
    fi
    
    [root@ss-server ~]# sh a.sh
    请输入一个数字: 12
    你输入的数字是12
    [root@ss-server ~]# sh a.sh 
    请输入一个数字: 45
    输入的数字不符合要求
    
    上面脚本中的[ ${num} -gt 10  -a  ${num} -le 30 ]
    不能改为:
    [ ${num} -ge 10 ] -a  [${num} -le 30 ]
    也不能改为
    [ ${num} > 10 -a ${num} < 30 ]
    
    [[]]的&&、||也可以用于整数对比。
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    read -p "请输入一个数字: " num
    if [[ ${num} -ge 10 && ${num} -le 30 ]];then
       echo "你输入的数字是${num}"
    else
       echo "输入的数字不符合要求"
    fi
    [root@ss-server ~]# sh a.sh
    请输入一个数字: 17
    你输入的数字是17
    [root@ss-server ~]# sh a.sh
    请输入一个数字: 67
    输入的数字不符合要求

    ||     逻辑符号 
    这个会时常看到,代表 or 逻辑的符号,表示前一个命令执行成功,则就此结束,后一个命令就不执行;前一个命令执行失败,后一个命令才会执行。如 A || B  表示A执行成功后,B就不会再执行了;A执行失败或不执行,B才能执行。

    &&     逻辑符号
    这个也会常看到,代表 and 逻辑的符号,表示串行,前一个命令执行成功,后一个命令才接着执行;前一个命令执行失败,则就此结束,后一个命令也不会执行。如 A && B  表示A执行成功后,B也会跟着执行了;A执行失败或不执行,B也不会执行了

    &     后台工作
    单一个& 符号,且放在完整指令列的最后端,即表示将该指令列放入后台中工作。 放在几个指令中间时,表示并行,实质就是在后台并行执行,跟指令前后顺序无关。

    [root@ss-server ~]# tar -zvcf test1.tar.gz test1 > /dev/null &

    <...>   单字边界
    这组符号在规则表达式中,被定义为"边界"的意思。如下想要在test文件中找寻 the 这个单字时,如果我们用

    [root@ss-server ~]# cat test 
    the
    there
    this is a
    123456
    thee
    [root@ss-server ~]# grep "the" test
    the
    there
    thee

    如上会发现,像 there、thee这类的单字,也会被当成是匹配的单字。因为 the 正巧是there、thee的一部份。如果要想必免这种情况,就得加上单字边界符号,进行精准匹配:

    [root@ss-server ~]# cat test          
    the
    there
    this is a
    123456
    thee
    [root@ss-server ~]# grep "the" test   
    the
    there
    thee
    [root@ss-server ~]# grep "<the>" test
    the
    
    另外:上面在进行grep精准匹配时,除了使用<str>单字边界符号,还可以使用grep -w进行精准匹配!
    [root@ss-server ~]# cat test 
    the
    there
    this is a
    123456
    thee
    [root@ss-server ~]# grep -w "the" test 
    the
    
    可以参考:https://www.cnblogs.com/kevingrace/p/9299232.html

    +    加号 
    在运算式中,她用来表示 "加法"。

    [root@ss-server ~]# expr 10 + 11 + 12  
    33
    
    注意:expr命令中的计算符号和数字中间一定要有空格!!否则无效!并且后面的运算两边不能有引号,否则也无效!
    
    下面都是错误的!!
    [root@ss-server ~]# expr 10+11+12      
    10+11+12
    [root@ss-server ~]# expr "10 + 11 + 12"
    10 + 11 + 12
    
    另外:注意expr使用*乘法的时候,需要在*前面加上转义符号,否则无效!
    [root@ss-server ~]# expr 2 * 3 
    expr: syntax error
    [root@ss-server ~]# expr 2 * 3
    6

    此外在正则表达式中,用来表示"很多个"的前面字元的意思。但是注意,正则里使用+符号表示"很多个"意思时,+号前面必须加上\符号!!

    [root@ss-server ~]# cat test 
    123456
    10aaaahuihhhhh
    s34eddddd
    kkkhuan
    [root@ss-server ~]# grep "10\+a" test 
    10aaaahuihhhhh
    [root@ss-server ~]# grep "e\+d" test           
    s34eddddd
    [root@ss-server ~]# grep "\k" test 
    kkkhuan

    -     减号 
    在运算式中,她用来表示 "减法"。

    [root@ss-server ~]# expr 10 - 2 
    8

    在 cd 指令中则比较特别,"cd -"表示变更工作目录到"上一次"工作目录。

    [root@ss-server ~]# cd /usr/local/src/
    [root@bz3aomsmsap1002 src]# cd
    [root@ss-server ~]# cd -
    /usr/local/src
    [root@bz3aomsmsap1002 src]# 

    %      除法后的余数 
    在运算式中,用来表示 "除法"后的余数。 [运算式中的乘法*,用的时候需要在前面加一个转移符   expr  5 * 10]

    [root@ss-server ~]# expr 10 % 2   
    0
    [root@ss-server ~]# expr 10 % 3    
    1
    [root@ss-server ~]# expr 10 % 6
    4
    [root@ss-server ~]# expr 6 % 9
    6
    [root@ss-server ~]# expr 6 % 90
    6
    [root@ss-server ~]# expr 5 % 6
    5
    
    %表示余数,即整除后的余数是多少。
    如果小除大,则%余数统一为前面那个小的数。  

    此外,也被运用在关于变量的规则表达式当中的下列

    ${parameter%word}
    ${parameter%%word} 
    
    一个 % 表示最短的 word 匹配,两个表示最长的 word 匹配。
    可以参考上面"参数替换"部分有详细介绍

    =      等号
    常在设定变数时看到的符号。

    [root@ss-server ~]# vara="hello world"
    [root@ss-server ~]# echo "vara=${vara}"
    vara=hello world

    或者像是 PATH 的设定,甚至应用在运算或判断式等此类用途上。

    ==      等号 
    常在条件判断式中看到,代表 "等于" 的意思。
    if [ $vara == $varb ]
    ...下略

    != 不等于
    常在条件判断式中看到,代表 "不等于" 的意思。
    if [ $vara != $varb ]
    ...下略

    ^
    这个符号在正则表达式中,代表行的 "开头" 位置!

    输出/输入重导向
    > 、>>、< 、<< 、<>、>&、>&2

    文件描述符(File Descriptor),用一个数字(通常为0-9)来表示一个文件。
    常用的文件描述符如下:
    文件描述符 名称 常用缩写 默认值
    0   标准输入 stdin 键盘
    1   标准输出 stdout 屏幕
    2   标准错误输出 stderr 屏幕
    在简单地用<或>时,相当于使用 0< 或 1>。如下面说明: 
    # cmd > file
    把cmd命令的输出重定向到文件file中。如果file已经存在,则清空原有文件,使用bash的noclobber选项可以防止复盖原有文件。[即>表示覆盖内容]
    # cmd >> file
    把cmd命令的输出重定向到文件file中,如果file已经存在,则把信息加在原有文件後面。 [即>>表示追加内容]
    # cmd < file
    使cmd命令从file读入
    # cmd << text
    从命令行读取输入,直到一个与text相同的行结束。除非使用引号把输入括起来,此模式将对输入内容进行shell变量替换。如果使用<<- ,则会忽略接下来输入行首的tab,结束行也可以是一堆tab再加上一个与text相同的内容,可以参考後面的例子。
    # cmd <<< word
    把word(而不是文件word)和後面的换行作为输入提供给cmd。
    # cmd <> file
    以读写模式把文件file重定向到输入,文件file不会被破坏。仅当应用程序利用了这一特性时,它才是有意义的。
    # cmd >| file
    功能同>,但即便在设置了noclobber时也会复盖file文件,注意用的是|而非一些书中说的!,目前仅在csh中仍沿用>!实现这一功能。
    : > filename 把文件"filename"截断为0长度.# 如果文件不存在, 那么就创建一个0长度的文件(与'touch'的效果相同).
    # cmd >&n    把输出送到文件描述符n
    # cmd m>&n    把输出 到文件符m的信息重定向到文件描述符n
    # cmd >&-    关闭标准输出
    # cmd <&n   输入来自文件描述符n
    # cmd m<&n  m来自文件描述各个n
    # cmd <&-    关闭标准输入
    # cmd <&n- 移动输入文件描述符n而非复制它。(需要解释)
    # cmd >&n- 移动输出文件描述符 n而非复制它。(需要解释)
    注意: >&实际上复制了文件描述符,这使得cmd > file 2>&1与cmd 2>&1 >file的效果不一样。

    关于EOF用法:https://www.cnblogs.com/kevingrace/p/6257490.html
    通常在执行一个命令时,如果不想打印命令执行的结果(包括正确或错误的结果信息),则通常使用"command >/dev/null 2>&1"

    Shell中几种特殊的参数变量的引用
    $1、$2、$3……${10}、${11}、${12}…… :表示脚本传入的的各个参数,注意当需表示两位数以后的参数时数字要用花括号括起
    $@ 列出所有的参数,各参数用空格隔开
    $*  列出所有的参数,各参数用环境变量的第一个字符隔开

                                                            $* 和 $@ 的区别                                                                      
    1)$* 将所有的引用变量视为一个整体。但$@则仍旧保留每个引用变量的区段观念
    2)当不加引号时,$*和$@二者都是返回传入的参数,但是当加了引号后,$*把参数作为一个字符串整体(单字符串)返回,$@把每个参数作为一个字符串返回!

    1) 示例1
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    
    for i in $*
    do
      echo $i
    done
    
    echo "++++++ $*和$@对比(不加双引号) ++++++"
    
    for j in $@
    do 
      echo $j
    done
    
    [root@ss-server ~]# sh a.sh aa bb cc
    aa
    bb
    cc
    ++++++ $*和$@对比(不加双引号) ++++++
    aa
    bb
    cc
    
    2) 示例2
    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    
    for i in "$*"
    do
      echo $i
    done
    
    echo "++++++ $*和$@对比(加双引号) ++++++"
    
    for j in "$@"
    do 
      echo $j
    done
    [root@ss-server ~]# sh a.sh aa bb cc
    aa bb cc
    ++++++ $*和$@对比(加双引号) ++++++
    aa
    bb
    cc
    
    3)示例3,在一个shell函数里分别定义 加双引号和不加双引号 传参时,$@和$*的区别
    [root@ss-server ~]# cat a.sh
    #! /bin/bash
    
    function test() {
        echo "未加引号,二者相同"
        echo $*
        echo $@
        echo "加入引号后对比"
        
        echo "----"$*----""
            for N in "$*"
            do
               echo $N
            done
    
        echo "----"$@----""
            for N in "$@"
            do
               echo $N
            done
    }
    test  11 22 33
    [root@ss-server ~]# sh a.sh
    未加引号,二者相同
    11 22 33
    11 22 33
    加入引号后对比
    ----$*----
    11 22 33
    ----$@----
    11
    22
    33
    
    ====================================================================================
    通过上面对比,可以发现:
    不加引号时,$*和$@二者都是返回传入的参数;
    加了引号后,$*把参数作为一个字符串整体(单字符串)返回,$@把每个参数作为一个字符串返回!

    命令列表 
    and列表   statement1 && statement2  && .....   表示只有在前面所有的命令都执行成功的情况下才执行后一条命令;即前面成功,后面继续执行;前面失败,后面也不执行!
    or列表      statement1 || statement2  || …..   表示允许执行一系列命令直到有一条命令成功为止,其后所有命令将不再被执行;即前面成功,后面不执行;前面失败,后面执行!!

    [root@ss-server ~]# cat a.sh
    #!/bin/bash
    
    touch file_one >/dev/null 2>&1
    rm -f file_two >/dev/null 2>&1
    
    if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there";then
       echo "in if"
    else
       echo "in else"
    fi
    exit 0
    [root@ss-server ~]# sh a.sh
    hello
    in else
    

    if逻辑判断语句中常用到的参数 以及 注意细节 (如[[]]和[]的区别)

    [ -a file ]  如果 file 存在则为真。  
    [ -e file ]  如果 file 存在则为真。
    
    [ -f file ]  如果 file 存在且是一个普通文件则为真。
    [ -d file ]  如果 file 存在且是一个目录则为真。   
    
    [ -b file ]  如果 file 存在且是一个块特殊文件则为真。(即设备文件,如/dev/sda1、/dev/sda2)  
      
    [ -h file ]  如果 file 存在且是一个符号文件则为真。(符号文件即是软链接文件)
    [ -L file ]  如果 file 存在且是一个符号文件则为真。(符号文件即是软链接文件)
    
    [ -g file ]  如果 file 存在且已经设置了SGID则为真。 
    [ -u file ]  如果 file 存在且设置了SUID则为真。 
    [ -k file ]  如果 file 存在且已经设置了粘制位则为真。(即设置了t权限的目录,粘制位仅对目录有效)  
    
    [ -r file ]  如果 file 存在且是可读的则为真。  
    [ -w file ]  如果 file 存在且是可写的则为真。  
    [ -x file ]  如果 file 存在且是可执行的则为真。
    
    [ -s file ]  如果 file 存在且大小不为0则为真。
    
    [ -O file ]  如果 file 存在且属有效用户ID则为真。  
    [ -G file ]  如果 file 存在且属有效用户组则为真。  
    
    [ file1 -nt file2 ]  如果 file1 比 file2 要老(即先创建), 或者 file1 存在且 file2不存在则为真。  
    [ file1 -ot file2 ]  如果 file1 比 file2 要老(即先创建), 或者 file2 存在且 file1 不存在则为真。  
    
    [ -z str ]  如果str字符串的长度为零则为真。 (即空串为真) 
    [ -n str ] or [ str ]  如果str字符串的长度为非零则为真。 (即非空串为真)
    
    [ str1 == str2 ]  如果2个字符串相同则为真。  
    [ str1 != str2 ]  如果字符串不相等则为真。 
    
    二、简单总结
    ===========================================================================
    1)字符串判断 
    str1 = str2     当两个串有相同内容、长度时为真 
    str1 != str2     当串str1和str2不等时为真 
    -n str1       当串的长度大于0时为真(串非空) 
    -z str1       当串的长度为0时为真(空串) 
    str1         当串str1为非空时为真。等于"-n star1"
    
    2)数字的判断 
    int1 -eq int2    两数相等为真 
    int1 -ne int2    两数不等为真 
    int1 -gt int2    int1大于int2为真 
    int1 -ge int2    int1大于等于int2为真 
    int1 -lt int2    int1小于int2为真 
    int1 -le int2    int1小于等于int2为真
    
    3)文件的判断 
    -a file        文件存在为真
    -z file        文件存在为真
    -r file     用户可读为真 
    -w file     用户可写为真 
    -x file     用户可执行为真 
    -f file     文件为普通文件为真 
    -d file     文件为目录为真 
    -s file     文件大小非0时为真 
    -h file        文件为符号文件为真
    -L file        文件为符号文件为真
    -g file        文件为SGID权限文件为真
    -u file        文件为SUID权限文件为真
    -k file        文件为T权限文件为真
    
    4)复杂逻辑判断 
    -a     与 
    -o    或 
    !     非
    
    三、注意细节
    ===========================================================================
    1)在if的中括号中,判断变量的值,加不加双引号的问题?
    -z 判断变量的值,是否为空:
            变量的值,为空,返回0,为true
            变量的值,非空,返回1,为false
    -n 判断变量的值,是否为空:
            变量的值,为空,返回1,为false
            变量的值,非空,返回0,为true
    str="abc"
     [ -z "$str" ]   单中括号,变量必须要加双引号!
     [[ -z $str ]]   双中括号,变量不用加双引号
    
     [ -n "$str" ]   单中括号,变量必须要加双引号!
     [[ -n $str ]]   双中括号,变量不用加双引号
    
    2)多个条件判断,[]  和 [[]] 的区别????????????????????
    && 并且,相当于and 
    || 或,相当于or  
    
    -a 并且,相当于and    
    -o 或者,相当于or 
    
    --------------------------------------------
    2.1)双中括号[[]]的条件判断
    [[  ]] 双中括号的条件判断用"&&" 和 "||"
    
    ||  满足一个条件满足就成立;或者的关系      
    [[ $a -lt 3 || $a -gt 6 ]]     
    [[ $a -lt 3 ]] || [[ $a -gt 6 ]]    # 写在外面也可以
       
    &&  必须同时满足两个条件同时;并且的关系。
    [[ $a -gt 3 && $a -lt 10 ]] 
    [[ $a -gt 3 ]] &&  [[$a -lt 10 ]]   # 写在外面也可以
    
    这里需要注意的问题的是:
    [[]]双中括号的判断语句中,只能使用&&和||,可以在[[]]内部使用,也可以在[[]]外面使用!
    [[]]双中括号的判断语句中不能使用-a和-o参数!!!!!!
    
    如果使用下面写法就是错误的!!!!!!
    [[ $a -lt 3 -o $a -gt 6 ]]  
    [[ $a -lt 3 ]] -o [[ $a -gt 6 ]]
    [[ $a -gt 3 -a $a -lt 10 ]] 
    [[ $a -gt 3 ]] -a  [[$a -lt 10 ]]
    
    --------------------------------------------
    2.2)单中括号[]的条件判断
    [ ] 单中括号的条件判断可以使用-a和-o的参数,但是必须在单[ ]中括号内判断条件!!不能在单中括号外面!!
    [ $a -lt 10  -o  $a -gt 20 ]      这个"或者"条件成立
    [ $a -lt 10 ] -o [ $a -gt 20 ]    这个"或者"不成立,因为必须在中括号内判断!!!!
    
    如果想在[]中括号外判断两个条件,必须用&& 和 || 比较!
    [ $a -lt 10 ] ||  [ $a -gt 20 ]  这个"或者"条件成立
    [ $a -lt 10 ] &&  [ $a -gt 20 ]  这个"并且"条件成立 
     
    同样需要注意:|| 和 && 不能在单中括号[]内使用,只能在单中括号[]外面使用!!!
    
    3) 当判断某个变量的值是否满足正则表达式的时候,必须使用[[  ]] 双中括号!!!!
    示例:
    [root@ss-server ~]# str=13611082178
    [root@ss-server ~]# [[ ${str} =~ [0-9]{11} ]]
    [root@ss-server ~]# echo $?
    0
    
    如果使用单中括号,会直接报错:
    [root@ss-server ~]# str=13611082178          
    [root@ss-server ~]# [ ${str} =~ [0-9]{11} ] 
    -bash: [: =~: binary operator expected

                                                                                                                                              

    shell脚本获取第10个参数
    
    在Shell脚本中,可以用$n的方式获取第n个参数
    [root@ansible-server ~]# cat a.sh
    #!/bin/bash
    echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}
    
    [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab
    a b c d 1 2 3 4 8 ab
    
    取第10个参数, 要用${10}, 不能使用$10(这个表示第1个参数加上0)。因为个位数的参数,可以直接使用数字。但两位以上数字的参数,必须使用{}符号!!!!
    #!/bin/bash
    echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10
    
    [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab
    a b c d 1 2 3 4 8 a0
    
    即上面脚本中$10 取的值为$1+0
    
    再看几个例子
    [root@ansible-server ~]# cat a.sh
    #!/bin/bash
    #echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10
    echo $3 $12
    
    [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab
    c a2
    
    [root@ansible-server ~]# cat a.sh    
    #!/bin/bash
    #echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10
    echo $3 ${12}
    
    [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab bo kevin
    c kevin

                                                                                                                                                 
    $#    是传递给脚本的参数个数;
    $0    是脚本本身的名字;
    $1    是传递给该shell脚本的第一个参数;
    $2    是传递给该shell脚本的第二个参数;
    $@   是传递给脚本的所有参数的列表(是多个字符串,每个参数为1个字符串);
    $*     是传递给脚本的所有参数的列表(以一个单字符串显示所有参数),与位置变量不同,参数可超过9个;
    $$    是运行脚本的当前进程ID号;
    $?    是显示执行上一条Shell命令的返回值,0表示没有错误,其他表示有错误。

    如下,用一个简单的脚本来说明上面这些变量的含义
    [root@kevin ~]# vim /root/path.sh
    #!/bin/sh
    echo "the number of parameters passed to the script: $#"
    echo "the name of the script itself: $0"
    echo "the first parameter passed to the shell script: $1"
    echo "the second parameter passed to the shell script: $2"
    echo "the list of all the parameters passed to the script(some string): $@"
    echo "the list of all the parameters passed to the script(one string): $*"
    echo "the current process ID number of the script which is running: $$"
    echo "the return value of the last shell command performed: $?"
    
    [root@kevin ~]# chmod 755 /root/path.sh
    [root@kevin ~]# ll /root/path.sh
    -rwxr-xr-x. 1 root root 512 Jun 25 11:21 /root/path.sh
    
    [root@kevin ~]# sh /root/path.sh 10 20 30
    the number of parameters passed to the script: 3
    the name of the script itself: /root/path.sh
    the first parameter passed to the shell script: 10
    the second parameter passed to the shell script: 20
    the list of all the parameters passed to the script(some string): 10 20 30
    the list of all the parameters passed to the script(one string): 10 20 30
    the current process ID number of the script which is running: 372
    the return value of the last shell command performed: 0

                                                                                                                                                 
    Shell脚本常用命令 -exit 和 if

    1、exit
    exit 0   退出shell,成功
    exit 1   退出shell,失败
    exit 2   退出shell,用法不当 
    
    需要注意:
    如果shell脚本中调用的子脚本的exit,那么会退出子脚本
    如果是source一个子脚本,里面的exit会导致外面的脚本也退出
    
    ==============================================================
    2、if
    1) if [-z "$name"]   
    判断name是否为空字符串,如果空,则为真,执行if的内容
    等同于  if ["$name" = ""]
    等同于[! "$name"]
    
    2) if的几个参数
    -z  字符串是否为空,空为真
    -n  指定字符串是否不空,不空为真
    -a  某东西不存在,则为真。不限定为字符串
    -f  普通文件是否存在
    -d  目录是否存在
    -e  某东西是否存在,不限定为文件

                                                                                                                                                 
    Shell脚本中判断参数是否为空,如果为空就停止后续操作

    注意下面的方法
    if [ str1 = str2 ]  当两个串有相同内容、长度时为真 
    if [ str1 != str2 ] 当串str1和str2不等时为真 
    if [ -n str1 ]    当串的长度大于0时为真(串非空) 。 注意: 这个等同于if [ ! -n str1 ] ,前提是里面的str1不加上"",如果加上""就等同于if [ -z str1 ]了!
    if [ -z str1 ]    当串的长度为0时为真(空串) 。  注意:这个等同于 if [ ! -n "str1" ],前提是str1必须要加上""双引号!!
    
    ==================================================================
    [root@bz3aomsmsap1002 mnt]# cat test.sh
    #!/bin/bash
    AN=""
    BN="sadf"
    if [ -z ${AN} ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh
    没有变量AN,无法执行后续操作,请确认输入了AN参数
    
    -----------------------------------------
    [root@bz3aomsmsap1002 mnt]# cat test.sh  
    #!/bin/bash
    AN="ha"
    BN="sadf"
    if [ -z ${AN} ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh  
    结果为:ha is a good sadf
    
    ==================================================================
    如果要想使用-n代替-z,则做法如下:
    必须注意:
    下面的if判断语句中的-n后面的变量必须要加上双引号""!否则就失效!
    因为如果不加""的话,就等同于了效于if [ -n ]
    [root@bz3aomsmsap1002 mnt]# cat test.sh 
    #!/bin/bash
    AN=""
    BN="sadf"
    if [ ! -n "${AN}" ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh  
    没有变量AN,无法执行后续操作,请确认输入了AN参数
    
    -----------------------------------------
    [root@bz3aomsmsap1002 mnt]# cat test.sh
    #!/bin/bash
    AN="ru"
    BN="sadf"
    if [ ! -n "${AN}" ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh
    结果为:ru is a good sadf
    
    -----------------------------------------
    如果不加双引号,则if [ ! -n ] 就等同于了 -f [ -n ]
    
    [root@bz3aomsmsap1002 mnt]# cat test.sh
    #!/bin/bash
    AN=""
    BN="sadf"
    if [ ! -n ${AN} ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh 
    结果为: is a good sadf
    
    -----------------------------------------
    [root@bz3aomsmsap1002 mnt]# cat test.sh
    #!/bin/bash
    AN="ru"
    BN="sadf"
    if [ ! -n ${AN} ];then
       echo "没有变量AN,无法执行后续操作,请确认输入了AN参数"
       exit 1
    fi
    
    echo "结果为:${AN} is a good ${BN}"
    
    [root@bz3aomsmsap1002 mnt]# sh test.sh
    结果为:ru is a good sadf

                                                                                                                                               
    $(( ))、$( )、${ }的区别

    ===================================================================
    一、$( ) 与 ` ` (反引号)
    在bash shell中,$( ) 与 ` `(反引号) 都是用来做命令替换用(command substitution)的。
    [root@bobo tmp]# echo `hostname`
    kevin-testserver
    [root@bobo tmp]# echo $(hostname)
    kevin-testserver
    
    比如查看上一星期天的日期
    [root@bobo tmp]# echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)[/code]
    the last sunday is 2019-10-27[/code]
    
    ===================================================================
    二、${ } 用来作变量替换。
    一般情况下,$var 与 ${var} 并没有什么不一样。但是用${ }会比较精确的界定变量名称的范围。
    例如下面的例子,原本是打算先将$A的结果替换出来,然后再补一个B字母于其后。
    如果使用$AB打印结果就为空,但是使用${A}B打印就不一样了。
    [root@bobo tmp]# A=B
    [root@bobo tmp]# echo $AB
    
    [root@bobo tmp]# echo ${A}B
    BB
    [root@bobo tmp]# 
    
    
    在bash中。${ }功能是十分强大的,不仅仅是用来界定变量名称,
    --------------------------------------
    1)${}可以灵活地用来截图变量中的字符串
    具体可以参考:https://www.cnblogs.com/kevingrace/p/8868262.html
    
    例如:var="http://www.kevin.com/shibo/anhuigrace"
    我们可以用 ${ } 分别替换获得不同的值:
    ${var#*/}:拿掉第一条/及其左边的字符串:/www.kevin.com/shibo/anhuigrace
    ${var##*/}:拿掉最后一条/及其左边的字符串:anhuigrace
    ${var#*.}:拿掉第一个.及其左边的字符串:kevin.com/shibo/anhuigrace
    ${var##*.}:拿掉最后一个.及其左边的字符串:com/shibo/anhuigrace
    ${var%/*}:拿掉最后一条/及其右边的字符串:http://www.kevin.com/shibo
    ${var%%/*}:拿掉第一条/及其右边的字符串:http:
    ${var%.*}:拿掉最后一个.及其右边的字符串:http://www.kevin
    ${var%%.*}:拿掉第一个.及其右边的字符串:http://www
    
    记忆的方法为:
    # 是去掉左边(在键盘上 # 在 $ 之左边)
    % 是去掉右边(在键盘上 % 在 $ 之右边)
    单一符号是最小匹配﹔
    两个符号是最大匹配。
    
    --------------------------------------
    2)${}可以对变量值里的字符串作替换
    ${file/dir/path}:将第一个 dir提换为path:
    ${file//dir/path}:将全部dir提换为path:
    
    示例:
    [root@bobo tmp]# cat test.sh
    #!/bin/bash
    
    var="/data/web/kevin/www/web/ui/web/list"
    
    echo "${var}"
    echo "${var/web/shi}"
    echo "${var//web/shi}"
    [root@bobo tmp]# sh test.sh
    /data/web/kevin/www/web/ui/web/list
    /data/shi/kevin/www/web/ui/web/list
    /data/shi/kevin/www/shi/ui/shi/list
    
    --------------------------------------
    3) 利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值)
    ${var-kevin.txt}:假如$var没有设定,则使用kevin.txt作传回值。(空值及非空值时不作处理)
    ${var:-kevin.txt}:假如$var没有设定或为空值,则使用kevin.txt作传回值。(非空值时不作处理)
    ${var+kevin.txt}:假如$var设为空值或非空值,均使用kevin.txt作传回值。(没设定时不作处理)
    ${var:+kevin.txt}:若$var为非空值,则使用kevin.txt作传回值。(没设定及空值时不作处理)
    ${var=kevin.txt}:若$var没设定,则使用kevin.txt作传回值,同时将$var赋值为kevin.txt。(空值及非空值时不作处理)
    ${var:=kevin.txt}:若$var没设定或为空值,则使用kevin.txt作传回值,同时将$var赋值为kevin.txt。(非空值时不作处理)
    ${var?kevin.txt}:若$var没设定,则将kevin.txt输出至STDERR。(空值及非空值时不作处理)
    ${var:?kevin.txt}:若$var没设定或为空值,则将kevin.txt输出至STDERR。(非空值时不作处理)
    
    示例:
    [root@bobo tmp]# cat test.sh
    #!/bin/bash
    
    #var="/data/web/kevin/www/web/ui/web/list"
    
    echo "${var}"
    echo "${var-my.txt}"
    echo "${var:-my.txt}"
    echo "${var+my.txt}"
    echo "${var:+my.txt}"
    echo "${var=my.txt}"
    echo "${var:=my.txt}"
    echo "${var?my.txt}"
    echo "${var:?my.txt}"
    
    [root@bobo tmp]# sh test.sh
    
    my.txt
    my.txt
    
    
    my.txt
    my.txt
    my.txt
    my.txt
    
    
    修改下脚本
    [root@bobo tmp]# cat test.sh
    #!/bin/bash
    
    var="/data/web/kevin/www/web/ui/web/list"
    
    echo "${var}"
    echo "${var-my.txt}"
    echo "${var:-my.txt}"
    echo "${var+my.txt}"
    echo "${var:+my.txt}"
    echo "${var=my.txt}"
    echo "${var:=my.txt}"
    echo "${var?my.txt}"
    echo "${var:?my.txt}"
    
    [root@bobo tmp]# sh test.sh 
    /data/web/kevin/www/web/ui/web/list
    /data/web/kevin/www/web/ui/web/list
    /data/web/kevin/www/web/ui/web/list
    my.txt
    my.txt
    /data/web/kevin/www/web/ui/web/list
    /data/web/kevin/www/web/ui/web/list
    /data/web/kevin/www/web/ui/web/list
    /data/web/kevin/www/web/ui/web/list
    
    需要注意的是:
    以上理解一定要分清楚unset 与 null 及 non-null 这三种赋值状态。一般而言:
    : 与 null 有关;
    若不带 : 的话, 则 null 不受影响,;
    若带 : 的话,则连 null 也受影响.
    
    --------------------------------------
    4)${#var} 可计算出变量值的长度
    [root@bobo tmp]# cat test.sh
    #!/bin/bash
    
    var="/data/web/kevin/www/web/ui/web/list"
    
    echo "${#var}"
    
    [root@bobo tmp]# sh test.sh
    35
    
    这里就引申出shell中的数组的概念了,数组的使用可以参考:https://www.cnblogs.com/kevingrace/p/5761975.html
    
    这里简单说明下:
    一般而言,var="haha hehe heihei houhou" 这样的变量只是将${var}替换为一个单一的字符串,
    [root@bobo tmp]# var="haha hehe heihei houhou"
    You have mail in /var/spool/mail/root
    [root@bobo tmp]# echo ${var}
    haha hehe heihei houhou
    
    如果改为 var=(haha hehe heihei houhou) ,则是将${var}定义为组数。
    [root@bobo tmp]# var=(haha hehe heihei houhou)
    
    bash 的组数替换方法可参考如下方法:
    ${var[@]} 或 ${var[*]} 可得到 haha hehe heihei houhou (全部组数)
    ${var[0]} 可得到 haha (第一个组数),${var[1]} 则为第二个组数…
    ${#var[@]} 或 ${#var[*]} 可得到 4 (全部组数数量)
    ${#var[0]} 可得到4(即第一个组数(haha)的长度),${#var[3]} 可得到6(第四个组数(houhou)的长度)
    var[3]=xyz 则是将第四个组数重新定义为xyz …
    
    [root@bobo tmp]# echo ${var[@]}
    haha hehe heihei houhou
    [root@bobo tmp]# echo ${var[*]}
    haha hehe heihei houhou
    [root@bobo tmp]# echo ${var[0]}
    haha
    [root@bobo tmp]# echo ${var[1]}
    hehe
    [root@bobo tmp]# echo ${#var[@]}
    4
    [root@bobo tmp]# echo ${#var[*]}
    4
    [root@bobo tmp]# echo ${#var[0]}
    4
    [root@bobo tmp]# echo ${#var[3]}
    6
    [root@bobo tmp]# var[3]=xyz
    [root@bobo tmp]# echo ${var[@]} 
    haha hehe heihei xyz
    
    ===================================================================
    三、 $(( )) 的用途:
    1)$(( ))是用来作整数运算的。
    + - * / :分别为 "加、减、乘、除"。
    % :余数运算
    & | ^ !:分别为 "AND、OR、XOR、NOT" 运算。
    
    [root@bobo tmp]# a=5; b=7; c=2
    [root@bobo tmp]# echo $(( a+b*c ))
    19
    [root@bobo tmp]# echo $(( (a+b)/c ))
    6
    [root@bobo tmp]# echo $(( (a*b)%c))
    1
    
    在 $(( )) 中的变量名称,可于其前面加 $ 符号来替换,也可以不用,如:
    [root@bobo tmp]# echo $(( $a + $b * $c)) 
    19
    [root@bobo tmp]# echo $(( ($a * $b) % $c))    
    1

                                                                                                                                                 
    Shell 脚本中诸如查看目录大小并排序等技巧

    =====================================================================
    查看目录下的文件大小并排序
    
    1. 查看/data目录下空间大小排在前10位的文件
    # du -sh /data/* | sort -nr | head -10
    
    查看目录下所有文件的大小并按照大小排序
    # du -sh * | sort -rh
    
    2. 查看/data目录下空间大小排在前10位的目录(单位为G),并且只是在/data当前目录下查看,不轮询(用到参数"-maxdepth 1")
    # find /data/* -maxdepth 1 -type d -exec /usr/bin/du -sh {} ;|grep '[0-9]G'|sort -rh|head -5
    
    [bxapp@bz6aomdepap1001 ~]$ find /data/ftp/ONLINE/* -maxdepth 1 -type d -exec /usr/bin/du -sh {} ;|grep '[0-9]G'|sort -rh|head -5
    64G /data/ftp/ONLINE/CCS
    13G /data/ftp/ONLINE/MPB
    11G /data/ftp/ONLINE/ICS
    9.5G /data/ftp/ONLINE/mysql
    9.0G /data/ftp/ONLINE/EOB
    
    =====================================================================
    Shell中求字符串中单词的个数的几种方法
    
    方法一:
    [root@VM_16_9_centos tmp]# echo 'wang shi kevin ruo bao' | wc -w
    5
    
    方法二:
    [root@VM_16_9_centos tmp]# echo 'wang shi kevin ruo bao' | awk '{print NF}'
    5
    
    方法三:
    [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' 
    [root@VM_16_9_centos tmp]# set ${s}
    [root@VM_16_9_centos tmp]# echo $#
    5
    
    方法四:
    [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' 
    [root@VM_16_9_centos tmp]# a=($s)
    [root@VM_16_9_centos tmp]# echo ${#a[@]}
    5
    
    方法五:
    [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' 
    [root@VM_16_9_centos tmp]# echo $s | tr ' ' '
    ' | wc -l
    5
    
    =====================================================================
    linux 中wc 用法小结
    wc命令用于统计给定文件中的字节数、字数、行数。
    如果没有给出文件名,则从标准输入读取。
    wc同时也给出所有指定文件的总统计数。字是由空格字符区分开的最大字符串。
    
    wc命令各选项含义如下:
    - c 统计字节数
    - l 统计行数
    - w 统计字数
    
    1. 统计行数:
    # wc -l file
    
    2. 如果需要将stdin作为输入,使用下列命令:
    #cat file | wc -l
    
    3. 统计单词数:
    # wc -w file
    # cat file | wc -w
    
    4. 统计字符数:
    # wc -c file
    # cat file | wc -c
    
    可以按照下面的方法统计文本中的字符数:
    -n用于避免echo添加额外的换行符。
    [root@VM_16_9_centos tmp]# echo "CCS"|wc -c   
    4
    [root@VM_16_9_centos tmp]# echo -n "CCS"|wc -c
    3
    4
    
    5. 当不使用任何选项执行wc时:
    # wc file
    1435 15763 112200
    它会分别打印出文件的行数、单词数和字符数。
    
    6. 使用-L选项打印出文件中最长一行的长度:
    # wc file -L
    205
    
    =====================================================================
    shell求两个数相除后的百分比
    
    [root@VM_16_9_centos tmp]# 
    [root@VM_16_9_centos tmp]# cat test.sh
    #!/bin/bash
    NUM1=78
    NUM2=345
     
    Percent_1=$(printf "%d%%" $((${NUM1}*100/${NUM2})))
    #或者
    
    #保留1位小数,四舍五入
    Percent_2=`awk 'BEGIN{printf "%.1f%%
    ",('${NUM1}'/'${NUM2}')*100}'`
    
    #保留3位小数,四舍五入
    Percent_3=`awk 'BEGIN{printf "%.3f%%
    ",('${NUM1}'/'${NUM2}')*100}'`
    
    echo $Percent_1
    echo $Percent_2
    echo $Percent_3
    [root@VM_16_9_centos tmp]# sh test.sh
    22%
    22.6%
    22.609%
  • 相关阅读:
    bzoj2161 布娃娃
    bzoj2161 布娃娃
    Tyvj1054
    Tyvj1054
    Tyvj1053
    Tyvj1053
    hdu3265 Poster(扫描线)
    hdu3265 Poster(扫描线)
    hdu3265(好题翻译)
    hdu3265(好题翻译)
  • 原文地址:https://www.cnblogs.com/kevingrace/p/5896386.html
Copyright © 2020-2023  润新知