【运维必会】shell脚本语言入门!老男孩SRE工程师培训
老男孩IT教育
技术博客
2022年8月8日 16:41
Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具,Linux/UNIX系统的底层及基础应用软件的核心大部分涉及Shell脚本的内容。
文章目录:
- shell脚本前言
- shell脚本入门
- shell变量基础
- shell变量子串
- shell数值运算
- 条件表达式
- 流程控制语句
- shell函数
- case语句
- shell变量数组
shell脚本前言
| 为什么学习shell编程
Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具,Linux/UNIX系统的底层及基础应用软件的核心大部分涉及Shell脚本的内容
每一个合格的Linux系统管理员或运维工程师,都需要熟练的编写Shell脚本语言,并能够阅读系统及各类软件附带的Shell脚本内容
只有这样才能提升运维人员的工作效率,适应日益复杂的工作环境,减少不必要的重复工作,从而为个人的职场发展奠定较好的基础
| 学好Shell编程所需的基础知识
①能够熟练使用vim编辑器,熟悉SSH终端
②有一定的Linux命令基础,至少需要掌握80个以上Linux常用命令,并能够熟练使用它。
③要熟练掌握Linux正则表达式及三剑客命令(grep,sed,awk)
| 如何学好Shel编程
①学好Shel编程的核心:多练-->多思考-->再练-->再思考,坚持如此循环即可!
②新手大忌:不可拿来主义,可以模仿,但是要自己嚼烂了吃下去。
③格言:你觉得会了并不一定会了,你认为对的并不一定对的。
大家要勤动手,自行完成学习笔记和代码的书写。
shell脚本入门
| shell是什么?
Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出屏幕返回给用户
这种对话方式可以是:
①交互的方式:从键盘输入命令,通过/bin/bash的解释器,可以立即得到shell的回应
②非交互的方式:脚本
| Shell能做什么?
①安装操作系统:CentOS6.X和CentOS7.X 手动方式安装或克隆方式自动化安装:cobbler、kickstart 底层都是shell脚本实现
②优化SSH:关闭Selinux 优化防火墙,放行 80、443、SSH端口、zabbix监控等服务访问端口
③个人需求:加大文件描述符、时间同步、硬件时间、软件时间、YUM源等,都可以写入shell脚本
④安装服务 Nginx、Apache Tomcat、PHP、MySQL、Redis、Mongo、docker等例如:PHP5.4和PHP7.1写入shell脚本,实现自动化安装不同版本的服务
⑤代码上线:shell脚本自动化发布自动化回滚
⑥zabbix监控:硬件、软件、进程、端口号、自定义监控都可以通过shell脚本+定时任务完成
⑦日志分析日志统计:命令三剑客+定时任务+shell脚本来实现在ELK集群上的日志展示
⑧业务层面
⑨辅助开发程序:nohup和python的大量的日志处理
| 如何Shell编程
①重点掌握前面的内容:变量、判断、bash,对它们彻底理解
②先看懂,读懂shell脚本
③讲完判断,将前面学过的脚本进行完善
④自己写简单的脚本,如一些小的项目:生活中:随机点餐、大保健、会员办理,消费、服务 对应价格不同 结账 会员账号 密码 密码丢失
⑤有基本适合自己的教材,如:跟老男孩学习Shell编程或者完善的文档
⑥不能拿来及用,要搞懂、变成自己的,吸收了后可以解决企业中大部分的shell问题
一个shell脚本
# cat test.sh
#!/bin/bash
echo "Hello World!"
| 执行脚本的三种常用的方式
(1)使用bash或者sh通过解释器执行脚本
在子shell中执行命令
# sh test.sh
Hello World!
# bash test.sh
Hello World!
(2)使用路径方式
全路径执行方式或者当前路径,必须给x权限
# chmod +x test.sh
# /server/scripts/test.sh
Hello World!
# ./test.sh
Hello World!
(3)使用source或者 . 的方式
# . test.sh
Hello World!
# source test.sh
Hello World!
(4)其他shell的执行方式
# cat test.sh | bash
Hello World!
# echo ls | bash
test.sh
# bash < test.sh
Hello World!
shell变量基础
| 什么是变量
shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义,所以若要进行数学运算,必须使用一些命令例如let、declare、expr、双括号等
shell变量可分为两类:局部变量和环境变量
- 局部变量只在创建它们的shell中可用
- 环境变量则可以在创建它们的shell及其派生出来的任意子进程中使用
有些变量是用户创建的,其他的则是专用shell变量
- 变量名必须以字母或下划线字符开头,其余的字符可以是字母、数字(0~9)或下划线字符
- 变量名字是大小写敏感的,环境变量推荐设置为字母大写
- 给变量赋值时,等号周围不能有任何空白符,为了给变量赋空值,可以在等号后跟一个换行符
变量删除:用set命令可以查看所有的变量,unset var命令可以清除变量var,var相当于没有定义过
变量只读:readonly var可以把var变为只读变量,定义之后不能对var进行任何更改
对shell变量的引用方式很多,用这些方式可以方便的获取shell变量的值,变量值的长度,变量的一个字串,变量被部分替换后的值等等
| 变量值的定义
字符串定义
# name=Iamlizhenya
# name='I am lizhenya'
# name="I am lizhenya"
# echo $name
I am lizhenya
双引号和单引号的区别:双引号解析变量,单引号所见即所得不能解析变量,不加引号可以解析变量
数字的定义
# age="12 23 432"
# echo $age
12 23 432
命令的定义
通过``调用命令
# date +%F-%H-%M-%S
2022-07-07-18-02-34
# time=`date +%F-%H-%M-%S`
# echo $time
2022-07-07-18-02-40
# 时间是固定 每次调用都相同
# echo $time
2022-07-07-18-02-40
通过$()调用命令
# time=$(date +%F-%H-%M-%S)
# echo $time
2022-07-07-18-02-52
| 变量可以定义变量
# ip=`ifconfig eth0|awk 'NR==2{print $2}'`
# echo $ip
10.0.0.7
# dir=${ip}_${time}
# echo $dir
10.0.0.7_2022-07-07-18-11-34
当shell脚本中出现2条以上相同的命令就将它们写成变量
| 核心位置变量
$0 的使用
# cat test.sh
#!/bin/bash
echo $0
# sh test.sh
test.sh
# sh /server/scripts/test.sh
/server/scripts/test.sh
$0 的使用方法
在脚本给予用户提示 如何使用脚本
# cat test.sh
#!/bin/bash
echo $0
echo $"Usage: $0 {start|stop|status|restart|force-reload}"
# sh test.sh
test.sh
Usage: test.sh {start|stop|status|restart|force-reload}
$n 脚本的参数
# cat test.sh
#!/bin/bash
echo $1
# sh test.sh oldboy
oldboy
序列传参
# cat test.sh
#!/bin/bash
echo $3
# sh test.sh {a..z}
c
# sh test.sh {1..10}
3
$# 获取脚本传参的总个数
# cat test.sh
#!/bin/bash
echo $1 $2 $3
echo $#
# sh test.sh 1 2 3
1 2 3
3
# sh test.sh {1..20}
1 2 3
20
$? 获取上一条命令的返回值
# ls
# echo $?
0
# llll
# echo $?
127
案例:
# cat ping.sh
#!/bin/bash
ping -c1 -W1 $1 &>/dev/null
[ $? -eq 0 ] && echo "$1 通的" || echo "$1 不通"
# sh ping.sh www.baidu.com
www.baidu.com 通的
# sh ping.sh www.baidu.commmmmm
www.baidu.commmmmm 不通
$$ 在有多个相同名称的shell环境中使用
# cat test.sh
#!/bin/bash
echo $$ > /tmp/nginx_pid # 将当前的pid号写入文本中
| 脚本传参的三种方式
1. 直接传参
# cat test.sh
#!/bin/bash
echo $1 $2
# sh test.sh oldboy 100
oldboy 100
2. 赋值传参
# cat test.sh
#!/bin/bash
name=$1
age=$2
echo $name
echo $age
# sh test.sh oldboy 200
oldboy
200
# cat test.sh
#!/bin/bash
name=$1
age=$2
echo 姓名: $name
echo 年龄: $age
# sh test.sh oldboy 100
姓名: oldboy
年龄: 100
3. read读入
# read -p "请输入你的姓名: " name
请输入你的姓名: oldboy
# echo $name
oldboy
第一种书写方式
# cat test.sh
#!/bin/bash
read -p "请输入你的姓名: " name
read -p "请输入你的年龄: " age
echo name=$name
echo age=$age
第二种书写方式
# cat test.sh
#!/bin/bash
read -p "请输入你的姓名和年龄: " name age
echo name=$name
echo age=$age
shell变量子串
| 子串的切片
# name=1234567
# echo ${name:2:2}
34
# echo ${name:2:3}
345
# echo ${name:2:4}
3456
| 子串的长度统计
# name=1234567
第一种统计方式:
# echo $name|wc -L
第二种统计方式:
# expr length "$name"
第三种统计方式:
# echo $name|awk '{print length}'
第四种统计方式:
# echo ${#name}
| 子串的删除(支持通配符)
# url='www.baidu.com'
1.#从前面往后删除 ## 贪婪匹配
# echo ${url#www.}
baidu.com
# echo ${url#*.}
baidu.com
# echo ${url#*.*c}
om
# echo ${url#*.*.}
com
# echo ${url##*.}
com
2.%从后面往前删除
# echo ${url%.*}
www.baidu
# echo ${url%.*.*}
www
# echo ${url%%.*}
www
| 子串的替换
格式:/替换谁/替换成谁 /// 贪婪替换
# url='www.baidu.com'
# echo ${url/w/W}
Www.baidu.com
# echo ${url//w/W}
WWW.baidu.com
# echo ${url/www/WWW}
WWW.baidu.com
# echo ${url/baidu/sina}
www.sina.com
shell数值运算
| expr 只支持整数运算
# expr 1 + 1
2
# expr 10 - 10
0
# expr 10 \* 10
100
# expr 10 / 10
1
错误运算方式:# expr 1 + 1.5
expr: non-integer argument
# expr 10 * 10
expr: syntax error
案例: 判断传入的参数是否为整数
# cat expr.sh
#!/bin/bash
read -p "请输入你的年龄: " age
expr 1 + $age &>/dev/null
[ $? -ne 0 ] && echo "请输入整数" && exit
echo $age
| $(()) 只支持整数运算
注意不要和$()冲突了 执行的命令和``相同
# echo $((10+10))
20
# echo $((10-10))
0
# echo $((10*10))
100
# echo $((10/10))
1
随机数取余数 RANDOM 0-32767之间的数字
# echo $((RANDOM%100+1))
82
| $[] 只支持整数运算
# echo $[10+10]
20
# echo $[10-10]
0
# echo $[10/10]
1
# echo $[10*10]
100
平方:# echo $[10**10]
10000000000
| let 只支持整数运算
# let a=1+1
# echo $a
2
# let a=1*10
# echo $a
10
i++
let i++ =========== let i=i+1
# let i=i+1
# echo $i
2
# let i++
# echo $i
3
直接运算 ++i i++ 相同 都是自增1
++a
# let ++a
# echo $a
1
在使用变量的情况下两个是有区别i++先赋值在运算++i 先运算在赋值
# a=1
# b=1
# let i=a++
# let c=++b
# echo $i
1
# echo $c
2
| bc 支持整数和小数运算
# echo 10+10|bc
20
# echo 10+10.5|bc
20.5
# echo 10*10.5|bc
105.0
# echo 10-10.5|bc
-.5
# echo 10/10.5|bc
0
| awk 支持整数和小数运算
# awk 'BEGIN{print 10+10}'
20
# echo 10 20|awk '{print $1+$2}'
30
# echo 10 20|awk '{print $1*$2}'
200
# echo 10 20|awk '{print $1/$2}'
0.5
# echo 10 20|awk '{print $1^$2}'
100000000000000000000
条件表达式
| 文件表达式
语法结构:
第一种:
test -f /etc/hosts
# test -f /etc/hosts && echo "文件存在"
文件存在
# test -f /etc/host && echo "文件存在"
# test -f /etc/host && echo "文件存在" || echo "文件不存在"
文件不存在
# test -f /etc/hosts && echo "文件存在" || echo "文件不存在"
文件存在
第二种: 常用
# [ -f /etc/passwd ] && echo "文件存在" || echo "文件不存在"
文件存在
# [ -f /etc/passwdddd ] && echo "文件存在" || echo "文件不存在"
文件不存在
# [ -d /etc/passwd ] && echo "文件存在" || echo "文件不存在"
文件不存在
# [ -d /etc/ ] && echo "文件存在" || echo "文件不存在"
文件存在
# [ -x /etc/ ] && echo "文件存在" || echo "文件不存在"
文件存在
# ll -d /etc
drwxr-xr-x. 79 root root 8192 Oct 19 09:14 /etc
# [ -e /etc/ ] && echo "文件存在" || echo "文件不存在"
文件存在
# [ -w /etc/hosts ] && echo "文件存在" || echo "文件不存在"
文件存在
注意: 表达式中支持变量和命令
# dir=/tmp
# [ -d $dir ] && echo "文件存在" || echo "文件不存在"
文件存在
# dir=/tmppppp
# [ -d $dir ] && echo "文件存在" || echo "文件不存在"
文件不存在
# ls -d /etc/sysconfig/
/etc/sysconfig/
# [ -d `ls -d /etc/sysconfig/` ] && echo "文件存在" || echo "文件不存在"
文件存在
| shell数值比较
语法结构第一种:test 整数1 比较符 整数2第二种:[ 整数1 比较符 整数2 ]
# test 10 -eq 10 && echo 成立 || echo 不成立
成立
# test 10 -ne 10 && echo 成立 || echo 不成立
不成立
# [ 10 -eq 10 ] && echo 成立 || echo 不成立
成立
# [ 10 -ne 10 ] && echo 成立 || echo 不成立
不成立
# [ 15 -ne 10 ] && echo 成立 || echo 不成立
成立
# [ 15 -gt 10 ] && echo 成立 || echo 不成立
成立
# [ 10 -ge 10 ] && echo 成立 || echo 不成立
成立
# [ 10 -le 10 ] && echo 成立 || echo 不成立
成立
支持命令
# [ 50 -gt `echo $((RANDOM%100))|tee file.txt` ] && echo "成立" || echo 不成立
成立
# cat file.txt
20
由于篇幅过长,文章分两篇进行发布,其他内容见文章链接:https://www.oldboyedu.com/blog/4348.html
