Bash 脚本编程基础及示例

            

简介

Bash(Bourne Again Shell)是当前 Linux 系统默认的,在 sh(Bourne Shell)的基础上进行扩展,并代替 sh 的一种 CLI(command-line interface)工具。

由于 bash 本身就是 Linux 上的命令语言,所以 bash 编程有着得天独厚的优势:所有在 bash 编程中用到的语句,都可以在命令行中执行。换句话说,就是 bash 编程,其实就是按条件堆积 linux 命令的过程。这也很好地解释了 Linux 是由众多功能单一程序组成的这种哲学思想。

类型

编程语言类型可大致分为过程式编程语言和面向对象式编程语言,而 bash 编程则是过程式编程语言的一种。

过程式编程语言有着以下三种执行流程:

  1. 顺序执行;
  2. 选择执行;
  3. 循环执行。

顺序执行就不说了,就是沿着文件内容,从上到下执行。

选择执行

选择执行有以下几种方法:

  1. &&||
  2. case 语句;
  3. if 语句。

第 1 种方式在在《Bash变量、配置及测试运算简介》中已经讲过,其实这篇文章中的测试条件及判断方法,都可以用到 bash 编程中来,也就是选择执行的一个过程。

Case 语句和 if 语句有着类似之处,但 case 大多用于判断一个值在不同的预期中执行不同的操作,而 if 则有着更多的判断条件及更灵活的使用方式。

case

#/bin/bash

handle="$1"

case "${handle}" in
'start')
/usr/sbin/apachectl start ;;
'stop')
/usr/sbin/apachectl stop ;;
'restart')
/usr/sbin/apachectl restart ;;
*)
echo "usage $0 start|stop|restart" ;;
esac

以上 case 代码表示输入制定指令来让 apache 执行不同的操作。

Case 的应用比较简单,下面来着重说说比较常用的 if 语句的用法。

if

If 语句有三种格式:

  1. 单分支的 if 语句;
if 条件;then
  执行;
fi
  1. 双分支的 if 语句;
if 条件; then
  执行1;
else
  执行2;
fi
  1. 多分支的 if 语句;
if 条件1; then
   执行1;
 elif 条件2; then
   执行2;
 elif 条件3; then
   执行3;
 ...
 elif 条件n; then
   执行n;
 else
   执行n+1;
 fi

注意:即便多个条件可能同时都能满足,分支只会执行中其中一个,首先测试为“真”。

示例一:

写一个脚本:

脚本参数传递一个文件路径给脚本,判断此文件的类型。

#!/bin/bash

if [ $# -lt 1 ]; then
    echo "At least on path."
    exit 1
fi

if ! [ -e $1 ]; then
    echo "No such file."
    exit 2
fi

if [ -f $1 ]; then
    echo "Common file."
elif [ -d $1 ]; then
    echo "Directory."
elif [ -L $1 ]; then
    echo "Symbolic link."
elif [ -b $1 ]; then
    echo "block special file."
elif [ -c $1 ]; then
    echo "character special file."
elif [ -S $1 ]; then
    echo "Socket file."
else
    echo "Unkown."
fi

示例二:

写一个脚本:

(1) 传递一个参数给脚本,此参数为用户名;
(2) 根据其ID号来判断用户类型:
    0:管理员
    1-999:系统用户
    1000+:登录用户
#!/bin/bash

[ $# -lt 1 ] && echo "At least on user name." && exit 1

! id $1 &> /dev/null && echo "No such user." && exit 2

userid=$(id -u $1)

if [ $userid -eq 0 ]; then
    echo "root"
elif [ $userid -ge 1000 ]; then
    echo "login user."
else
    echo "System user."
fi

示例三:

写一个脚本:

(1) 列出如下菜单给用户:
    disk) show disks info;
    mem) show memory info;
    cpu) show cpu info;
    *) quit;
(2) 提示用户给出自己的选择,而后显示对应其选择的相应系统信息;
#!/bin/bash

cat << EOF
disk) show disks info
mem) show memory info
cpu) show cpu info
*) QUIT
EOF

read -p "Your choice: " option

if [[ "$option" == "disk" ]]; then
    fdisk -l /dev/[sh]d[a-z]
elif [[ "$option" == "mem" ]]; then
    free -m
elif [[ "$option" == "cpu" ]];then
    lscpu
else
    echo "Unkown option."
    exit 3
fi

循环执行

循环执行,即将一段代码重复执行多次,有进入条件和退出条件(每个循环都应该有退出条件,以避免造成死循环)。

循环执行有以下几种方式:

  1. for 循环;
  2. while 循环;
  3. until 循环。

for 循环

for 循环有两种格式:

  1. 遍历列表;
  2. 控制变量。

遍历列表,即在一个列表中循环执行,直至把列表中的元素循环完为止。

for VARAIBLE in LIST; do
    循环体
done

# 进入条件:只要列表有元素,即可进入循环;
# 退出条件:列表中的元素遍历完成;

其中,LIST 的生成方式包括但不限于下几种:

  1. 直接给出:for x in 1 2 3 4;do ...;done
  2. 整数列表:{start..end}for x in {1..4};do ...;done
  3. seqfor x in seq 1 4;do ...;done
  4. 返回列表的命令:for x in $(ls);do ...;done
  5. glob :for x in /etc/git*;do ...;done
  6. 变量引用:for x in ${abc};do ...;done

示例一:

写一个脚本:

判断制定用户是否存在,如不存在则添加用户。

#!/bin/bash
#
for username in user21 user22 user23; do
    if id $username &> /dev/null; then
        echo "$username exists."
    else
        useradd $username && echo "Add user $username finished."
    fi
done

示例二:

写一个脚本:

求100以内所有正整数之和。

#!/bin/bash
#
declare -i sum=0

for i in {1..100}; do
    echo "\$sum is $sum, \$i is $i"
    sum=$[$sum+$i]
done

echo $sum

示例三:

写一个脚本:

判断 /var/log 目录下的每一个文件的内容类型。

#!/bin/bash
#
for filename in /var/log/*; do
    if [ -f $filename ]; then
        echo "Common file."
    elif [ -d $filename ]; then
        echo "Directory."
    elif [ -L $filename ]; then
        echo "Symbolic link."
    elif [ -b $filename ]; then
        echo "block special file."
    elif [ -c $filename ]; then
        echo "character special file."
    elif [ -S $filename ]; then
        echo "Socket file."
    else
        echo "Unkown."
    fi                  
done

控制变量,即以一个变量为媒介,控制此变量的范围来控制整个循环。

for (( i=1;i<10;i++ ));do
    循环体
done

# 进入条件:i 在指定范围内;
# 退出条件:i 在指定范围外;

示例一:

写一个脚本:

将 I'm a good boy 输出10遍。

#/bin/bash

for (( i=1;i<11;i++ ));do
    echo "I'm a good boy"
done

示例二:

写一个脚本:

将以下变量的值输出:
setVar1=1
setVvar2=2
setVar3=3
...
setVar1000=1000
for (( i=1;i<1001;i++));do
    eval setVar=\${setVar${i}}
    echo "$setVar"
done

while 循环

while 循环和 for 循环的不同之处是没有范围限制(当然 for 循环也可以设置无限范围,但一般不这样做),只要设定条件为真,就会一直循环下去。所以 while 循环需要特别注意退出条件的设置

while CONDITION; do
    循环体
    循环控制变量修正表达式(修正表达式以设置退出条件)
done

# 进入条件:CONDITION 测试为真;
# 退出条件:CONDITION 测试为假;

示例

求100以内所有正整数之和。

#!/bin/bash
#
declare -i sum=0
declare -i i=1

while [ $i -le 100 ]; do
    let sum+=$i
    let i++
done

echo $sum

until 循环

until 循环的用法和 while 循环的类似,只不过条件判断跟 while 循环相反。

until CONDITION; do
    循环体
    循环控制变量修正表达式(修正表达式以设置退出条件)
done

# 进入条件:CONDITION 测试为假;
# 退出条件:CONDITION 测试为假真

示例

求100以内所有正整数之和。

#!/bin/bash
#
declare -i sum=0
declare -i i=1

until [ $i -gt 100 ]; do
    let sum+=$i
    let i++
done

echo $sum