shell脚本基础

        所谓的shell脚本,就是一大串命令集合成一个文本运行,也就是说,我们可以将平时在交互模式下写的命令,编写成文件内容让其执行,当然,shell脚本也不单单只是将命令集合起来,脚本里面融入了像,循环,遍历,判断分支等强大的功能,

    shell脚本的创建:

                以.sh结尾的文件,如:newfile.sh ,

                书写要求是第一行要写上解释这个shell脚本的解释器,通常的shell脚本的解释器都是bash,也就是这样,#!/bin/bash ,第一行除了写解释器路径,不能写其他的,然后第二行就为脚本的内容了,比如

                vim file.sh #编辑器打开文件(如果没有就创建)

                        #!/bin/bash        # 脚本第一行

                        #                            # 出第一行外的其他任意行,由#开头的行为注释行,

                        cat /etc/passwd     # 查看/etc/passwd 内容

                        echo "hello world " # 输出 hello world

                这就是一个简单的shell脚本,将在命令行执行的命令,写入文本文件中,

    shell脚本的执行:

            创建好了简单的shell脚本如何执行?有两种:

                    1,chmod +x  file.sh # 给脚本加上一个执行权限就能直接执行了,命令行直接执行  ./file.sh 因为我们脚本的第一行指定了脚本的解释器,所以只要脚本有执行权限,就能直接执行了,

                    2,bash file.sh 通过bash命令来执行file.sh脚本,bash执行脚本有选项,

                                -n 检查脚本语法是否有错,

                                -x 显示执行步骤,

      bash的流程控制语句: for if while until 都可以嵌套,

            循环

            for循环,语句格式

                    for VAR in 循环数列表(循环条件) do;# VAR是方便循环体调用的变量,

                            循环值

                    done

                    如 for i in {1..10};do #{1..10} 表示数字1-10就是循环的第二种方法,

                            sun= $[ $sun+$i ]

                        done

                        echo $sum

                    最后输出的$sum的结果为1+2+3..+10的和,        

            while循环:

                    while CONDITION; do

                    循环体

                    循环控制变量的修正表达式

                    done

                当CONDITION为“真”进入循环,直到“假”退出循环;

                比如:计算100以内数值之和;

            

until循环:

until CONDITION; do

循环体

循环控制变量修正表达式

done

当CONDITION为“假”时进入循环;为“真”退出循环;

计算100以内所有数之和;

            条件判断

                    if / then

            条件测试:(中括号和表达式之间要有空格)

                [ EXPRESSION ]

                ` EXPRESSION `

            整数测试:A, B

                A -gt B: 大于

                A -ge B: 大于等于

                A -eq B: 等于

                A -lt B: 小于

                A -le B: 小于等于

                A -ne B: 不等于

            字符串测试:A, B

                A > B

                A < B

                A >= B

                A <= B

                A == B或A = B:等值比较

                A != B: 不等于

                -z A: 判断A是否为空;空则为真,不空则假;

                -n A:判断A是否不空;不空则为值,空则为假;

                        字符串比较 符号两边要有空格, 

                        if的语句格式:

                        if [ 条件 ];then

                            循环体

                        fi

                          比如,测试172.16.100.*这个网段所有的ip联通率,

                        

                    if结构的分支可以有很多,

                        if [ 条件 ];then

                            循环体

                          else

                               循环体

                            else

                                循环体

                              ...

                        fi

                case 就是简要版本的if多分支另一种形式,

        语法格式:

        case 变量引用  in 

        PATTERN1)

    分支1

    ;;

        PATTERN2)

    分支2

    ;;

            ...

        *)

    分支n

    ;;

        esac

                            

扩展:

            if循环里面的判断,条件测试;

字符串测试:=~

"$A" =~ PATTERN

如果变量A中保存的字符串能被PATTERN所匹配;即为真;否则为假;

文件测试:$file

-e $file: 是否存在;存在则为真;

-a $file: 同上;弃用;

-f $file: 文件是否存在,且为普通文件;

-d $file: 是否存在且为目录;

-h $file: 是否存在且为符号链接文件;

-L $file:同上

-b $file: 是否存在且为块设备文件;

-c $file: 是否存在且为字符设备文件;

-S $file: 是否存在且为套接字文件:

-p $file: 是否存在且为管道文件;

-r $file: 当前用户对此文件是否拥有读权限;

-w $file:                         写

-x $file:                         执行权限;

-u $file: 文件是否拥有suid权限;

-g $file:文件是否拥有sgid权限;

-k $file: 文件是否拥有sticky权限;

-O $file: 当前用户是否为文件的属主;

-G $file: 当前用户是否属于文件的属组;

-N $file: 文件自从上一次被读取之后,是否被修改过;

$f1 -nt $f2: 文件f1是否比文件f2新;

$f1 -ot $f2: 文件f1是否比文件f2旧;

$f1 -ef $f2: f1和f2是否为同一个文件的硬链接;

通过这些条件测试可以得知这文件是否存在?是否有内容?这目录是否存在,否则就创建, 组合测试条件:短路操作符

与:COMMAND1 && COMMAND2

COMMAND1的退出状态如果为假,则COMMAND2不用运行,即可有最终结果;

或:COMMAND1 || COMMAND2

COMMAND1的退出状态如果为真,则COMMAND2不用运行,即可有最终结果;

非:! COMMAND

                # 如果根目录下存在目录tmd 就不创建,如果没有,就创建tmd

                [ -d /tmd ] || mkdir /tmd

            函数

                        函数就是将一段重复调用的代码合并到一起,通过调用函数来调用代码的执行,

                        函数的格式:

                            function   f_name() {

                                    重复调用的代码

                            }

                            f_name()  #通过函数名来调用函数,

递归函数之阶乘函数:

fact() {

if [ $1 -eq 0 -o $1 -eq 1 ]; then

echo 1

else

  echo $[$1*$(fact $[$1-1])]

fi

}

                       #以后要用这个函数就调用fact执行他,

                唯一要注意的是函数名和变量名的命名要区分开,比如函数名叫f_NAME 变量名为v_NAME

                如果不分开命名 或许等一段时间后你自己都不知到fact是变量还是函数了。

           

            数组

                    是一种键值对集合,array[ 0=>张三,1=>李四 ] ,输出array[ 0 ] 结果就为张三,

                        像上面的 0 1 称为键也叫做下标,张三,李四为值,他们是一对对出现的,

                    常见的两种数组形式,

            数组调用:

                ${ARRAY[index]}

                    索引数组,

                                下标从0开始,0,1,2,,,,

                    关联数组,

                                自定义下标,array[ one=>张三,for=>李四 ] echo array[ for ]结果为李四,

                    数组赋值声明:

                        

    数组元素的赋值:

    (1) 一次只赋值一个元素

    ARRAY[index]=VALUE

    a[0]="hello"

    (2) 一次赋值全部元素

            ARRAY=("mon" "tue" "wed")

     (3) 指定索引进行赋值

            ARRAY=([0]="sun" [1]="mon" [5]="fri")

      (4) read -a ARRAY   

                        read 是交互式输入,

                            # 用户输出的值赋给变量choice,-t是表示最多等7秒,7秒后跳出,

                            read -p  -t 7 "Your  choice: " choice 

              常见的数组操作,

        从数组中挑选某元素:

        ${ARRAY[@]:offset:number}

        对于:week=(mon tue wed thu fri sat sun)

${week[@]:3:2}结果为:

切片:

offset: 偏移过去的元素的个数;

number: 取出的元素的个数;

${ARRAY[@]:offset}

取出指定偏移量之后的所有元素;

${ARRAY[@]}, ${ARRAY[*]}

取出所有元素;

        向数组中追加元素:非稀疏格式

        week, 

        week[${#week[@]}]

        从数组中删除元素:

        unset ARRAY[index]

常见的字符串处理操作:

字符串切片:${var:offset:lenth}

a="world", ${a:2:2}, rl

取字符串最后的几个字符:${var: -lenth}

注意:冒号之后有空格;

基于模式取子串:

${var#*word}:其中word可以是指定的任意字符;

                        自左而右,查找var变量所存储字符中,第一次出现的word,

                         删除字符开头直至第一次wrod出现处之间的所有字符;

# mypath='sysconfig/network-scripts/ifcfg-eth0'

# echo ${mypath#*/}

network-scripts/ifcfg-eth0

${var##*word}: 其中word可以是指定的任意字符;

                            自左而右,查找var变量所存储字符中,最后一次出现的word,

                            删除字符开头直至最后一次wrod出现处之间的所有字符;

# mypath='/sysconfig/network-scripts/ifcfg-eth0'

# echo ${mypath##*/}

ifcfg-eth0

${var%word*}: 自右而左,删除第一次word出现处的字符开始直到尾部的所有字符;

${var%%word*}自右而左,删除最后一次word出现处的字符开始直到尾部的所有字符;

例子:url=http://www.magedu.com:80

取端口:${url##*:}

取协议:${url%%:*}

    查找并替换:

${var/pattern/substi}:查找var所表示的字串中,

                        第一次被Pattern匹配到的字串,并以substi替换之;

${var//patten/substi}:查找var所表示的字串中,

                        所有被Pattern匹配到的字串,并以substi替换之;

${var/#pattern/substi}:以行首锚定的方式将pattern匹配至var所表示的字串上,

                        如果能匹配,则以substi替换之;

${var/%pattern/substi}:以行尾锚定的方式将pattern匹配至var所表示的字串上,

                        如果能匹配,则以substi替换之;

可使用?, *元字符;

查找并删除:

${var/pattern}:删除pattern匹配到的第一次出现;

${var//pattern}: 删除pattern匹配到的所有出现;

${var/#pattern}

${var/%pattern}

字符串大小写转换:

${var^^}:小写-->大写

${var,,}:大写-->小写