Shell脚本常用基础语法

GO

什么是shell脚本

shell脚本在Linux系统管理员的运维工作中非常重要。shell脚本并不能称之为正式的编程语言,因为它是在Linux的shell中运行的,而且它是有一些逻辑语法组合起来的命令的集合,所以称之为shell脚本很贴切。

在运维工作中,自定义的shell脚本建议都放到/usr/local/bin目录下,这样做的好处是,一来可以很方便的管理文档,二来在以后运维工作中,接管你的管理员就会知道自定义脚本都放在了哪里,方便维护。

shell脚本的创建和运行

创建一个shell脚本

vim hello.sh用编辑器vim即可创建一个空的shell脚本。在其中添加脚本内容:

1
2
3
4
5
6
#!/bin/bash
# HelloWorld!
# 创建时间:2017-09-21
date
echo "HelloWorld!"

说明:

  • shell脚本通常都是以.sh为后缀名。
  • shell脚本第一行要以#!/bin/bash#!/bin/sh开头,它俩是相同的,是链接文件。这行内容表示的是该文件使用的是bash语法。
  • #为注释符,一般在后面填写这样的注释内容:本脚本的功能,创建时间和更新时间,以及作者等相关信息。

运行一个shell脚本

运行一个脚本有两种方式:

  1. 以bash来执行这个脚本
    • # sh hello.sh
    • # bash hello.sh
    • # sh -x hello.sh-x选项用来查看shell脚本的执行过程,方便debug。
  2. 以可执行文件的方式来执行这个脚本
    • # chmod +x hello.sh 使用这种执行方式要使该脚本文件具有可执行的权限。
    • ./hello.sh或该文件的绝对路径名称。

date命令

date命令常用语shell脚本中。

该命令常用的几个选项如下:

  • date +%Y:表示以四位数字格式打印年份
  • date +%y:表示以两位数字格式打印年份
  • date +%m:表示月份
  • date +%d:表示日期
  • date +%H:表示小时
  • date +%M:表示分钟
  • date +%S:表示秒
  • date +%w:表示星期几。结果显示0则表示周日
  • date +%W:表示目前所在星期是一年中的第多少个星期

该命令在shell中最常用的几个选项如下:

  • date +%Y-%m-%d:输出四位的年月日,格式 2017-09-21
  • date +%y-%m-%d:输出两位的年月日,格式 17-09-21
  • date +%F:相当于date +%Y-%m-%d
  • date +%H:%M:%S:输出时间,格式 16:22:30
  • date +%T:等同于上面
  • date +%s:时间戳
  • date -d @时间戳:根据时间戳反推出时间
  • date -d "+1 day" +%d:一天后
  • date -d "-1 day" +%d:一天前
  • date -d "-1 hour" +%H:一个小时前
  • date -d "-1 month" +%m:一个月前
  • date -d "-1 min" +%M:一分钟前

shell脚本中的变量

自定义变量

变量的定义和使用

定义变量的格式为:变量名=变量的值
使用变量时需要在变量前面加上这个符号$

变量的常用用法

反引号的使用

使用反引号,可以将一条命令的执行结果赋值给一个变量,如:

1
2
d1=`date +F%T`
echo "$d1"

数学运算

shell脚本中变量的数学运算有两种方式,如下:

  1. c=$[$a+$b]
  2. c=$(($a+$b))

但是,shell脚本默认是不支持小数的,如果我们需要用到小数,比如保留两位小数点时,我们可以这样来实现:
# echo "scale=2;10/3" | bc

和用户交互

read命令用于和用户交互,它把用户输入的字符串作为变量值。常用格式为:read "提示的内容:" 变量名

示例脚本如下:

1
2
3
4
5
6
7
8
9
#!/bin/bash
## Using 'read' in shell script.
## Theshu 2017-09-21
read -p "Please input a number: " x
read -p "Please input another number: " y
sum=$[$x+$y]
echo "The sum of two numbers is: $sum"

预设变量

在shell脚本执行时,后面可以跟一个或多个参数。在shell中有一些预设的变量可以表示这些参数(这些预设的变量从理论上看是没有限制的)。

常用的几个预设变量如下:

  • $#:表示总共有几个参数
  • $0:表示命令或脚本名本身
  • $1:表示后面跟的第一个参数
  • $2:表示后面跟的第二个参数
  • $n:表示后面跟的第n个参数

示例脚本如下:

1
2
3
4
5
6
#!/bin/bash
# use $1 and $2
# Theshu 2017-09-21
sum=$[$1+$2]
echo "sum=$sum"

shell脚本中的逻辑判断

if 语句

if语句常用于判断某些条件满足时执行哪些语句,不满足时又执行哪些语句。其格式有以下三种。

不带else的if语句

格式如下:

1
2
3
4
if 判断语句
then
command
fi

带有else的if语句

格式如下:

1
2
3
4
5
6
if 判断语句
then
command1
else
command2
fi

带有elif的if语句

格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
if 判断语句1
then
command1
elif 判断语句2
then
command2
......
elif 判断语句n
then
command(n)
else
command(n+1)

case 语句

当有多个判断条件时,除了用带有elif的if语句外,还可以用case语句来实现。

格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
case 变量 in
value1)
command1
;;
value2)
command2
;;
......
valuen)
command(n)
;;
*)
command(n+1)
;;
esac

条件表达式(即判断语句)

一个特殊的条件表达式:

  • :表示条件为真

((条件表达式))来表示判断语句

这种格式在判断数值大小时最为方便,比如:
(($a > 60))

在这种格式下,可以用<、<=、>、>=、==、!=这些数学符号。

[[ 条件表达式 ]]条件表达式来表示判断语句

这种格式在判断小数值的大小时最为方便,比如:
[[ $a > 1.5 ]]

[ 条件表达式 ]来表示判断语句

这种格式最为常用,但是这种格式下,不能用那些数学符号来表示数值关系了(除==外)。

在这种格式下,常用的判断符号有:

  • 判断数值大小
    • -lt:小于
    • -gt:大于
    • -le:小于等于
    • -ge:大于等于
    • -eq:等于(也可以使用==)
    • -ne:不等于
  • 判断属性的符号
    • -e:判断文件或目录是否存在
    • -d:判断是不是目录以及是否存在
    • -f:判断是不是普通文件以及是否存在
    • -r:判断是否有读权限
    • -w:判断是否有写权限
    • -x:判断是否有执行权限
    • -z:判断某个变量是否为空
    • 使用if判断时具体的格式如下(例子):
      1
      2
      3
      4
      if [ -e filename ]
      then
      command
      fi

说明:

  • shell脚本中的语句可以以分号结尾,也可以不用分号,不用分号时以换行符结尾
  • [ 条件表达式 ]这种格式中,中括号和条件表达式之间有空格
  • 条件表达式中,变量名用双引号括起来更加准确,变量名和判断符号之前也要有空格

逻辑运算符

逻辑运算符用于判断条件与条件之间的关系。有下面三个:

  1. &&:表示并且的意思
  2. ||:表示或者的意思
  3. !:表示非的意思

常用格式:

1
2
3
4
5
[ 条件表达式1 ] && [ 条件表达式2 ]
[ 条件表达式1 ] || [ 条件表达式2 ]
((条件表达式1)) && ((条件表达式2))
((条件表达式1)) || ((条件表达式2))
[ ! 条件表达式 ] 表示不满足该条件时

shell脚本中的循环

for循环

for循环结构是在日常工作中使用最频繁的循环结构。其格式为:

1
2
3
4
for 变量名 in 循环的条件
do
command
done

说明:

  • 循环的条件,可以是一组字符或者数字(用一个或多个空格隔开),也可以是一条命令的执行结果(用反引号把命令括起来,如`seq 1 5`表示从1到5的一个序列)。

示例脚本如下(打印出1到5的数字):

1
2
3
4
5
6
7
#!/bin/bash
## use for
for i in `seq 1 5`
do
echo $i
done

while循环

while循环常用于编写死循环的脚本,用于监控某项服务。其格式为:

1
2
3
4
while 条件
do
command
done

示例脚本如下:

1
2
3
4
5
6
7
8
#!/bin/bash
a=5
while [ $a -ge 1 ]
do
echo $a
a=$[$a-1]
done

另外可以用一个冒号代替循环条件,表示真,这样可以做到死循环。示例脚本如下:

1
2
3
4
5
6
#!/bin/bash
while :
do
sleep 3
done

select循环

select也是循环的一种,它比较适合在用户选择的情况下。接下来我们用一个例子来说明它的用法。

一个例子

比如,我们有这样一个需求,运行脚本后,让用户去选择数字,选择1运行w命令,选择2运行top命令,选择3运行free命令,选择4退出。脚本这样实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
echo "Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit"
echo
select command in w top free quit
do
case $command in
w)
w
;;
top)
top
;;
free)
free
;;
quit)
exit
;;
*)
echo "Please input a number:(1-4)."
;;
esac
done

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# sh select.sh
Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit
1) w
2) top
3) free
4) quit
#? 1
19:41:01 up 13 min, 1 user, load average: 0.00, 0.01, 0.04
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.0.100 19:30 5.00s 0.04s 0.00s w
#? 3
total used free shared buff/cache available
Mem: 2032156 109500 1791200 8748 131456 1765448
Swap: 4194300 0 4194300
#? 4
#

说明:

  • select默认会把序列号对应的命令列出来,每次输入一个数字,则会执行相应的命令,命令执行完后并不会退出脚本。它会继续让我们再次输入序号。
  • 序号前面的提示符,我们是可以修改的,利用变量PS3即可。

例子改版1

利用PS3变量定义序号前的提示符,修改脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
PS3="Please select a number:"
echo "Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit"
echo
select command in w top free quit
do
case $command in
w)
w
;;
top)
top
;;
free)
free
;;
quit)
exit
;;
*)
echo "Please input a number:(1-4)."
;;
esac
done

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# sh select2.sh
Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit
1) w
2) top
3) free
4) quit
Please select a number:1
19:52:07 up 24 min, 1 user, load average: 0.00, 0.01, 0.04
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.0.100 19:30 7.00s 0.07s 0.00s w
Please select a number:3
total used free shared buff/cache available
Mem: 2032156 109496 1791192 8748 131468 1765444
Swap: 4194300 0 4194300
Please select a number:4
#

例子改版2

如果想要脚本每次输入一个序号后就自动退出,则需要再次更改脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
PS3="Please select a number:"
echo "Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit"
echo
select command in w top free quit
do
case $command in
w)
w;exit
;;
top)
top;exit
;;
free)
free;exit
;;
quit)
exit
;;
*)
echo "Please input a number:(1-4).";exit
;;
esac
done

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
# sh select3.sh
Please chose a number, 1:run w, 2:run top, 3:run free, 4:quit
1) w
2) top
3) free
4) quit
Please select a number:1
19:55:14 up 27 min, 1 user, load average: 0.08, 0.03, 0.04
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.0.100 19:30 2.00s 0.08s 0.00s w
#

shell脚本中的函数

在shell脚本中也可以使用函数,包括自定义的函数。其格式如下

1
2
3
4
5
function 函数名()
{
command1
command2
}

示例脚本如下:

1
2
3
4
5
6
7
8
9
#!/bin/bash
function sum()
{
sum=$[$1+$2]
echo $sum
}
sum $1 $2

说明:

  • 函数必须定义在前,使用在后

shell脚本中的控制语句

  1. break语句:break用于结束本层循环
  2. continue语句:continue忽略continue之下的代码,直接进行下一次循环
  3. exit语句:exit 数值用于结束脚本的执行,并向系统返回后面的数值

shell脚本中的数组

关于shell脚本中的数组了解即可,因为它不常用。在平时的运维工作中,几乎用不到。但是这个概念还是需要了解一下。

数组定义

一对圆括号表示是数组,数组元素用”空格”符号分隔开。

1
2
3
# a=(1 2 3 4 5)
# echo $a
1

说明;

  • 数组名代表的是数组的首个元素

数组读取

  • 获取数组元素的个数:

    1
    echo ${#a[@]}
  • 读取数组中的某一个元素,数标从0开始,a[0]是第一个元素:

    1
    echo ${a[2]}
  • 打印整个数组的元素:

    1
    2
    3
    echo ${a[*]}
    或者
    echo ${a[@]}

数组赋值

1
2
3
4
5
6
# a[1]=100
# echo ${a[*]}
1 100 3 4 5
# a[5]=100
# echo ${a[*]}
1 100 3 4 5 100

说明:

  • 直接通过数组名[下标]就可以对其进行赋值
  • 如果下标不存在,自动添加一个新的数组元素

数组的删除

1
2
3
4
5
6
7
8
9
# a=(1 2 3 4 5)
# unset a
# echo ${a[*]}
# a=(1 2 3 4 5)
# unset a[1]
# echo ${a[*]}
1 3 4 5
# echo ${#a[*]}
4

数组分片

1
2
3
4
5
# a=(`seq 1 5`)
# echo ${a[@]:0:3} //表示从a[0]开始,依次向后输出3个元素
1 2 3
# echo ${a[@]:1:4} //表示从a[1]开始,依次向后输出4个元素
2 3 4 5

数组替换

可用echo替换(并非真正的改变值):

1
2
3
4
5
# a=(1 2 3 4 5)
# echo ${a[@]/3/100}
1 2 100 4 5
# echo ${a[@]}
1 2 3 4 5

可用赋值的方式来替换

1
2
3
# a=(${a[@]/3/100})
# echo ${a[@]}
1 2 100 4 5

Shell脚本技巧

使用 exec 重定向输出

使用exec可以把脚本中exec下面所用到的全部的命令重定向到某一个指定的文件。使用示例如下:

1
2
3
4
5
6
7
#!/bin/bash
d=`date +%F`
exec > /tmp/$d.log 2>&1
echo "Begin at `date`"
ls /tmp/jlkfsksd
cd /sdfsdfas/
echo "End at `date`"

这样的话在运行脚本的时候,屏幕上没有任何的信息输出,但是其全部信息都重定向到了指定的文件中了,可在相关文件中查阅。

case 结构中的条件

1
2
3
4
5
6
7
8
9
10
case n in
1|2)
command1
;;
3|4)
command2
;;
*)
command3
;;

如上,在右半括号之前可以写多个条件,用或字符分割,这样可以达到满足多个条件时执行相同的下一步。

OK

0%