设为首页 收藏本站
查看: 913|回复: 0

shell脚本编程总结

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-2-16 08:37:57 | 显示全部楼层 |阅读模式
shell脚本是什么?

(1)命令的堆积;        
(2)程序逻辑;   

如何写shell脚本:
脚本文件的第一行,顶格:给出shebang,解释其路径,用于指明解释执行当前脚本的解释器程序文件。
常见的解释器:

    #!/bin/bash

    #!/usr/bin/python   

    #!/usr/bin/perl

运行脚本:
    (1)赋予执行权限,并直接运行此程序文件;

    (2)直接运行解释器,将脚本以命令行参数传递给解释器程序:

        bash /PATH/TO/SCRIPT_FILE

    注:脚本中的空白行会被解释器忽略。

  • 脚本中,除了shebang,余下所有以#开头的行,都会被视作注释行而被忽略;此即为解释行。
  • shell脚本的运行是通过一个子shell进程实现的。



bash的算术运算及条件测试

(1)实现算术运算
let var=算术表达式
var=$[算术表达式]
var=$((算术表达式))
var=$(expr arg1 arg2 arg3)
例:mul=$(expr $num1 \* $num2)
注:称号在某些场景中需要转义
(2)增强型赋值符号
     +=, -=, *=, /=, %=
     let varOPERvalue
    例如:let count+=1
自增,自减:
    let var+=1
    let var++
    let var-=1
    let var--
(3)条件测试:
  判断某需求是否满足,需要由测试机制来实现;
如何编写测试表达式以实现所需的测试:
    (1)执行命令;并利用命令状态返回值来判断。

        0:成功  1-255:失败

    (2)测试表达式:[ EXPRESSION ]
            [[ EXPRESSION ]]

        注:EXPRESSION前后必须有空白字符;

        ①数值测试:
            -eq:是否等于;

            -ne:是否不等于;

            -gt:是否大于;

            -lt:是否小于;

            -le:是否小于等于;

        ②字符串测试:

             ==:是否等于;
            >:是否大于;
            <:是否小于;
            !=:是否不等于;
            =~:左侧字符串是否能够被右侧的PATTERN所匹配;
                注:此表达式一般用于[[ ]]中;
            -z "STRING":测试字符串是否为空,空则为真,不空则为假;
            -n "STRING":测试字符串是否不空,不空则为真,空则为假;
                     注:用于字符串比较时用到的操作数东应该使用引号;
           ③自定义退出状态码:
            exit [n]:自定义推出状态码;

      注:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字;如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码;


        ④文件测试:

           存在性测试:

            -a FILE

            -e FILE:文件存在性测试,存在为真,否则为假;

           存在性及类别测试:

            -b FILE:是否存在且为块设备文件;
            -c FILE:是否存在且为字符设备文件;

            -d FILE:是否存在且为目录文件;

            -f FILE:是否存在且为普通文件;

            -h FILE 或 -L FILE:存在且为符号链接文件;

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

            -S FILE:是否存在且为套接字文件;

           文件权限测试:

            -r FILE:是否存在且为可读;

            -w FILE:是否存在且为可写;

            -x FILE:是否存在且为可执行

           文件特殊权限测试:

            -g FILE:测试是否存在且拥有sgid权限;
            -u FILE:是否存在且拥有suid权限;
            -k FILE:是否存在且拥有sticky权限;
           文件大小测试:
            -s FILE:是否存在且非空
           文件是否打开:
            -t fd:fd表示文件描述符是否已经打开且与某终端相关
            -N FILE:文件上一次读取之后是否被修改过

                -O FILE: 当前有效用户是否为文件属主
                -G FILE: 当前有效用户是否为文件属组
              双目测试:
            FILE1 -ef FILE2:两个文件是否指向同一个设备上相同的inode
            FILE1 -nt FILE2:FILE1是否新于FILE2
            FILE1 -ot FILE2:FILE1是否旧于FILE2
         组合测试条件:
            逻辑运算
                第一种方式
                    COMMAND1 && COMMAND2
                    COMMAND1 || COMMAND2
                    !COMMAND
                第二种方式
                    EXPRESSION1 -a EXPRESSION2
                    EXPRESSION1 -o EXPRESSION2
                    !EXPRESSION
(4)shell脚本变量:  
   1)变量赋值:name='value'
  其中的value可以为
a.可以使直接字串:name="username"
b.变量引用:name="$username"
c.命令引用:name=`COMMAND`(单反引号)
   name=$(COMMAND)
   2)变量引用:${name},$name
" ": 弱引用,其中的变量引用会被替代为变量值
' ': 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
   3)位置变量
在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,...:对应调用第1,第2等参数
     $#:它可抓出positional parameter的数量,即在脚本后面的参数有几个
$0:脚本本身的名字
$@:传给脚本的所有参数
$*:是以一个单字符串显示里所有向脚本传递的参数,与位置参数不同,参数可超过9个
$$:是脚本运行的当前进程的ID号
$?:显示最后命令的退出状态

bash脚本编程:
(1)用户交互
    read [option]... [name]...

      -p 'PROMPT'

      -t TIMEOUT

   bash -n /PATH/TO/SOME_SCRIPT
    检查脚本中有无语法错误;

   bash -x /PATH/TO/SOME_SCRIPT

    分步执行脚本内容;

(2)脚本编程结构:
    ①条件测试

      运行命令或[[ EXPRESSION ]]

        执行状态返回值

      if

      case

    ②循环执行

      将某代码段重复运行多次

     必须有进入条件和退出条件

       for ,while, until

      ③函数:结构化编程及代码复用

       function

(3)if语句
    单分支:

      if CONDITION; then

        ...

      fi
    双分支:

      if CONDITION; then

        ...

      else
        ...

      fi

    多分支:

      if CONDITION1;then

        ...

      elif CONDITION2; then
        ...

      elif CONDITION3; then

        ...

      ....

      else

        ...

      fi

       逐条件进行判断,第一次判断为“真”时,执行其分支,而后结束;

    if语句可嵌套;

示例1:提示用户键入文件路径,用脚本判断文件类型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

#judge type about a file what user give

read -p "Please Enter a filename:" filename

if [ -z "$filename" ]; then
        echo "Usage: Enter a file path"
        exit 2
fi

if [ ! -e $filename ]; then
        echo "Usage: No such file, check it and enter again"
        exit 3
fi

if [ -f $filename ]; then
        echo "It's a common file"
elif [ -d $filename ]; then
        echo "It's a directory"
elif [ -L $filename ]; then
        echo "It's a symbolic file"
else
        echo "Other type"
fi

[iyunv@localhost ~]# bash file.sh
Please Enter a filename:file.sh
It's a common file



示例2:传递给脚本文件名,判断两个文件的行数多少:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
#compare two files lines

if ! [ -e $1 ] || ! [ -e $2 ]; then
        echo "Please enter a exist filename"
        exit 2
fi


A=` wc $1  &> /dev/null `
B=` wc $2  &> /dev/null `

if [ $A -gt $B ]; then
  echo "$1 has more lines"
else
  echo "$2 has more lines"
fi

[iyunv@localhost ~]# bash first.sh /etc/fstab /etc/passwd
/etc/fstab has more lines




(4)for循环语句:
    ①for VARAIBLE in LIST; do
        循环体
     done
       进入条件:只要列表有元素,即可进入循环;
       退出条件:列表中的元素遍历完成;
    ②列表生成方式:
      直接给出
      整数列表
        {start..end}
          ${seq [start [incremtal]] last}
      返回列表的命令

         $(COMMAND)

      glob

        /etc/rc.d/rc1.d/k*(遍历该路径下的以k开头的所有文件)

      变量引用

         $@,$*

示例1:添加10个用户,user1-user10;密码同用户名;
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# add 10 user, username:user1~user10,password:user1~user10;


for i in {1..10}; do
     if id user$i &> /dev/null; then
        echo "user$i is exist"
     else
        useradd user$i && echo "user$i" | passwd --stdin user$i &> /dev/null
        echo " add user$i is successed"
     fi
done



示例2:判断某路径下所有文件的类型  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
#judge type of file in some  path

for file in $(ls /etc); do
     if [ -f /etc/$file ]; then
        echo "$file is common file"
     elif [ -d /etc/$file ]; then
        echo "$file is directory file"
     elif [ -L /etc/$file ]; then
        echo "$file is symbolic file"
     else
        echo "$file is oth type"
     fi
done



示例3:打印九九乘法表:

1
2
3
4
5
6
7
8
9
#!/bin/bash
#9X9 multiplication

for i in {1..9}; do
        for j in $(seq 1 $i); do
         echo -e -n "${i}x${j}=$[$i*$j]\t"
         done
         echo
done



(4)for循环的特殊用法:
    for ((控制变量初始化;条件判断表达式;控制变量的修正表达式));do
        循环体
    done  

   控制变量初始化:尽在运行到循环代码段时执行一次
   控制变量的修正表达式:每轮循环结束后会先对控制变量进行修正运算

示例:九九乘法表
1
2
3
4
5
6
for ((i=1; i<=9; i++)); do
         for ((j=1; j<=$i; j++)); do
         echo -e -n "${i}x${j}=$[$i*$j]\t"
         done
         echo
done




(5)while循环:
    ①while CONDITION; do

      循环体

     done

     CONDITION:循环控制条件,进入循环前,先做一次判断;每一次循环之后会再次做判断,条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环;


示例:求100以内的偶数和以及奇数和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
#even number sum and odd number sum

declare -i i=0
declare -i evensum=0
declare -i oddsum=0
while [ $i -le 100 ]; do
        if [ $[$i%2] -eq 0 ]; then
         evensum=$[$evensum+$i]
        else
         oddsum=$[$oddsum+$i]
        fi
let i++
done
echo "even number sum is $evensum"
echo "odd number sum is $oddsum"

[iyunv@localhost ~]# bash  sum.sh
even number sum is 2550
odd number sum is 2500



    ②while循环的特殊用法(遍历文件中的每一行)

        while read line; do

           循环体

       done < /PATH/FROM/SOMEFILE

     依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line;

示例:找出其ID号为偶数的所有用户,显示其用户名及ID号;
1
2
3
4
5
6
7
8
9
#!/bin/bash
#ouput even number id

while read line; do
        if [ $[`echo $line | cut -d: -f3` % 2] -eq 0 ]; then
          echo -e -n "username: `echo $line | cut -d: -f1`\t"
          echo "uid: `echo $line | cut -d: -f3`"
        fi
done < /etc/passwd



(6)until循环

    until CONDITION; do

       循环体

    done

   进入条件:false

   退出条件:true

(7)循环控制语句(用于循环体中)
   1)continue [N]
    提前结束由内而外的第N层的本轮循环,并且直接进入下一轮循环判断

       while CONDITION1; do

         ...

        if CONDITION2; then

           continue

        fi

        ...

       done

   2)break [N]:提前结束循环
示例:只求100内的偶数和
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
#output even numner sum

declare -i i=0
declare -i sum=0
until [ $i -gt 100 ]; do
        let i++
        if [ $[$i%2] -eq 1 ]; then
           continue
        fi
        let sum+=$i
done
echo "even number sum is $sum"




(8)条件判断:case语句
    case 变量引用 in

    PAT1)

      分支1

      ; ;

    PAT2)
      分支2
      ; ;
     PAT3)
      分支3
      ; ;
      ...
    *)
      默认分支
      ; ;

    esac
case支持glob风格的通配符

   *:任意长度任意字符

   ?:任意单个字符

   []:指定范围内的单个字符

   a|b:a或b
示例:提示用户键入字符,并判断类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
#input a key,judge type

read -p "Please enter a key:" key

case $key in
[[:lower:]] )
echo "Lowercase letter"
;;
[[:upper:]] )
echo "Uppercase letter"
;;
[0-9] )
echo "Digit"
;;
*)
echo "others"
esac

[iyunv@localhost ~]# bash case.sh
Please enter a key:a
Lowercase letter



(9)函数:function

    对于过程式编程,可以实习代码重写

     模块化编程

     结构化编程

把一段独立功能的代码当做一个整体,并为之起个名字;命名的代码段,纪委函数。
注:定义函数的代码段不会自动执行,在调用时执行;所谓调用函数,在代码中给定函数名即可;函数名出现的任何位置,在代码执行时,都会被自动被替换为函数代码。
  1)语法一
    function f_name{

      函数体

    }

    语法二

    f_name{

      函数体

    }

  2)调用:函数只有被调用才会执行

    调用方法:给定函数名即可

           函数名出现的地方,会被自动替换为函数代码

    函数生命周期:被调用时创建
  3)函数返回值

    函数执行结果返回值

        使用echo或print命令进行输出

        函数体中调用命令的执行结果

    函数的退出状态码

        默认取决于函数体中执行的最后一条命令的退出状态码

        自定义退出状态码:return

  4)函数可以接受参数

    传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可

    在函数体中,可使用$1,$2...调用这些参数,还可以使用$@,$*,$#等特殊变量

  5)函数递归:

    函数直接或间接调用自身

示例:简单使用函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
#show function

print(){
echo "your choice is $1"
}
read -p "Please enter one、two、three or four:"  num
case $num in
one)
   print 1
;;
two)
   print 2
;;
three)
   print 3
;;
four)
   print 4
;;
esac
[iyunv@localhost ~]# bash function.sh
Please enter one、two、three or four:one
your choice is 1
[iyunv@localhost ~]# bash function.sh
Please enter one、two、three or four:two
your choice is 2



(10)数组
基本概念:

    变量:存储单个元素的内存空间

    数组:存储多个元素的连续的内存空间

       数组名

       索引:编号从0开始,是数值索引

    引用数组中的元素:${ARRAY_NAME[INDEX]}

1)声明数组

     declare -a ARRAY_NAME

     declare -A ARRAY_NAME 关联数组
   注:索引也可支持使用自定义的格式,而不仅仅是数值格式
    bash数组支持稀疏格式
2)数组元素的赋值
    ①一次只赋值一个元素
       ARRAY_NAME[INDEX]=VALUE
         例: weekday[0]="Sunday"
            weekday[0]="Thursday"
    ②一次赋值全部元素
      ARRAY_NAME=("VAL1" "VAL2" "VAL3"...)
    ③只赋值特定元素
      ARRAY_NAME=([0]="VAL1" [3]="VAL2")
    ④read -a ARRAY
3)引用数组元素
    ${ARRAY_NAME [INDEX]}

     注:引用时,只给数组名,表示引用下标为0的元素;

    ${ARRAY_NAME
  • }:引用数组中的所有元素;

        ${ARRAY_NAME[@]}

    4)数组的长度:(数组中元素的个数)

        ${#ARRAY_NAME
  • },${#ARRAY_NAME[@]}


    引用数组中的元素
        数组切片;${ARRAY[@]:offset:number}

            offset:要跳过的元素的个数

            number:要去除的元素个数,取偏移量之后的所有元素
            ${ARRAY[@]:offset}
    向数组中追加元素
        ARRAY[${#ARRAY
  • }]

    删除数组中的某元素
        unset ARRAY[INDEX]

    关联数组
        declare -A ARRAY_NAME

        ARRAY_NAME=([index_name1]='val1'[index_name]='val2'...)


    示例:使用数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/bash
    #

    declare -a arry
    arry=(tom jery joe)
    for ((i=0; i<=${#arry[@]}; i++)) do
    echo  "${arry[$i]}"
    done
    echo "array length: ${#arry[@]}"
    [iyunv@localhost ~]# bash array.sh
    tom
    jery
    joe

    array length: 3




    示例:生成10个随机数并从小到大排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/bin/bash
    #
    declare -a num
    for i in {0..9}; do
            num[$i]=$RANDOM

    done
    echo ${num
  • }
    for((i=0;i<=9;i++)); do
            for((j=$[${i}+1];j<10;j++)); do
                    if [ ${num[$i]} -gt ${num[$j]} ]; then
                    a=${num[$i]}
                    num[$i]=${num[$j]}
                    num[$j]=$a
                    fi
            done
    done
    echo ${num
  • }

    [iyunv@localhost ~]# bash paixu.sh
    6670 15462 25364 28280 14556 4667 24577 7020 22897 5217
    4667 5217 6670 7020 14556 15462 22897 24577 25364 28280







  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-178539-1-1.html 上篇帖子: shell实现一个简单的计算器功能小脚本 下篇帖子: bash脚本并行执行scp下载任务
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表