前言 
unix/linux操作系统下的shell,是一种,其目的是提供一个用户与计算机相互交互的命令接口,通过输入各种命令,达到操作的目的。 
与此同时,shell支持控制流程,进而可以组合出各种各样的应用实例。

  • shell脚本的格式 

    • 首行shebang机制: 
      bash脚本,首行添加#!/bin/bash [options] 
      csh脚本,首行添加#!/bin/csh [options] 
      ksh脚本,首行添加#!/bin/ksh [options] 
      ……

    • 描述脚本的注释部分: 
      包括Author, Version, Date, Description,……该部分是非必须项,目的是为了让使用脚本的人能够比较清晰地了解该脚本的背景以及功能 
      ……

    • 脚本的正文部分: 
      包含命令与声明,以面向过程的形式组合在一起

脚本示例如下:

#!/bin/bash     #首行的shebang,表示使用bash编写脚本
#Author: AAA  #标注作者(格式规范,非必须)
#Version: 1.0   #标注版本(格式规范,非必须)
#Date: 2017-04-14   #标注日期(格式规范,非必须)
#Description: XXXXX...      #脚本功能描述(格式规范,非必须)

echo "Hello World"      #脚本正文部分
  • 编写脚本的一些规范 
    1. 脚本的第一行shebang注明调用的语言 
    2. 注释上一些信息,诸如: 文件名,功能描述,作者,版本…… 
    3. 变量名和函数名建议使用同一种命名法则 
    4. 有尽量多的注释说明程序的功能,单行注释写在代码行上部或者尾部 
    5. 代码做的修改要加必要的版本注释和功能说明 
    6. 脚本的控制流程里面建议要有缩进,使用一定数量的空格或者Tab 
    7. 文件名按照使用的语言,以.sh,.pl,.py等形式为后缀 

  • 常用的符号

符号 描述
在单引号中所有特殊符号均无特殊含义
“” 在双引号中,除“$”“\”外其他特殊符号都无特殊含义
$() 在括号中使用系统命令
$ 调用变量的值
\ 转义符
$n 代表命令行的第n个参数,其中$0代表命令本身
$# 代表命令行中参数的个数
$* 代表命令行中所有的参数,把所有参数看成一个整体
$@ 代表命令行中的所有参数,把每个参数个别对待
$? 代表最后一次执行的命令的返回状态,返回0代表执行成功,否则不成功
$$ 代表当前进程的进程号
$! 代表后台运行的最后一个进程的进程号
  • 变量 
    用户自定义变量 *: 
    为局部变量,只对当前shell生效。默认类型为字符串类型。 
    定义:变量名=变量值,当变量中含有空格时,需要用引号引起来 
    声明:declare [+/-] [option] 变量名 
    选项: +取消属性 -设置属性 -i 整型 -a 数组 -r 只读 
    使用unset命令删除变量 
    更加详细的声明规则,可以使用help declare查询 
    数组 *: 
    定义数组: arr_name=(value1 value2 ….)或 使用arr_name[index]=value单独为元素赋值 
    注意: 
    数组元素放在小括号内,而不是大括号,元素之间使用空格分开,而不是逗号,元素下标从0开始 
    获取数组元素: {arr_name[index]} 索引号为index的元素 {array_name[*]}数组的所有元素 
    获取数组长度: ${#arr_name[*]} 
    数组切片:${arr_name[@]:start:length} 
    元素匹配替换:${arr_name[@]/before/after} 
    环境变量 *: 
    为全局变量,对子shell仍然有效,一般定义为大写,使用命令env或者set命令可以查询,用命令declare -x可以自定义环境变量,使用unset命令可以删除变量。常用的系统预定义的环境变量如下所示:

变量 描述
$PATH 命令的搜寻路径
$OLDPWD 前一个工作目录
$LANG 目前的工作环境语言
$BASH 目前使用的shell的绝对路径(默认为/bin/bash)
$BASH_VERSION 使用的shell解释器的版本
$HISTCONTROL 控制历史记录,常用的有ignoredups,erasedups,ignorespace,……
$OSTYPE 显示系统类型
$MAIL 存放mail的文件
$MAILCHECK 多久检查一下邮件
$PWD 当前路径
$SSH_TTY 当前登录的TTY
$SHLVL 当前SHELL在第几层
$RANDOM 输出一个随机整数

注:生成0-49之间的随机数可以用如下命令:

echo $[RANDOM%50]
  • 算数运算 
    bash支持简单的算数运算,实现方式如下:

  1. let r=9+9

  2. r=$[9+9]; r=$[VAR1+VAR2]

  3. r=$((9+9)); r=$((VAR1+VAR2))

  4. expr 8 + 3

  5. declare -i r=9+9

  6. echo “9+9” | bc

赋值 可以使用如下几种赋值符号: =, +=, -=, *=, /=, %= 使用示例如下:
[root@centos7-front1 scripts]# a=10;b=10
[root@centos7-front1 scripts]# echo $a $b
10 10
[root@centos7-front1 scripts]# let c=a++
[root@centos7-front1 scripts]# echo $c
10
[root@centos7-front1 scripts]# let d=++b
[root@centos7-front1 scripts]# echo $b
11
  • 字体颜色 
    字体颜色示例如下:

    echo -e “\033[30m 黑色字 \033[0m” 
    echo -e “\033[31m 红色字 \033[0m” 
    echo -e “\033[32m 绿色字 \033[0m” 
    echo -e “\033[33m ×××字 \033[0m” 
    echo -e “\033[34m 蓝色字 \033[0m” 
    echo -e “\033[35m 紫色字 \033[0m” 
    echo -e “\033[36m 天蓝字 \033[0m” 
    echo -e “\033[37m 白色字 \033[0m”

    带背景的字体示例如下:

    echo -e “\033[40;37m 黑底白字 \033[0m” 
    echo -e “\033[40;37m 红底白字 \033[0m” 
    echo -e “\033[40;37m 绿底白字 \033[0m” 
    echo -e “\033[40;37m 黄底白字 \033[0m” 
    echo -e “\033[40;37m 蓝底白字 \033[0m” 
    echo -e “\033[40;37m 紫底白字 \033[0m” 
    echo -e “\033[40;37m 天蓝底白字 \033[0m” 
    echo -e “\033[40;37m 白底黑字 \033[0m”

  • 条件判断 
    使用test命令或者[]或者[[]]对条件进行测试 
    关于文件的判断,使用方式如下:

判断符 解释
-e 判断文件是否存在,如果存在则为真
-d 判断文件是否存在并且是否是目录(目录是一种特殊的文件),是则返回真
-f 判断文件是否存在并且是普通文件,是则返回真
-r 判断文件是否存在并且执行判断的用户是否对该文件有读的权限,是则返回真
-w 判断文件是否存在并且执行判断的用户是否对该文件有写的权限,是则返回真
-x 判断文件是否存在并且执行判断的用户是否对该文件有执行的权限,是则返回真
-nt 判断前面的文件是否比后面的文件新,是则返回真
-ot 判断前面的文件是否比后面的文件旧,是则返回真
-ef 判断前后两个文件的i节点是否相同,是则返回真

  使用示例如下:

[guest@centos7-front1 ~]$ ls
1.sh  attach  file
[guest@centos7-front1 ~]$ [ -e "/home/guest/file" ] && echo "True" || echo "False"
True
[guest@centos7-front1 ~]$ [ -d "/home/guest/file" ] && echo "True" || echo "False" 
False
[guest@centos7-front1 ~]$ [ -f "/home/guest/file" ] && echo "True" || echo "False" 
True
[guest@centos7-front1 ~]$ ls -al
total 28
drwx------  3 guest guest  144 Apr 17 16:51 .
drwxr-xr-x. 3 root  root    18 Mar 30 10:58 ..
-rwxr-xr-x  1 guest guest  171 Apr 17 16:51 1.sh
-rw-r--r--  1 root  root     1 Mar 30 13:21 attach
-rw-------  1 guest guest  416 Apr 10 17:05 .bash_history
-rw-r--r--  1 guest guest   18 Nov 20  2015 .bash_logout
-rw-r--r--  1 guest guest  193 Nov 20  2015 .bash_profile
-rw-r--r--  1 guest guest  231 Nov 20  2015 .bashrc
--w-------  1 guest guest    0 Apr 10 16:58 file
drwxr-xr-x  4 guest guest   37 Mar 19 18:42 .mozilla
-rw-------  1 guest guest 1013 Apr 17 16:51 .viminfo
[guest@centos7-front1 ~]$ 
[guest@centos7-front1 ~]$ [ -r "/home/guest/file" ] && echo "True" || echo "False" 
False
[guest@centos7-front1 ~]$ [ -w "/home/guest/file" ] && echo "True" || echo "False" 
True
[guest@centos7-front1 ~]$ [ -x "/home/guest/file" ] && echo "True" || echo "False" 
False
......
......
[guest@centos7-front1 ~]$ [ "/home/guest/.bash_history" -nt "/home/guest/.bash_logout" ] && echo "True" || echo " False"
True
[guest@centos7-front1 ~]$ [ "/home/guest/.bash_history" -ot "/home/guest/.bash_logout" ] && echo "True" || echo " False"  
 False

  关于整数的判断,使用的方式如下:

判断符 解释
-eq 判断前后两个整数是否相等,是则返回真
-ne 判断前后两个整数是否不相等,不相等则返回真
-gt 判断前一个整数是否大于后一个整数,是则返回真
-lt 判断前一个整数是否小于后一个整数,是则返回真
-ge 判断前一个整数是否大于等于后一个整数,是则返回真
-le 判断前一个整数是否小于等于后一个整数,是则返回真

  使用示例如下:

[root@centos7-front1 ~]# a=1 b=2 c=2
[root@centos7-front1 ~]# [ $a -eq $b ] && echo "True" || echo "False"
False
[root@centos7-front1 ~]# [ $a -ne $b ] && echo "True" || echo "False"  
True
[root@centos7-front1 ~]# [ $a -gt $b ] && echo "True" || echo "False"  
False
[root@centos7-front1 ~]# [ $a -lt $b ] && echo "True" || echo "False" 
True
[root@centos7-front1 ~]# [ $b -ge $c ] && echo "True" || echo "False"    
True
[root@centos7-front1 ~]# [ $b -le $c ] && echo "True" || echo "False"  
True

   关于字符串的判断,使用方式如下:

判断符 解释
-z 判断后面的字符串是否为空,是则返回真
-n 判断后面的字符串是否不为空,不为空则返回真
== 判断前后字符串是否相等,相等则返回真
!= 判断前后两个字符串是否不相等,不相等则返回真
> 前面字符串的ascii码是否大于后面字符串的ascii码,大于则返回真
< 前面字符串的ascii码是否小于后面字符串的ascii码,小于则返回真
=~ 左侧的字符串是否能够被右侧的pattern所匹配,是则返回真

  使用示例如下:

[root@centos7-front1 scripts]# cat execute.sh 
#!/bin/bash -x
ARG=$1
if [[ -f "$ARG" ]] && [[ "$ARG" =~ .sh$ ]]; then
        echo "ok"
else
        echo "fail"
fi
[root@centos7-front1 scripts]# bash execute.sh file 
fail
[root@centos7-front1 scripts]# bash execute.sh 1.sh 
ok
  • 流程控制 
    if语句控制流程,内容如下:

if [ 条件1 ];then
  expression
elif [ 条件2 ];then
  expression
  .....
else
  expression
fi

 多分支case语句控制流程,内容如下:

case $变量名 in
          "value1")
                expression
                ;;
          "value2")
               expression
               ;;
          .......
          *)
              expression
              ;; 
esac  


使用示例如下:
#!/bin/bash
read -t 30 -p "please input yes or no...." VAR
case $VAR in
        yes)
                echo "your input is yes."
        ;;
        no)
                echo "your input is no."
        ;;
        *)
                echo "your input is error..."
        ;;
esac

  for循环控制流程,内容如下:

形式1
for 变量  in  value1 value2 value3.....
do
      expression
done 

示例:
#!/bin/bash
cd /root/test/
ls *.tar.gz  >  ls.log
ls *.tgz    >>ls.log
for i in $(cat ls.log)
do
      tar -zxf $i &> /dev/null  #将执行中显示的信息丢到黑洞
done
rm -rf ls.log

形式2
for ((初始值;循环控制条件; 变量变化))
do
        expression
done

示例:
#!/bin/bash
#从1加到100
s=0;
for((i=1;i<=100;i=i+1))
do
     s=$(($s+$i))
done
echo "the sum is:$s"

 while循环控制流程,只要条件为真,便一直执行下去。内容如下:

while [ 条件判断式 ]
do
   程序
done

示例:
#!/bin/bash
#从1加到100
i=1
s=0
while [ $i -le 100 ]
do
     s=$(($s+$i))
     i=$(($i+1))
done
echo "the sum is:$s"

  until循环控制流程,一直执行,直到条件为真为止。内容如下:

until [ 条件判断式 ]
do
   程序
done

示例:
i=1
s=0
until [ $i -ge 100 ]
do
     s=$(($s+$i))
     i=$(($i+1))
done
echo "the sum is:$s"


  • 参考链接 

  1. linux之shell脚本

  2. wiki百科: Unix shell