bash应该是目前Linux上最流行的shell脚本解释程序了,只要你在linux上工作,并且希望自己能够工作得更愉悦,那么你应该熟悉最基本的bash编程,因为它将给你的工作带来足够的幸福感。本文将总结一些我自己平时使用的bash基本编程知识,和大家分享,也便于自己查询。

   

变量

   bash的变量名是区分大小写的,并且变量名首字符不能是数字

    变量定义与赋值

aaa=123

这里需要注意定义变量时等号前后都不能有空格,必须紧靠着写。虽然等号后面有空格的情况,语法可能不会出错,但结果绝对是错误的。 

变量拼接

bbb=${aaa}123

很多时候,我们可能需要用一些变量、常量字符串等来拼接出一个新的变量,这时需要注意用来拼接的变量可能需要加上{},否则可能会出现变量识别错误从而找不到变量的情况。这种情况,我倾向于所有变量一股脑的全加上{}。

  

条件判断

if条件表达中长涉及到的比较有字符串整数文件属性比较等。

if语句格式有:

if [ expr ] ; then

      do something

fi


if [ expr ] ; then

      do something

else

      do something

fi


if [ expr ] ; then

     do something

elif [ expr ] ; then

     do something

else

     so something

fi


if语句和其他语言(c,java)相比,是行不同但神似。then关键可以另起一行,那样条件表达式后的分号就可以省略了。这里最需要注意的是 " [ " 和 " ] "前后至少需要一个空格来分割。

 

1、整数比较

整数大小比较涉及的操作符有—— -lt、-le、-eq、-gt、-ge和 -ne。

例子:

-lt 大于

-gt 小于

 -le 小于等于

-ge 大于等于

-ne 不等于

-eq 等于


a=1
b=2

if [ $a -lt $b ] ; then
    echo "a < b"
else
    echo "a >= b"
fi

if [ $a -ne 3 ] ; then
    echo "a != 3"
else
    echo "a == 3"
fi


if [ 1 -gt 3 ] ; then
    echo "1 > 3"
else
    echo "1 <= 3"
fi


使用整数大小比较的6个操作符时,涉及到的两个操作数将会作为数值来处理,而不是字符串,即使你使用双引号将比较对象给引起来,也是如此。

 

三种使用格式

单分支的if语句:

if 测试条件; then

    选择分支

fi

表示条件测试状态返回值为值,则执行选择分支;


if ! id $username &> /dev/null; then

useradd $username

fi


练习:写一个脚本,接受一个参数,这个参数是用户名;如果此用户存在,则显示其ID号;


双分支的if语句:

if 测试条件; then

   选择分支1

else

选择分支2

fi


两个分支仅执行其中之一。



通过命令行给定一个文件路径,而后判断:

如果此文件中存在空白行,则显示其空白行的总数;

否则,则显示无空白行;


if grep "^[[:space]]*$" $1 &> /dev/null; then

              echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."

else

             echo "No blank lines"

fi


注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。


多分支的if语句:

if 条件1; then

分支1

elif 条件2; then

分支2

elif 条件3; then

分支3

...

else

分支n

fi



传递一个用户名给脚本:

如果此用户的id号为0,则显示说这是管理员

如果此用户的id号大于等于500,则显示说这是普通用户

否则,则说这是系统用户;

   bash 编程

2、字符串比较

字符串比较可能用到的操作符有—— =、!=、>、<、-n和-z。

例子:
s1=aaa
s2=bbb

if 
[ $s1 \< $s2 ] ; then
    echo "$s1 < $s2"
else
    echo "$s1 >= $s2"
fi

if 
[[ $s1 < $s2 ]] ; then
    echo "$s1 < $s2"
else
    echo "$s1 >= $s2"
fi

if [ $s1 = $s2 ] ; then
    echo "$s1 == $s2"
else
    echo "$s1 != $s2"
fi

if [ -n $s1 ] ; then
    echo $s1
fi

用于字符串大小比较的>和<两个操作符比较特别,在[ ]中书写时需要转义,否则可以使用` `来替代[ ]。不转义,>和<会被解释为IO重定向操作。其次,if语句体不能为空,必须至少做一件事情。


操作符-n 用于判断字符串不为空,即长度不为0。-z判断字符串为空,即长度为0

   

for循环

常用的for循环有两种主要形式

形式一

for e in [list]

do

    do something

done

这种格式的for常用来遍历一个list集合中的所有元素,并加以处理。比如:

1、遍历一个目录中的所有文件

for file in `ls dir`

do

     echo $file

done


2、遍历一个给定的集合

list="a b c d e f g"

for e in $list

do

    echo $e

done


for in格式在遍历集合时,其实是根据空白字符来分隔字符串,取得每个元素的,上例中的`ls dir`和$list得到的都是一个带空白字符的字符串。


形式二

for ((i = 0; i < n; i++))

do

    do something

done

这一种for的形式和C语言基本一致,只是需要双括号罢了,它更擅长做确定次数的循环计算。比如:


for ((i = 0; i < 10; i++))

do

    echo $i

done

     

练习:写一脚本

1、添加10个用户:tuser601-tuser610

如果用户不存在,才添加,并以绿色显示添加成功;如果存在,则以红色显示已经有此用户;

2、显示一共添加了多少个用户;

#!/bin/bash

#

declare -i count=0


for i in {501..510}; do

   if id tuser$i &> /dev/null; then

       echo -e "\033[31mtuser$i\033[0m exists."

   else

       useradd tuser$i

       echo -e "add user \033[32mtuser$i\033[0m successfully."

       let count++

   fi

done


echo "Total add $count users."


练习:写一个脚本

传递用户名给脚本

1、判断此用户的shell是否为/bin/bash,如果是,则显示此用户为basher

2、否则,则显示此用户为非basher


#!/bin/bash

#

userShell=`grep "^$1\>" /etc/passwd | cut -d: -f7`


if [ "$userShell" == '/bin/bash' ]; then

   echo "basher"

else

   echo "not basher"

fi

我们

扫描172.16.250.0/16内的所有主机;在线的,使用绿色显示;不在线,使用红色显示;


最后分别显示:在线和不在线各有多少主机;

bash 编程

  我们要给其加上一个执行权限 

   在执行以下bash 编程

    也可以用bash走下测试

                   bash -n    文件名 测试语法错误

                       bash -x  文件名  直接交给bash运行   不用加权限

     

case语句

case语句相当于绝大多数语言里的switch语句。这玩意除了具备if-elif的功能外,还支持通配符,这个相当有用。我们直接看例子。

例子:

url=www.tmall.com

case $url in
    www.taobao.com)  echo 1;;
    *.taobao.com)         echo 2;;
    *.tmall.com)             echo 3;;
    www.tmall.com)      echo 4;;
    *)                               echo 5;;
esac


上例中条件分支不光有常量字符串,还有含通配符的字符串,这一点用来进行模式匹配非常便利。其次,需要注意case语言在匹配的过程中是从第一个开始逐一匹配,所有上例的输出结果是3,而不是精确匹配的4

   

函数

函数定义

function hello()

{

      echo "hello world"

}

函数定义实用关键字function,函数名后面的括号可有可无。


函数调用

无参数的函数调用只需要给出函数名就ok了,上面定义的函数直接用hello调用即可。有参数的函数,只需要将参数依次在函数名后面给出即可,如:func_name arg1 arg2。


函数参数

函数调用的时候可以给函数传递参数,那么函数体中又如何获取这些参数呢? 函数参数的获取和脚本程序参数的获取一致,都是通过$1、$2等来取得。比如:


function add()
{
    n=$1
    m=$2
    echo $((n + m))
}

调用add 1 2,将输出3。

在函数中,可以通过$#的值来判断函数调用的时候,传递了几个参数。


bash函数里很少使用return这种方式来返回值。不过可以这样调用函数来获取计算结果,比如:


res=`add 1 2`

变量res的值就是3了。注意上面不是单引号,而是数字1旁边的字符。


字符串处理

字符串处理差不多是整个计算机世界里做得最频繁的一件事情了。玩C语言的人很多事情都是在编写字符串处理程序。玩java的人大多数时候虽然不用自己去编写字符串处理程序,但也基本总是在调用字符串处理方法。linux其实有着非常强大的工具让我们去做字符串处理,不熟悉之前,每个工具貌似长得都非常复杂的样子。这里简单的总结一下自己使用过的字符串相关的东东。


1、求子串

str=abcdefg

echo ${str:2:3} 将得到bcd,表达式中的2代表偏移量,3代表长度。


2、求字符串长度

str=123456

echo ${#str}


3、字符串替换

${变量/pattern/xx}   将变量中的第一个匹配替换为xx。

${变量//pattern/xx} 将变量中的所有匹配替换为xx。


str=aaabbbccc

echo ${str/aaa/xxx}

echo ${str/a/x}


有关字符串的处理,有着很多的工具,比如:你可以使用cut, awk等程序去拆分一个字符串等。


整数运算

整数运算一般使用$(( expr ))来进行。比如:

echo $((1 + 2))
a=1
echo $((
a + 2))
echo $((
a++))
echo $((
++a))
b=2
echo $((
(a + b) / 2))

可以看到只需要将计算表达式塞到$(())中就可以了,参与计算的变量并不需要$符号。整数运算涉及到的运算符有:++ 、--、+、-、*、/、%、+=、

     


写一个脚本,使用格式:

script.sh {start|stop|restart|status}


1) start: 创建/var/lock/subsys/script.sh

2) stop: 删除此文件

3) restart: 先删除文件,再创建文件

4) status: 如文件存在,显示running,否则,显示stopped


#!/bin/bash

#

srv=`basename $0`


lockFile="/var/lock/subsys/$srv"


[ $# -lt 1 ] && echo "Usage: $srv {start|stop|restart|status}" && exit 4


[ $UID -ne 0 ] && echo "Only root." && exit 5


case $1 in

start)

  if [ -f $lockFile ]; then

       echo "$srv is running."

exit 7

  else

touch $lockFile

[ $? -eq 0 ] && echo "Starting $srv OK."

  fi

  ;;

stop)

   if [ -f $lockFile ]; then

rm -f $lockFile

[ $? -eq 0 ] && echo "Stopping $srv OK."

   else

echo "$srv is stopped yes."

exit 6

   fi

   ;;

restart)

   if [ -f $lockFile ];then

    rm -f $lockFile

[ $? -eq 0 ] && echo "Stopping $srv OK."

   else

echo "$srv is stopped yet."

   fi

   touch $lockFile

   [ $? -eq 0 ] && echo "Starting $srv OK."

   ;;

status)

   if [ -f $lockFile ];then

echo "$srv is running."

   else

echo "$srv is stopped."

   fi

   ;;

*)

   echo "Usage: $srv {start|stop|restart|status}" && exit 9

esac