日常运维工作大部分是一些繁琐的重复的工作,每天80%的工作就是重复干昨天的事情,而且工作量还比较大, 那么摆在运维面前的选择是:
A:自己手动搞定一切
B:让机器搞定一切
shell的学习阶段:
1)能看懂shell脚本
2)能改shell脚本
3)能自己写shell脚本
4)能优化shell脚本
shell是一个程序,采用C语言编写,是用户和linux内核沟通的桥梁。它既是一种命令语言,也是一种解释器的编程语言。通过一个图表来看下shell的作用。
拓展知识:
- kernel:为软件服务,接收用户或软件指令驱动硬件,完成工作。
- shell:命令解释器。
- user:用户接口,对接用户。
- 命令行解释功能
- 启动程序
- 输入输出重定向
- 管道连接
- 文件名置换(echo /*)
- 变量维护
- 环境控制
- shell编程
shell脚本就是将完成一个任务的所有的命令按照执行的先后顺序,自上而下写入到一个文本文件中,然后给予执行权限。
shell脚本的命名:
名字要有意义;
文件要有扩展名,建议使用.sh结尾;
名字不要太长,建议30字节以内解决。
shell脚本格式:
shell脚本开头必须制定脚本运行环境以
#!
这个特殊符号组合来组成。如:#!/bin/bash
指定该脚本是运行解析由/bin/bash来完成的:
shell中的注释使用#
号
shell脚本中,最好加入脚本说明字段:
#1)定义脚本的执行环境
#!/usr/bin/bash
#2)脚本信息
#Author:bai
#Created Time:xxxx-xx-xx xx:xx
#Release:1.0
#Script Description : nginx intstall script
#4)脚本组成
#解释环境 #!/usr/bin/bash | python | perl
#注释说明
#执行代码
#5)运行脚本
#1. 给执行权限
#2. 解释器直接运行,不需要给权限
Python
vim hello.py
#!/usr/bin/env python
print ("hello world!");
注意:不要和正则表达式混淆。
~
: 家目录 # cd ~ 代表进入用户家目录
!
:执行历史变量!!
执行上一条命令
$
:变量中取内容符
+ - * %
:对应数学运算:加、减、乘、除、取余数
&
:后台执行
*
:星号是shell中的通配符,匹配所有
?
:问号是shell中的通配符,匹配除回车以外的一个字符
;
:分号可以在shell中一行执行多个命令,命令之间用分号分割
|
:管道符,上一个命令的输出作为下一个命令的输入 cat filename | grep “abc”
\
:转义字符
``:反引号,命令中执行命令。echo “today is `date +%F`”
’ ':单引号,脚本中字符串要用单引号引起来,但是不同于双引号的是,单引号不解释变量。
" ":双引号,脚本中出现的字符串可以用双引号引起来
|
:管道符在shell中使用是最多的,很多组合命令都要通过组合命令来完成输出,管道符其实就是下一个命令对上一个命令的输出做处理。
>
:重定向输入 ,覆盖原数据
>>
:重定向追加输入,在原数据的末尾添加
<
:重定向输出 wc -l < /etc/passwd
wc < test.txt :输出的是数据流
wc test.txt :输出的是文本
<<
:重定向追加输出 : ceshi /dev/abc << EOF … EOF
vim disk_partition.sh
fdisk -l
-------------------------------------------
#!/usr/bin/bash
#Author:Bai
#Created Time: yyyy-mm-dd hh:MM
#Script Description: harddisk partition script
fdisk /dev/sdb <<EOF
n
p
3
+512M
w
EOF
##作业
#4块磁盘 分两个区/盘
#所有的1区 做成一个LVM-LV100分区 全部空间 /data/lv100
#所有的2区 做成一个raid5分区 全部空间 /data/raid5
#要求开机挂载
#要求全部通过脚本来完成。
#线上案例:squid硬盘(CDN) 问题:IO瓶颈 解决:硬盘存储初始化脚本
expr
命令:只能做整数运算,格式比较古板,注意空格,必须是整数。
root@mips-01# expr 3 + 3
6
root@mips-01# expr 5 - 2
3
root@mips-01# expr 6 / 2
3
root@mips-01# expr 7 / 2
3
root@mips-01# expr 3 * 39
root@mips-01# expr 9 % 3
0
root@mips-01# expr 9 % 2
1
可以用来判断输入是否为整数:【结合$?
使用】
root@mips-01# expr 3 + 1
4
root@mips-01# echo $?
0
root@mips-01# expr 3 + 1.1
expr: 非整数参数
root@mips-01# echo $?
2
root@mips-01# expr 7 + 1 &>/dev/null ; echo $?
0
root@mips-01# expr 7 + 1.1 &>/dev/null ; echo $?
2
root@mips-01#
let
命令和expr
命令都是用来做整数运算的。
root@mips-01# let a=1+3
root@mips-01# echo $a
4
-----------------------------------------
root@mips-01# expr 3 + 1
4
还可以使用bc命令
进行整数和小数的运算
yum -y install bc
bc
[root@bogon ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
3+2
5
4+5
9
100/3
33
141*100/7966
1
4/4
1
(1+1)*3/3
2
小数计算需要设置
scale=2
100/3
33.33
计算内存使用率:
echo "当前内存使用率:`echo "scale=2;141*100/7966"|bc`%"
当前内存使用率:1.77%
使用(( ))
计算:
echo $((1+1))
2
echo $((1-1 ))
0
echo $(( 100*3/2))
150
echo $(( 100%3 ))
1
echo $(( (1+2)*3 ))
9
echo $((10**3)) #开方运算
1000
exit NUM
退出脚本,释放系统资源,NUM代表一个整数,代表返回值。NUM:1-255
一个程序需要有0个或以上输入,一个或更多输出。
功能:将内容输出到默认显示设备。
echo命令
的功能是在显示器上显示一段文字,一般起到一个提示的作用。
功能说明:显示文字。
语法:echo [-ne][字符串]
补充说明:echo会将输入的字符串送往标准输出。输出的字符串间以空白字符隔开,并在最后加上换行号。
命令选项:
-n :不要在最后自动换行
-e :若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:转义字符
\a :发出警告声;
\b :删除前一个字符;【必须在同一行的字符,配合-n
使用】
\c :最后不加上换行符号;
\f:换行但光标仍旧停留在原来的位置;
\n:换行且光标移至首行;
\r:光标移至首行,但不换行;
\t:插入tab;
\v:与\f相同;
\插入\字符;
\nnn:插入nnn(八进制)所代表的ASCII字符;
-help:显示帮助;
-version:显示版本信息;
------输出内容不换行-----------
echo -n "Login:";read
Login:root
echo -n "Date:";date +%F
Date:2022-03-04
-------让机器输出警告声-----------
echo -e "\a\a\a\a\a\a"
------输出三个换行----------------
echo -e "\n\n\n"
----------删除一个字符------------
echo -n -e "a\b"
---------写一个倒计时脚本----------
vim daojishi.sh
#!/bin/bash
for time in `seq 9 -1 0`;do
echo -n -e "\b$time"
sleep 1
done
echo
--------输出一个水果商店清 单----------
[root@bogon test]# cat fruits.sh
#!/bin/bash
echo -e "\t\t\t\tFruits Shop"
echo -e "\t1) Apple"
echo -e "\t2) Orange"
echo -e "\t3) Banana\n"
echo -n -e "你想吃什么?";read
[root@bogon test]#
执行脚本输出如下:
[root@bogon test]# sh fruits.sh
Fruits Shop
1) Apple
2) Orange
3) Banana
你想吃什么?banana
[root@bogon test]#
脚本中echo显示内容带颜色显示,echo显示带颜色,
需要使用参数-e
格式如下:
echo -e "\033[字体背景色; 文字颜色m字符串\033[属性效果m"
eg:
echo -e “\033[41;36m something here \033[0m”
其中41的位置代表底色,36的位置代表字的颜色,0的位置代表字体的样式【属性效果】
1、字的背景色和文字颜色之间是英文的""
2、文字颜色后面有一个m
3、字符串前后可以没有空格,如果有的话,输出也是同样有空格
下面是相应的字和背景颜色,可以自己来尝试找出不同颜色搭配:
字的颜色范围:30-37【黑、红、绿、黄、蓝、紫、天蓝、白】
字的背景色范围:40-47【黑、红、绿、黄、蓝、紫、天蓝、白】
[root@bogon test]# echo -e "\033[41;36m something here \033[0m"
something here
[root@bogon test]# echo -e "\033[31m 红色字 \033[0m"
红色字
[root@bogon shell-04]# echo -e "\033[33m 黄色 \033[0m"
黄色
[root@bogon shell-04]# echo -e "\033[33m 黄色 \033[1m"
黄色
[root@bogon shell-04]# echo -e "\033[33m 黄色 \033[10m"
黄色
[root@bogon shell-04]# echo -e "\033[34m 蓝色 \033[1m"
蓝色
[root@bogon shell-04]# echo -e "\033[34m 蓝色 \033[0m"
蓝色
[root@bogon shell-04]# echo -e "\033[34m"
[root@bogon shell-04]# echo -e "\033[41;30m 红底黑色字 \033[0m"
红底黑色字
[root@bogon shell-04]# echo -e "\033[32m 绿色字 \033[0m"
绿色字
[root@bogon shell-04]# echo -e "\033[35m 紫色字 \033[0m"
紫色字
[root@bogon shell-04]# echo -e "\033[36m 天蓝字 \033[0m"
天蓝字
[root@bogon shell-04]# echo -e "\033[37m 白色字 \033[0m"
白色字
[root@bogon shell-04]#
字的背景色范围:40-47【黑、红、绿、黄、蓝、紫、天蓝、白】
最后面控制选项说明:
- \033[0m :关闭所有属性
- \033[1m :设置高亮度
- \033[4m :设置下划线
- \033[5m :设置闪烁
- \033[7m :设置反息
- \033[8m :设置消隐
- \033[9m :设置过期线
- \033[30m - \033[37m
设置前景色:
- \033[40n - \033[47m :设置背景色
- \033[nA :光标上移n行
- \033[nB :光标下移n行
- \033[nC :光标右移n行
- \033[nD :光标左移n行
- \033[x;y :设置光标位置
- \033[9m :
- \033[30m - \033[37m
默认接收键盘的输入,回车符代表输入结束
语法:
read 命令选项
- -p :打印信息
- -t :限定时间
- -s :不回显
- -n :输入字符个数
练习:模拟虚拟机的登录界面。
#!/usr/bin/bash
clear
echo -e -n "Centos Linux 7 (Core)\n"
echo -e "kernel `uname -r` an `uanme -m`\n"
echo -n -e "$HOSTNAME login:"
read acc
read -s -p "password:" pw
echo
在编程中,我们总是有一些数据需要临时存放在内存,以待后续使用时快速读出。内存在系统启动的时候被按照18个单位划分为若干个块,然后统一编号(16进制编号),并对内存的使用情况做记录,保存在内存跟踪表中。
那么问题来了,1G内存有多少个1B的单位呢?
计算机的单位:
1B = 8bit
1KB = 1024B
1M = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TP
1EB = 1024PB
1ZB = 1024EB
…
好了,已经够大了!当然还有YB、BB更大的单位,同样进制也是1024.
1G = 102410241024-10737418248
假如你将一个1B的字符存入内存,如何读出呢?有没有一种大海捞针的感觉啊!,我们讨论一下计算机是如何通过让我们人类快速将数据提取在内存,如何从内存中读取数据的。我们研究过变量后就明白了。
变量:变量时编程中最常用的一种临时在内存中取数据的一种方式。
变量存取原理:
从图片可以看出,当我们在定义变量存值的时候,可以从以下方面看到变化:
- 1)内存占用:如果存的是一个字符则占用1个字节,如果存的是字符串则是字符串的长度加1个字节长度(\0是一个特殊字符,代表字符串结束)。
- 2)变量名与内存空间关系:计算机中会将对应的内存空间和变量名称绑定在一起,此时代表这段内存空间已经被程序占用,其他程序不可复用;然后将变量名对应在对应内存地址的空间里。
**本地变量:**用户私有变量,只有用户可以使用,保存在家目录下的,bash_profile、bashrc文件中。
**全局变量:**所有用户都可以使用,保存在/etc/profile、/etc/bashrc文件中。
**临时变量:**只作用域本终端,在关闭终端界面或者关机以后就被释放。
**用户自定义变量:**用户自定义,比如脚本中的变量。
变量格式:变量名=值
在shell编程中
的变量名和等号之间不能有空格
。
变量名命名规则:
- 命名只能使用英文字母、数字和下划线,首个字符不能以数字开头。
- 变量名中间中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
VAR1=1
age=8
name=‘baism’
score=88.8
注意:字符串要用单引号或双引号引起来
定义变量演示:
[root@arm-00 ~]# age=8
[root@arm-00 ~]# name='baism'
[root@arm-00 ~]# score=88.8
读取变量内容符:$
变量内容读出:
[root@arm-00 ~]# echo $name
baism
[root@arm-00 ~]# echo $age
8
[root@arm-00 ~]# echo $score
88.8
[root@arm-00 ~]# unset name
[root@arm-00 ~]# echo $name
[root@arm-00 ~]#
一个变量只能存在一个值,但是现实中又有很多值需要存储,那么变量就有些拘谨了。比如做一个学员信息表,一个班级有50个人,每个人有6条信息,我们需要定义300个变量才能完成。恐怖,这只是一个班级的学生,一个学校呢?一个市呢?。。。
仔细想想上述的案例,一个学生有6个信息:ID、姓名、性别、年龄、成绩、班级。可不可以定义六个变量就能存储这六类信息呢?答案是肯定的。变量不行,可以用数组。
数组可以让用户一次赋予多个值,需要读取数据时只需要通过索引调用就可以方便读出了。
数组名称=(元素1 元素2 元素3 ...)
${数组名称[索引]}
索引默认是元素在数组中的排队编号,默认第一个从0开始
eg:
echo ${ARRAY1[2]}
方法一:一次赋一个值
ARRAY1[0]=‘2’
ARRAY1[1]=‘F’
ARRAY1[2]=‘4’
ARRAY1[3]=‘tom’
方法二:一次赋多个值
ARRAY1=(‘A’ ‘B’ ‘C’ ‘D’ ‘4’)
ARRAY2=(tom jack alice)
ARRAY3=(`cat /etc/passwd) 希望是将文件中的每一个行作为一个元素赋值给数组array3 ARRAY4=(\
ls /var/ftp/Shell/for*`)
ARRAY5=(tom jack alice “bash shell”)
declare -a
:可以查看声明过的数组。
[root@arm-00 test]$ declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="aarch64-redhat-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
echo ${array1[0]}
:访问数组中的第一个元素
echo ${array1[@]}
:访问数组中所有元素,等同于echo ${array1[*]}
echo ${#array1[@]}
:统计数组中的元素个数
echo ${!array2[@]}
:获取数组元素的索引
echo ${array1[@]:1}
:从数组下标1开始
echo ${array1[@]:1:2}
:从数组下标1开始,访问两个元素。
默认数组通过数组元素的个数进行遍历
echo ${array1[0]}
echo ${array1[1]}
echo ${array1[2]}
echo ${array1[3]}
方法二:
针对关联数组可以用过数组元素的索引进行遍历。
关联数组可以允许用户
自定义数组的索引
,这样使用起来更加方便、高效。
声明关联数组变量
declare -A ass_array1
declare -A ass_array2
[root@bogon shell-05]# bash declare_array.sh
baidu
30
[root@bogon shell-05]# cat declare_array.sh
#!/bin/bash
#声明一个关联数组
declare -A ass_array1
ass_array1[name]='baidu'
ass_array1[age]='30'
echo ${ass_array1[name]}
echo ${ass_array1[age]}
[root@bogon shell-05]#
方法一:一次附一个值
数组名[索引]=变量值
ass_array1[index1]=pear
ass_array1[index2]=apple
ass_array1[index3]=orange
ass_array1[index4]=peach
方法二:一次附多个值
数组名=([索引1]=变量值 [索引2]=变量值 [索引3]=变量值 [索引4]=变量值)
ass_array2=([index1]=tom [index2]=jack [index3]=java [index4]=‘bash shell’)
[root@bogon shell-05]# bash declare_array.sh
java
[root@bogon shell-05]# cat declare_array.sh
#!/bin/bash
#声明一个关联数组
declare -A ass_array2=([index1]=tom [index2]=jack [index3]=java [index4]='bash shell')
echo ${ass_array2[index3]}
[root@bogon shell-05]#
echo ${ass_array2[index2]}
:访问数组中第二个元素
echo ${ass_array2[@]}
:访问数组中所有元素,等同于echo ${array1[*]}
echo ${#ass_array2[@]}
:获得数组元素的个数
echo ${!ass_array2[@]}
:获取数组元素的索引
通过数组元素的索引进行遍历,针对关联数组可以通过数组元素的索引进行遍历
[root@bogon shell-05]# echo ${ass_array2[index4]}
bash shell
[root@bogon shell-05]# echo ${ass_array2[index3]}
java
[root@bogon shell-05]# echo ${ass_array2[index2]}
jack
[root@bogon shell-05]# echo ${ass_array2[index1]}
tom
[root@bogon shell-05]#
[root@bogon shell-05]# cat study_system.sh
#!/bin/bash
for ((i=0;i<3;i++))
do
read -p "输入第$((i + 1))个人名:" name[$i]
read -p "输入第$[$i + 1]个年龄:" age[$i]
read -p "输入第`expr $i + 1`个性别:" gender[$i]
done
clear
echo -e "\t\t\t\t学员信息查询系统"
while :
do
cp=0
read -p "输入要查询的姓名:" xm
[ $xm == "Q" ]&&exit
for ((i=0;i<3;i++))
do
if [ "$xm" == "${name[$i]}" ];then
echo "${name[$i]} ${age[$i]} ${gender[$i]}"
cp=1
fi
done
[ $cp -eq 0 ]&&echo "not fonud student"
done
[root@bogon shell-05]#