shell脚本

1 shell脚本概念

1.1 shell和shell脚本有什么区别

1
2
3
shell和shell脚本有什么区别?
确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。
shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。

1.2 shell脚本基本格式

1
2
3
4
5
6
7
8
9
10
11
+ 基本格式
#! /bin/bash --- #! 约定标记 --- shebang
内容
+ 后缀 --- .sh
+ 要赋予可执行权限才可正常使用

cat /etc/shells --- 查看系统还有哪些shell环境

/bin/bash --- 若命令执行失败,仍然会继续执行
/bin/sh --- 若出现命令执行失败,则会停止执行
不写shebang --- 主要根据当前用户的命令解释器来进行判定

2 案例1:脚本修改静态IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /bin/bash
cd /etc/sysconfig/network-scripts/
echo "TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=ens33
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.137.132
NETMASK=255.255.255.0
GATEWAY=192.168.137.2
DNS1=114.114.114.114
DNS2=218.85.157.99" > ifcfg-ens33
systemctl restart network
ifconfig ens33

2.1 shell变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
shell变量
变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
1.命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
2.中间不能有空格,可以使用下划线“_”。
3.不能使用标点符号。
4.不能使用bash里的关键字(可用help命令查看保留关键字)。

+ 主动设置变量
A=123 给变量A赋值123
echo $A 打印出变量A

+ 系统默认变量值
$PATH 系统环境变量
$? 返回值
$1 ... $9 --- 脚本接收参数

2.2 read交互

1
2
3
4
5
6
7
8
9
10
11
read简介
要与Linux交互,脚本获取键盘输入的结果是必不可少的。
选项:
-n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。
-N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。换行符或回车算一个字符。
-p:给出提示符。默认不支持"\n"换行,要换行需要特殊处理,见下文示例。例如,"-p 请输入密码:"-r:禁止反斜线的转义功能。这意味着"\"会变成文本的一部分。
-s:静默模式。输入的内容不会回显在屏幕上。


read -p "请输入IP地址:" IP
read -p "请输入网关地址:" GATEWAY

2.3 定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /bin/bash
cd /etc/sysconfig/network-scripts/
echo "TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=ens33
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.137.132
NETMASK=255.255.255.0
GATEWAY=192.168.137.2
DNS1=114.114.114.114
DNS2=218.85.157.99" > ifcfg-ens33
ifdown ens33
ifup ens33
ifconfig ens33
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
28
29
30
31
32
33
34
35
+ 定时任务
- crond服务
systemctl status crond 查看定时任务的状态
crontab -l 查看当前用户的定时任务
crontab -r 删除定时任务

vim /etc/crontab
* 9 * * * root /home/demo/Desktop/shangwu.sh
* 14 * * * root /home/demo/Desktop/xiawu.sh
crontab /etc/crontab //重新加载定时任务
cat /var/log/cron //定时任务日志

- 时间
minute: 表示分钟,可以是从0到59之间的任何整数。
hour:表示小时,可以是从0到23之间的任何整数。
day:表示日期,可以是从1到31之间的任何整数。
month:表示月份,可以是从1到12之间的任何整数。
week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。
command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。
- 符号
星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。
- 案例
每1分钟执行一次command
* * * * * command
每小时的第3和第15分钟执行
3,15 * * * * command
在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * command
每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * command
每个星期一的上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 command

3 案例2:存活主机探测

1
ping 192.168.137.2 -c2 -i0.5 -w1

3.1 特殊文件

1
2
3
/dev/null:在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。在程序员行话,尤其是Unix行话中,/dev/null 被称为位桶(bit bucket)或者黑洞(black hole)。空设备通常被用于丢弃不需要的输出流,或作为用于输入流的空文件。这些操作通常由重定向完成。

/dev/zero:在类UNIX 操作系统中, /dev/zero 是一个特殊的文件,当你读它的时候,它会提供无限的空字符(NULL, ASCII NUL, 0x00)。其中的一个典型用法是用它提供的字符流来覆盖信息,另一个常见用法是产生一个特定大小的空白文件。BSD就是通过mmap把/dev/zero映射到虚地址空间实现共享内存的。可以使用mmap将/dev/zero映射到一个虚拟的内存空间,这个操作的效果等同于使用一段匿名的内存(没有和任何文件相关)。

3.2 if 判断语句

1
2
3
4
if 条件
then 成立语句
else 不成立语句
fi
条件 代码
-gt(greater than) 大于
-lt(less than) 小于
-eq(equal) 等于
-ne(not equal) 不等于
-le(less than or equal) 小于等于
-ge(greater than or equal) 大于等于
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /bin/bash
if [ 10 -gt 100 ]
then
echo "yes"
else
echo "no"
fi

#! /bin/bash
if `ping -c2 -i0.5 -w1 192.168.137.2 > /dev/null`
then
echo "yes"
else
echo "no"
fi
- 主要根据返回值

3.3 三种文本流

1
2
3
4
5
6
7
8
文件描述符0(stdin):
文件描述符0是进程的标准输入,通常用于读取用户的输入。默认情况下,它与终端设备(键盘)连接,可以通过键盘输入数据。程序可以使用标准输入来读取用户的命令、数据或其他输入内容。

文件描述符1(stdout):
文件描述符1是进程的标准输出,通常用于向用户显示输出信息。默认情况下,它与终端设备(显示器)连接,程序可以通过标准输出将结果、消息或其他内容输出到终端上显示给用户。

文件描述符2(stderr):
文件描述符2是进程的标准错误输出,用于输出错误消息和诊断信息。与标准输出不同的是,标准错误通常用于输出错误、警告和其他与程序执行相关的问题。默认情况下,它也与终端设备连接,与标准输出在终端上显示的方式相同。

3.4 循环语句

3.4.1 for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for 变量 in 取值列表
do
子语句
done


#! /bin/bash
for IP in {1..254}
do
if `ping -c2 -i0.5 -w1 192.168.137.$IP > /dev/null`
then
echo -e "192.168.137.$IP is \e[1;5;31mup\e[0m"
else
echo -e "192.168.137.$IP is \e[1;36mdown\e[0m"
fi
done

3.4.2 while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while 条件
do
子语句
done

#! /bin/bash
IP=0
while [ $IP -lt 254 ]
do
let IP++
if `ping -c2 -i0.5 -w1 192.168.137.$IP > /dev/null`
then
echo -e "192.168.137.$IP is \e[1;5;31mup\e[0m"
else
echo -e "192.168.137.$IP is \e[1;36mdown\e[0m"
fi
done

3.5 case选择语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case 变量 in
模式1)
子语句
;;
模式2)
子语句
;;
模式3)
子语句
;;
*)
子语句
;;
esac