shell编程基础

shell概述

1. shell编程的意义

个人理解,shell编程类似于存储过程。存储过程是完成指定功能的一组sql语句集合,而shell编程就是完成指定功能的一组linux命令的集合。例如,我们要在服务器上部署一个一个项目,通常要做如下几个操作:

  • 进入项目目录:cd /home/dubhlinn/project/demo
  • 切分支:git checkout master
  • 从远程仓库拉取最新代码:git pull
  • 打包:mvn clean install -P production
  • 部署:docker build -t ...

每次部署都要执行相同的一套流程,如果能把这些操作放在一个文件里,只需执行这个文件即可,会明显提高服务器运维管理的效率。这就是shell编程要满足的需求。

2. shell分类

linux的shell分类很多,例如

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

其中,最常用的是bash shell,即/bin/bash。

3. shell编程的格式

可以使用vi或vim编辑器创建shell脚本文件,其扩展名并没有要求,可以使用(.sh)表示它是一个shell文件,例如hello.sh、deploy.sh等,但是使用别的扩展名或者不用扩展名也不影响其执行。shell文件的第一行一般要指定shell种类,#!用来告诉系统,这个文件使用哪个解释器。例如最常用的bash shell这样写:

#!/bin/bash
#这是单行注释
echo "hello world"
:<<!
这是多行注释
这是多行注释
这是多行注释
!
echo "byebye"

 

 4. shell脚本的执行方式

如果给shell脚本赋予了可执行权限,则直接写文件的路径名即可执行,可以使用绝对路径或相对路径,注意如果shell文件正好在当前目录下,相对路径要以 ./ 开头,而不能直接写文件名。如果并没有给shell脚本赋予可执行权限,则需要在文件路径名前加 sh。一般推荐第一种,即赋予用户对文件的可执行权限。例如,在当前路径(/home/dubhlinn)下有一个hello.sh的脚本,

(1) 当用户对其有可执行权限时:

./hello.sh

/home/dubhlinn/hello.sh

(2) 当用户对其无可执行权限时:

sh ./hello.sh

sh /home/dubhlinn/hello.sh

 

shell编程的变量

1. 变量的定义

变量名 = 变量值

#输出环境变量
echo $HOME
echo $USER

#自定义变量
A=12
B=hello
echo A=$A
echo B=$B

shell编程中变量分为两类:环境变量、自定义变量。环境变量是linux系统已经预先定义好的变量,可以直接使用;自定义变量必须先定义,再使用。定义变量的的语法很简单,但是有几点需要注意:

  • 变量名可以由数字、字母、下划线组成,但是不能以数字开头
  • 定义变量时,等号两侧不允许使用空格,这一点跟Java、JavScript等语言有区别
  • 变量名习惯用大写字母表示
  • 定义变量时不用美元符号($),使用变量时要使用美元符号($)
  • 变量被定义后,可以重新赋值,后面的值会覆盖前面

2. 声明环境变量

(1) export 变量名=变量值

(2) source 文件路径名

第一步跟自定义变量相比,只是多了一个export关键字,第二步是为了让shell文件生效。完成这两步之后,可以在其它的shelle文件或中获取刚刚声明的环境变量。而相比之下,自定义变量仅限于在一个shell文件中使用,在其他的shell文件中无法使用。

#设置环境变量
export VILLA=Spain7
export TORRES=Spain9 

需要注意的是,在一个shell文件中,自定义变量会覆盖同名的环境变量,例如

#输出环境变量
echo VILLA=$VILLA

#自定义变量
VILLA=Bacelona7

#输出,看是环境变量还是自定义变量
echo VILLA=$VILLA

第一次输出的是环境变量的值:Spain7,第二次输出的是自定义变量的值:Bacelona7。

3. 变量的撤销

unset 变量名

#撤销变量
B=hello
unset B
echo B=$B

4. 静态变量,不能被撤销

readonly 变量名=变量值

:<<!
静态变量
不能撤销
!
readonly C=5 
echo C=$C
unset C
echo C=$C

执行这个脚本会报错,因为C是静态变量,不能使用unset将其撤销。

5. 将linux命令的执行结果赋给变量

变量名=`命令`    或    变量名=$(命令)

#将linux命令的执行结果赋给变量,两种方式等价
A=`ls -lh`
B=$(date)
echo A=$A
echo B=$B

6. 接收参数

在shell脚本中可以像Java方法一样接收形参,其语法格式如下

  • $数字  表示第几个参数,超过10的需要用${数字},例如$1、$2、${15}
  • $*      表示所有参数,且作为一个整体
  • $@     表示所有参数,但每个分别对待
  • $#      表示参数的个数
#输出单个参数
echo 第1个参数为$1
echo 第2个参数为$2
echo 第10个参数为${10}

#输出全部参数,且作为一个整体
echo 全部参数为$*

#输出全部参数,且分别对待
echo 参数分别为$@

#输出参数个数
echo 总共有$#个参数

在执行这个shell脚本时,可以传入参数,例如 ./hello.sh 1 2 3

 

shell编程的运算符

shell的运算符本身跟Java、JavaScript等语言基本一样:+、-、*、/、%等,但实际应用有一些独特的规则,主要有以下三种使用方法

  • $((运算式))
  • $[运算式]
  • expr 运算式

其中,前两种方式的运算符之间不能加空格,第三种方式的运算符之间必须加空格,而且括号、乘号需要加转义符号,即 \(、\)、\* 。这些规则看起来有点奇怪,下面用几个具体的示例来说明。

1. 求 (3+5)*4/(2+1)的值

#使用第一种方式计算
R1=$(((3+5)*4/(9-1)))
echo R1=$R1

#使用第二种方式计算
R2=$[(3+5)*4/(9-1)]
echo R2=$R2

#使用第三种方式计算
R3=`expr \( 3 + 5 \) \* 4 / \( 9 - 1 \)`
echo R3=$R3 

2. 求第一个参数和第二个参数的和,然后取除以第三个参数的余数

#使用第一种方法计算
R1=$((($1+$2)%$3))
echo R1=$R1

#使用第二种方法计算
R2=$[($1+$2)%$3]
echo R2=$R2

#使用第三种方法计算
R3=`expr \( $1 + $2 \) % $3`
echo R3=$R3

 

shell编程的条件分支语句

1. if条件分支语句

if [ 条件1 ]

  then

    语句1

elif [ 条件2 ]

  then

    语句2

else

    语句3

fi

其中,中括号与条件之间必须加空格。

符号 意义
= 两个字符串是否相等
-lt 小于
-le 小于等于
-eq 等于
-ge 大于等于
-gt 大于
-ne 不等于
-r 文件或目录有读的权限
-w 文件或目录有写的权限
-x 文件或目录有执行权限
-f 文件存在并且是一个常规文件
-e 文件存在
-d 文件存在并且是一个目录

2. case条件分支语句

case 变量 in

值1)

语句1

;;

值2)

语句2

;;

*)

语句3

;;

esac 

 

3. 应用示例

#判断文件是否存在
if [ -e /home/dubhlinn/shell/aaa.txt  ]
    then
    echo 存在
else
    echo 不存在
fi

#判断是不是一个目录
if [ -d /home/dubhlinn/shell ]
    then 
        echo 是一个目录
else 
    echo 不是一个目录
fi

#判断文件是否有可执行权限
if [ -x /home/dubhlinn/shell/hello.sh ]
    then 
    echo 有可执行权限
else
    echo 无可执行权限
fi

#判断两个数字的大小
if [ $[5*3] -ge $[6+7] ]
    then 
    echo 前者大于等于后者
else 
    echo 前者小于后者
fi

#判断传入的参数范围
if [ $1 -gt 90 ]
    then
    echo 优秀
elif [ $1 -ge 60 ]
    then
    echo 及格
else
    echo 不及格
fi
#!/bin/bash

:<<!
如果参数是6,则输出"星期六",
如果参数是7,则输出"星期日"
如果是其他,则输出"工作日"
用两种判断语句实现
!


#使用if语句实现
if [ $1 -eq 6 ]
    then
    echo 星期六
elif [ $1 -eq 7 ]
    then
    echo 星期日
else
    echo 工作日
fi


#使用case语句实现
case $1 in
6)
echo 星期六
;;
7)
echo 星期日
;;
*)
echo 工作日
;;
esac

 

 shell编程的循环语句

1. for循环

for ((初始值;循环条件;变量变化))

do

    表达式

done

2. while循环

while [ 条件 ]

do

    表达式

    变量变化

done

注意,中括号跟条件之间需要加空格。

3. 使用示例

#!/bin/bash

:<<!
分别使用for循环和while循环
计算从1到控制台参数的累加之和
例如,控制台输入100,则计算从1-100之和
!

#使用for循环
SUM1=0
for ((i=0;i<=$1;i++))
do
    SUM1=$[$SUM1+$i]
done
echo SUM1=$SUM1

#使用while循环
SUM2=0
j=1
while [ $j -le $2 ]
do
    SUM2=$[$SUM2+j]
    j=$[$j+1]
done
echo SUM2=$SUM2

 

控制台交互

1. read关键字

read [-p 提示信息] [-t 等待时间] 参数

其中,-p后面接提示信息,显示在控制台;-t后面接等待时间(单位是秒),超过这个时间没有响应则自动退出;参数是用来接收用户在控制台输入的值的变量名。

2. 使用示例

#/bin/bash

#提示用户输入一个数字,然后打印到控制台
read -p "请输入一个数字" A
echo 您输入的数字是: $A


#提示用户输入一个数字,然后打印到控制台,最多等待5秒
read -p "请在5秒钟之内输入一个不等于零的数" -t 5  B
if [ $B -ne 0 ]
then echo 您输入的数字是:$B
else echo 输入无效
fi

 

shell函数

shell编程跟其他编程语言一样,也有函数(Java中叫方法)。shell函数分为系统函数和自定义函数,跟变量一样,系统函数是linux系统已经定义好的,我们可以直接拿来用;自定义函数需要自己先定义,再调用。

1. basename函数

basename 全路径 [后缀]

basename是一个系统函数,用于返回文件名,即最后一个/后面的部分,如果加了中括号内的后缀,表示连后缀也去掉。例如

#!/bin/bash

#返回一个全路径的文件名
basename /home/dubhlinn/shell/aaa.sh

#返回一个全路径的文件名,去掉后缀
basename /home/dubhlinn/shell/aaa.sh .sh

2. dirname函数

dirname 全路径

dirname也是一个系统函数,它与basename正好相反,返回的是目录名,即最后一个/之前的部分。

#!/bin/bash

#返回一个全路径的目录名
dirname /home/dubhlinn/shell/aaa.sh

3. 自定义函数的定义格式

function 函数名() {

    语句;

    [return 返回值;]

}

4. 自定义函数的调用格式

函数名 参数

5. 自定义函数使用示例

#!/bin/bash

:<<!
定义一个函数,求两个参数之和
!

#定义函数
function getSum() {
    SUM=$[$A+$B]
    echo 函数调用结构为$SUM
}

#调用函数
A=5
B=6
getSum $A $B

 

posted @ 2019-07-09 21:38  西班牙乞丐  阅读(738)  评论(0编辑  收藏  举报