1、bash脚本编程格式:

  • 顶格写#!/bin/bash

  • 接下来给出一些注释信息,以#开头如:

        #description

        #version

        #auhor ceshi <hello@heelp.com>

        #date 2017-11-07

  • 然后代码注释

  • 缩进,适度添加空白行


2、变量介绍:

    局部变量

    本地变量    

    环境变量

    位置参数变量

    特殊变量


3、数据类型:

    字符型

    数值型


4、bash算数运算:

方法①:let var=$num1 op $num2

方法②:var=$[ expression ]

方法③:var=$((expression))

方法④:var=$(expr argu1 op argu2 )

需要注意的是:

    var=变量值  //这是变量赋值

    var=$(命令) //这是命令结果引用

有些时候,乘法符号(*)需要转义实现;


5、增强型赋值:在shell脚本中要用let描述

变量做某种算数运算后回存至此变量中:

    let i=$i+#   //#是数字

    let i+=#

此类操作符有:+=、-+、*=、/=,%=


自增:

    let var+=1

    let var++  //如果每次加“1”,可以写成此种方式

自减:

    let var-=1

    let var--  //如果每次减“1”,可以写成此种方式


6、练习题:

计算/etc/passwd文件中的第10个用户和第20个用户的uid之和

id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3)

id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3)

idsum=$[ $id1 + $id2]


7、shell脚本编程之条件测试(测试表达式)

    判断某需求是否满足;需要由测试机制来实现。


如何编写测试表达式以实现所需要的测试:

    如#grep "^$" /etc/rc.d/init.d/functions &> /dev/null

     #echo $?

①、有专门命令实现测试表达式,使用执行命令,并利用命令状态返回值来判断:

    0:成功

    1-255:失败

    如:查看centos用户是否登陆系统:

    #w | grep "^centos\>"

    #echo $?

②、没有专门命令实现,这类需要用到测试表达式(如:大小、长短等)

    方法一:test expression

    方法二:[ expression ]   //注意:expression两端必须有空白字符,否则为语法错误

    方法三:` expression `  //注意:expression两端必须有空白字符,否则为语法错误


8、bash的测试表达式类型:

    数值测试

    字符串测试

    文件测试


8.1、数值测试:用于实现数值大小比较:

    -eq :是否等于;如[ $num1 -eq $num2 ]

    -ne :是否不等于

    -gt :是否大于

    -ge :是否大于等于

    -lt :是否小于

    -le :是否小于等于


8.2、字符串测试:字符比较;比较时,变量要加引号

    == :是否等于 如:[ "tom" =="tmo" ] 

    > :是否大于

    < :是否小于

    != :是否不等于

    =~:左侧字符串是否能够被右侧的PATTERN所匹配;可以匹配左侧字符串的部分内容。

    -z "string":判断指定的字串“string”是否为空,空则为真,不空为假

    -n "string":判断指定的字串"string" 是否为不空,不空为真,空则为假。


注意1:做字符串测试时,要在` expression `两个中括号中做比较,一个中括号有时是不生效的。

    如:#[[ a>b ]] 

        #echo $?

注意2:字符串要加引号,表示引用,做变量引用时不能用单引号。


8.3、文件测试:

  存在性测试:文件的存在性测试,存在为真,不存在为假

    -a FILE

    -e FILE

 文件存在性及类型测试:

    -b FILE :是否存在并且为块设备文件

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

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

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

    -h FILE :是否存在并且为符号链接文件

    -L FILE :是否存在并且为符号链接文件,大写"L"。

    -p FILE :是否存在并且为命名管道文件

    -S FILE :是否存在并且为套接字文件,大写"S"。

 文件存在性及权限测试:

    -r FILE :是否存在并且对当前用户可读

    -w FILE :是否存在并且对当前用户可写

    -x FILE :是否存在并且对当前用户可执行。

 文件存在性及特殊权限测试:

    -g FILE :是否存在并且拥有sgid权限

    -u FILE :是否存在并且拥有suid权限

    -k FILE :是否存在并且拥有sticky权限

 文件存在性及大小测试:文件是否有内容

    -s FILE :是否存在并且有内容,有为真没有为假;小写“s”

 文件存在性及时间戳测试:

    -N FILE :文件自从上一次读操作后是否被修改过。

 文件存在性及从属关系测试

    -O FILE :文件是否存在并且当前用户是文件属主。

    -G FILE :文件是否存在并且当前用户属于文件属组。

 双目测试:

    FILE1 -eq FILE2 :FILE1与FILE2是否为指向同一文件系统的相同inode的硬链接

    FILE1 -N FILE2 :FILE1是否新于FILE2

    

8.4、组合测试条件:

  逻辑运算:

方法一:

    command1 && command2

    command1 || command2 

    ! command2

方法二:

    test EXPRESSION1 -a|-o|!EXPRESSION2

方法三:[ EXPRESSION1 -a|-o|!EXPRESSION2 ]

方法四:[[ EXPRESSION1 -a|-o|!EXPRESSION2 ]]

    如:

    [ -o FILE -a -x FILE ] //表示测试用户是否属于当前用户并有执行权限。


9、脚本的状态返回值:

    默认是脚本中执行的最后一条命令的状态返回值,可以自定义状态退出状态码,如下:

    exit [n] :n为自己指定的状态码;若不指定n,默认0为真,其他为假,

注意:shell进程遇到exit时,即会终止,因此整个脚本执行即为结束。

    如:id user3 &> /dev/null && exit 0 || useradd user3



练习1:将当前主机名称保存至hostname变量中;主机名如果为空,或者为localhost.localdomain,则将其设置为www.magedu.com

[root@localhost ~]# hostname=$(hostname)

[root@localhost ~]# [ -z "$hostname"  -o "$hostname" == "localhost.localdomain" ]  && hostname www.magedu.com



10、位置参数变量:向脚本传递参数

 位置参数变量格式:

    MYSCRIPT ARGU1 ARGU2   //脚本 参数1 参数2

位置参数变量应用方式:$1,$2,.....${10},${...},

如:

有一个脚本如下:

#!/bin/bash

echo "put two arg"

let sum=$1+$2

echo $sum


运行:

[root@localhost ~]# bash ./script 2 3       //其中2 3 为位置参数表示脚本中的$1,$2

put two arg

5

[root@localhost ~]# 


位置参数轮替:

  格式:shift [n]   //一次将n个参数踢出,可以不加n,表示默认一个

如:

#!/bin/bash

echo " firsh pos argus :$1,$3"

shift 2

echo "second pos argus :$1"

运行:

~]# bash ./shift.sh 1 2 3  //一次踢出两个参数,那个再一次给$1赋值 即是第三个数

 firsh pos argus :1,3

second pos argus :3

[root@localhost ~]# 


练习:

写一个脚本,通过命令传递两个文本文件路径给脚本,计算空白行数之和

  1 #!/bin/bash

  2 lin1=$(grep "^$" "$1"| wc -l)

  3 lin2=$(grep "^$" "$2"| wc -l)

  4 echo $[$lin1+$lin2]

运行:

[root@localhost ~]# bash ./line0.sh  /etc/fstab /etc/issue

2

[root@localhost ~]# 



11、特殊变量

    $0:脚本文件路径本身

    $#:脚本参数的个数

    $*:所有参数,把所有参数当作一个个单独的字符串

    $@:所有参数,把所有参数当作一个个字符串来看待


引用9:

脚本的状态返回值:

    默认是脚本中执行的最后一条命令的状态返回值,可以自定义状态退出状态码,如下:

    exit [n] :n为自己指定的状态码,0为真,其他为假

注意:shell进程遇到exit时,即会终止,因此整个脚本执行即为结束。

    如:id user3 &> /dev/null && exit 0 || useradd user3

如下脚本:

  1 #!/bin/bash

  2 [ $# -lt 2 ] &&  echo "input two argu" && exit 10

  3 

  4 lin1=$(grep "^$" "$1"| wc -l)

  5 lin2=$(grep "^$" "$2"| wc -l)

  6 echo $[$lin1+$lin2]

运行:

[root@localhost ~]# bash ./line0.sh  /etc/fstab  

input two argu

[root@localhost ~]# echo $?   //查看执行状态,由于有exit命令,因此不会执行到最后一条语句

10

[root@localhost ~]# 

    


12、过程式编程语言的代码执行顺序:

    顺序执行:逐条运行

    选择执行:代码有一个或多个

        代码有一个分支:条件满足时才会运行

        代码有两个或以上分支:只会执行其中一个满足条件的分支

    循环执行:

        代码片段(即循环体)要执行0次,1次,或多次的循环。

12.1、选择执行--单分支的if语句


格式一:

if  测试条件

 then

   代码分支

fi


格式二:

if  测试条件;then

  代码分支

fi


12.2、选择执行--双分支的if语句


格式:


if 测试条件;then

  条件为真时执行的分支

else

  条件为假时执行的分支

fi

选择执行示例一:


通过参数传递一个用户名给脚本,此用户不存在时,则添加此用户:

脚本如下:

#!/bin/bash

if  ! grep "^$1\> " /etc/passwd  &> /dev/null ;then

useradd "$1"

echo $1 | passwd --stdin $1 &> /dev/null

fi

运行脚本如下:

[root@localhost ~]# grep "^zhang\>" /etc/passwd 

[root@localhost ~]# bash ./user.sh zhang

[root@localhost ~]# grep "^zhang\>" /etc/passwd 

zhang:x:2013:2013::/home/zhang:/bin/bash

[root@localhost ~]# 


选择执行示例二:


通过参数传递一个用户名给脚本,此用户不存在时,则添加此用户:

脚本如下:

#!/bin/bash

if [ $# -lt 1 ];then

echo "input username"

    exit 22

fi


if  grep "^$1\> " /etc/passwd  &> /dev/null ;then

echo  "$1 is exists"

fi


if  ! grep "^$1\> " /etc/passwd  &> /dev/null ;then

useradd "$1"

echo $1 | passwd --stdin $1 &> /dev/null

fi

    exit 222

注意:此shell脚本中有两处exit命令,去掉exit 22,会执行exit 222,用echo $?可以验证,如果在之间有exit 22,则以后的语句就不会再执行了。


选择执行示例三:


通过键盘给定的两个数字,输出其中较大的值

#!/bin/bash

if [ "$1" -gt "$2" ] 

  then

echo " the max is  $1"

else

echo "the max is $2"

fi


运行如下:

[root@localhost ~]# bash ./max.sh  3 20

the max is 20

[root@localhost ~]# 

示例四,

求两数较大值。 


1 #!/bin/bash 

  2 max=$2

  3 if [ "$1" -gt "$2" ]

  4  then

  5     max=$1

  6 else

  7     max=$2

  8 fi

  9 echo "max is $max"


注意:此处事先申明的max=$2有没有都可以,


选择执行示例四:


判断从键盘给定的一个用户名,他的id是偶数还是奇数。

#!/bin/bash

if [ $# -lt 1 ] ;then

echo " input at least one argu:"

exit 10

fi


if grep "^$1\>" /etc/passwd &>/dev/null;then 

echo "the user:$1 is cunzai"

else

echo "the user:$1 is not cunzai" 

exit 100

fi


id=$(grep "^$1\>" /etc/passwd | cut -d: -f3 )

echo $id

if [ $[$id%2] -eq 0 ];then     //判断取余运算

echo $1 is ou shu

else

echo $1 is ji shu

fi


运行如下:

[root@localhost ~]# bash ./jiou.sh lucy

the user:lucy is cunzai

2008

lucy is ou shu

[root@localhost ~]# bash ./jiou.sh lily

the user:lily is cunzai

2009

lily is ji shu

[root@localhost ~]# 


选择执行示例五:

通过命令行参数给定两个文件名,如果某文件不存在,则结束脚本执行;如果都存在,则返回每个文件的行数,并说明其中行数较多的文件。

#!/bin/bash

echo "input two filename:$1,$2"


if [ $# -lt 2 ] ;then

echo "the filename_num need two"

fi


if [ -e "$1" -a -e "$2" ];then

echo $(wc -l "$1") 

echo $(wc -l "$2")

else

echo at least one is not exists

exit 20

fi

line1=$(wc -l "$1" | cut -d ' ' -f1) 

line2=$(wc -l "$2" | cut -d ' ' -f1)

 

if [ "$line1" -gt "$line2" ]; then

echo "the filename is $1"

else

echo "the filename is $2"

fi

运行如下:

[root@localhost ~]# bash  hangshu  /etc/fstab /etc/issue

input two filename:/etc/fstab,/etc/issue

12 /etc/fstab

3 /etc/issue

the filename is /etc/fstab



注意:有时候脚本在编写的时候会有错误,可以用bash -x来执行检查

"-x"选项可用来跟踪脚本的执行,是调试shell脚本的强有力工具。“-x”选项使shell在执行脚本的过程中把它实际执行的每一个命令行显示出来,并且在行首显示一个"+"号。 "+"号后面显示的是经过了变量替换之后的命令行的内容,有助于分析实际执行的是什么命令。 “-x”选项使用起来简单方便,可以轻松对付大多数的shell调试任务,应把其当作首选的调试手段。