写在前面
这则笔记主要整理shell脚本撰写的知识,主要包括:
shell脚本介绍
date命令
shell判断
shell循环
shell函数
shell数组
shell脚本介绍
shell脚本(shell script),是一种为shell编写的脚本程序。我们可以把需要执行的命令写在脚本当中,系统通过读取脚本执行命令。
shell脚本的特点如下;
shell是一种脚本语言;
可以使用逻辑判断、循环等语法;
可以自定义函数;
shell是系统命令的集合;
shell脚本可以实现自动化运维,能大大增加我们的运维效率;
关于shell脚本,有一些约定俗成的规矩:
脚本通常都以 .sh 作为后缀名;
注释虽然不是必须的,但为了便于后期维护和管理,强烈建议每个脚本都要写注释;
脚本建议统一放在
/usr/local/sbin/
,便于维护和管理;
shell脚本结构
一个shell脚本一般包括三个部分:
第一部分:
#!/bin/sh
,指定脚本解释器。第二部分:
#
开头的是注释。第三部分:脚本代码。
shell脚本执行方式
方式一:
1 | //更改权限 |
方法二:
1 | //执行脚本 |
shell脚本的预备知识:date
命令
date
命令 是在shell脚本当中最常用的命令,用来显示或者设置系统的日期和时间。
命令行格式: date [参数] [+格式]
参数 | 含义 |
---|---|
-d | –date=字符串:显示指定字符串所描述的时间,而非当前时间 |
-f | –file=日期文件:类似–date,从日期文件中按行读入时间描述 |
-r | –reference=文件:显示文件指定文件的最后修改时间 |
-R | –rfc-2822:以RFC 2822格式输出日期和时间 |
格式 | 含义 |
---|---|
%y | 以两位数字表示年份(00-99) |
%Y | 以四位数字表示年份 |
%m | 月份(01-12) |
%d | 按月计的日期(例如:01) |
%j | 按年计的日期(0-366) |
%c | 当前locale 的日期和时间 (如:2005年3月3日 星期四 23:05:25) |
%b | 当前locale 的月名缩写 (如:一,代表一月) |
%a | 当前locale 的星期名缩写(例如: 日,代表星期日) |
%A | 当前locale 的星期名全称 (如:星期日) |
%H | 小时(00-23) |
%M | 分(00-59) |
%S | 大写S,表示秒(00-60) |
%s | 小写s,自UTC 时间 1970-01-01 00:00:00 以来所经过的秒数 |
%w | 小写w,一星期中的第几日(0-6),0 代表周一 |
%W | 大写W,一年中的第几周,以周一为每星期第一天(00-53) |
具体用法示例:
显示时间,可以设定显示格式 date + [格式]
1 | //显示年 |
加减操作 -d
参数
1 | date +%Y%m%d //显示前天年月日 |
一天前的日期:
1 | date date -d "-1 day" +%d |
一小时前:
1 | date date -d "-1 hour" +%H |
一分钟前;
1 | date date -d "-1 min" +%M |
设定时间:-s
选项,
注:设置当前时间,只有root权限才能设置,其他只能查看
1 | date -s 20120523 //设置成20120523,这样会把具体时间设置成空00:00:00 |
编写第一个脚本
1 | cd /usr/local/sbin |
执行脚本效果
查看脚本执行过程
示例:
1 | ``` |
cat sum1.sh
#! /bin/bash //shebang
get sum of two numbers //注释:求和
m=3
n=5
sum=$[$m+$n]
echo ‘The sum is $sum.’
1 |
|
#! /bin/bash
Using ‘read’ in shell scripts
read -p “please input a number: “ x
read -p “Input another number: “ y
sum=$[$x+$y]
echo “$x + $y = $sum”1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
### 预设变量
shell变量没有数据类型的区别,变量中的值都是以字符串的形式保存的,按照使用环境大概有以下几种:
* 环境变量:用于保存操作系统运行时使用的环境参数
* 位置变量:Bash将传递给脚本的参数保存在位置变量中,以便于在脚本中引用这些参数
* 预定义变量:由系统保留和维护的一组特殊的变量,这些变量通常用于保存程序运行状态等
* 自定义变量:由用户自行定义的变量,可用于用户编写的脚本,多个命令间的值传递等
预设变量|含义
---|---
$0|保存当前程序或脚本的名称
$*|保存传递给脚本或进程的所有参数
$$|当前进程给脚本的PID号
$!|后台运行的最后一个进程的PID号
$?|用于返回上一条命令是否成功执行。如果这个变量的值为0,说明上一个命令正确执行;如果这个变量的值为非0,则说明上一个命令执行有错误
$#|用于保存脚本的参数个数
示例:
#! /bin/bash
This script contains $0
echo “$1 $2 $0” $0指的是脚本的名字
sum=$[$1+$2]
echo “$1 + $2 = $sum”
1 |
|
if 条件 ; then 语句; fi1
2
示例:
[root@local-linux01 ~]# if true; then echo ‘hello’; fi
hello1
2
3
#### 第二种形式:
if 条件;
then
语句;
else
语句;
fi1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
示例:
```shell
#!/bin/bash
# if-practice
a=2
if
[ $a -gt 3 ]
then
ehco 'A is greater than 3.'
else
echo "No, It's not true."
fi
执行效果
1 | [root@local-linux01 sbin]# bash if*.sh |
第三种形式:
1 | if 条件; |
示例:
1 | a=10 |
注意:
if 判断中,expression 和方括号([ ])之间必须有空格,否则会有语法错误;
这里的条件
[ expression ]
,其实返回的是一个布尔值,如果 expression 返回 true,then 后边的语句将会被执行;如果返回 false,就不会执行;[ ]
中不能使用<,>,==,!=,>=,<=这样的符号判断脚本最后必须以 fi 来结尾闭合 if,否则会报错。
文件目录属性判断
表达式 | 含义 |
---|---|
[ -a FILE ] | 如果 FILE 存在则为真 |
[ -b FILE ] | 如果 FILE 存在且是一个块文件则返回为真 |
[ -c FILE ] | 如果 FILE 存在且是一个字符文件则返回为真 |
[ -d FILE ] | 如果 FILE 存在且是一个目录则返回为真; |
[ -e FILE ] | 如果 指定的文件或目录存在时返回为真。 |
[ -f FILE ] | 如果 FILE 存在且是一个普通文件则返回为真。 |
[ -g FILE ] | 如果 FILE 存在且设置了SGID则返回为真。 |
[ -h FILE ] | 如果 FILE 存在且是一个符号符号链接文件则返回为真。(该选项在一些老系统上无效) |
[ -k FILE ] | 如果 FILE 存在且已经设置了冒险位则返回为真。 |
[ -p FILE ] | 如果 FILE 存并且是命令管道时返回为真。 |
[ -r FILE ] | 如果 FILE 存在且是可读的则返回为真。 |
[ -s FILE ] | 如果 FILE 存在且大小非0时为真则返回为真。 |
[ -u FILE ] | 如果 FILE 存在且设置了SUID位时返回为真。 |
[ -w FILE ] | 如果 FILE 存在且是可写的则返回为真。(一个目录为了它的内容被访问必然是可执行的) |
[ -x FILE ] | 如果 FILE 存在且是可执行的则返回为真。 |
[ -O FILE ] | 如果 FILE 存在且属有效用户ID则返回为真。 |
[ -G FILE ] | 如果 FILE 存在且默认组为当前组则返回为真。(只检查系统默认组) |
[ -L FILE ] | 如果 FILE 存在且是一个符号连接则返回为真。 |
[ -N FILE ] | 如果 FILE 存在 and has been mod如果ied since it was last read则返回为真。 |
[ -S FILE ] | 如果 FILE 存在且是一个套接字则返回为真。 |
[ FILE1 -nt FILE2 ] | 如果 FILE1 比 FILE2 新, 或者 FILE1 存在但是 FILE2 不存在则返回为真。 |
[ FILE1 -ot FILE2 ] | 如果 FILE1 比 FILE2 老, 或者 FILE2 存在但是 FILE1 不存在则返回为真。 |
[ FILE1 -ef FILE2 ] | 如果 FILE1 和 FILE2 指向相同的设备和节点号则返回为真。 |
示例:
1 | cat if-file.sh |
执行效果
1 | [root@local-linux01 sbin]# bash -x !$ |
if特殊用法
表达式 | 含义 |
---|---|
[ -z STRING ] | 如果STRING的长度为零则返回为真,即空是真 |
[ -n STRING ] | 如果STRING的长度非零则返回为真,即非空是真 |
[ STRING1 ] | 如果字符串不为空则返回为真,与-n类似 |
示例:
1 | #!/bin/bash |
执行效果
1 | [root@local-linux01 sbin]# bash -x if03.sh |
case判断
case判断有点像选择题,给你一堆选择,根据你的选择,执行不同的操作。
格式如下:
1 | case "varname" in |
注意:
case需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break.
*)
相当于其他语言中的default;除了*)
模式,各个分支中;;是必须的,;;相当于其他语言中的break;
示例:
1 | !/bin/bash |
执行效果
1 | [root@local-linux01 sbin]# bash !$ |
执行过程
1 | [root@local-linux01 sbin]# bash -x !$ |
shell循环
跟python其他的高级语言类似,shell脚本也有for循环、while循环,以及break、continue。
for循环
格式:
1 | for 变量名 in 循环条件;do |
- 示例1:
1 | !/bin/bash |
- 示例2:累加计算
1 | !/bin/bash |
- 示例3:遍历文件夹
1 | !/bin/bash |
while循环
while循环相当于一种特殊的for循环,当满足条件时,会一直执行,直到不再满足条件为止。
格式:
1 | while condition |
如果将condition改为布尔值true,就会变成无限循环,一直执行下去。格式可以写成一下三种形式:
1 | while : |
或者
1 | while true |
或者
1 | for (( ; ; )) |
- 示例1:
1 | !/bin/bash |
- Samples2:在循环过程中需要人为的输入一个数字
1 | !/bin/bash |
break跳出循环
适用场景:将判断和循环结合起来,符合某些条件时break中断循环。注:break只会影响本次循环,在有多重循环嵌套的情况,break只会影响本层级的循环,它的上层循环不受影响。
samples:
1 | !/bin/bash |
continue结束本次循环
忽略continue之下的代码,直接进行下一次循环
samples:
1 | !/bin/bash |
exit退出整个脚本
跟break不同之处,在于使用exit语句,会直接退出整个shell脚本。
samples:
1 | !/bin/bash |
注:运行exit语句,直接退出shell脚本,后面的语句都不执行。
shell中的函数
linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。
用法:
- 第一种:
1 | function function_name { |
- 第二种:
示例
samples1:定义函数打印参数
1 | #!/bin/bash |
samples2:加法函数
1 | #!/bin/bash |
samples3:显示IP
1 | #!/bin/bash |
shell中的数组
在Shell中,用括号来表示数组,数组元素用空格符号分割开。定义数组的一般形式为:
1 | array_name=(value1 value2... valuen) |
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。与C语言类似,shell数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
定义数组
- 第一种:
1 | array_name=(val0 val1 val2 val3) |
- 第二种:
1 | array_name=( |
- 第三种:也可以单独定义变量
1 | array_name[0]=value0 |
读取数组
格式为:
1 | ${array_name[index]} |
samples:
1 | #!/bin/sh |
执行效果
1 | [root@local-linux01 sbin]# bash array01.sh |
获取数组长度
示例:
执行效果
删除数组元素
1 | //删除数组 |
samples:
1 | #!/bin/sh |
执行效果
1 | [root@local-linux01 sbin]# vi array01.sh |