shell
为什么要用shell?
1.---
安装操作系统(CentOS)自动化安装操作系统(kickstart cobbler)底层shell
2.--- 初始化、优化操作系统
1)ntp时间同步
2)更改默认yum源
3)ssh优化
4)关闭Selinux
5)关闭/开启 防火墙(C6:iptables C7:firewalld)
6)安装基础服务(wget vim lrzsz net-tools unzip gzip...)
7)优化文件描述符
8)优化字符集
0)。。。
3.--- 安装服务
1)Nginx
2)PHP
3)MySQL
4)Redis
5)MHA
6)Rsync
7)NFS
8)MongoDB
9)Zabbix
...
4.--- 启动服务(系统默认的shell脚本)
5.--- 脚本实现自动化代码上线
6.--- 监控服务(使用shell)
7.--- 结合定时任务使用shell
8.--- 重复性工作写入脚本
1)日志切割
2)日志分析
3)数据统计
4)机器巡检
5)数据备份
...
shell编程和基础知识
1)熟练使用vim编辑器
2)熟悉ssh终端(Xshell、CRT)
3)熟练掌握linux常用命令
4)熟练掌握linux正则表达式及三剑客命令
学习shell三部曲
先读懂shell
再修改shell
自己写shell
什么是shell?
##### 交互式shell #####
交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。
##### 非交互式shell #####
shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。
shell脚本的执行方式
## 需要加上执行权限x 可以直接执行
./1.sh
## 正常执行
sh 1.sh
bash 1.sh
. 1.sh
source 1.sh
## 区别 ##
使用sh 1.sh和bash 1.sh在新的子Shell中执行脚本,当前Shell环境不受影响。
使用. 1.sh和source 1.sh在当前Shell中执行脚本,当前Shell环境会被脚本中的变化影响。
[root@GIAO ~]# cat 1.sh
#!/bin/bash
cd /tmp && ls -l
[root@GIAO ~]# sh 1.sh
total 0
drwx------. 2 root root 6 Jul 3 09:37 vmware-root_657-4022112241
[root@GIAO ~]# . 1.sh
total 0
drwx------. 2 root root 6 Jul 3 09:37 vmware-root_657-4022112241
shell的脚本规范
1.目录统一
2.shell脚本的结尾要以.sh结尾
3.脚本的开头需要有解释器
#!/bin/bash
4.脚本中需要有作者信息
#!/bin/bash
#Author: _DriverL_
#Date: _1999-12-21_
#Name: _Print Message_
5.必须要加注释(开发规范,运维规范...)
6.shell中的文字尽量使用英文
7.成对的符号和语句一次性书写完
什么是shell脚本
# 1.首先先编辑一个模板文件,该模板文件可以叫任何名字
[root@zabbix01 ~]# vim /usr/share/vim/vimfiles/template.zls
#!/bin/bash
# 2.写完之后,我们需要修改一下vim的配置文件
[root@zabbix01 ~]# vim /etc/vimrc
autocmd BufNewFile *.spec 0r /usr/share/vim/vimfiles/template.spec
## 在第28行,autocmd自动保存模板文件,修改一下,因为我们是要写shell脚本的模板
## 所以我们要把*.spec 修改成*.sh
## 然后将后面的模板文件改成你定义的模板文件名
autocmd BufNewFile *.sh 0r /usr/share/vim/vimfiles/template.zls
# 3.接下来,我们编辑所有只要以sh结尾的文件,都会带有作者信息
[root@zabbix01 ~]# vim test_zls.sh
####################### 华丽的分割线 ########################
给你们介绍一个更牛逼的东西,叫做vimscript,专门的vim脚本语法。
我们可以完全自定义,上面那个模板不识别变量,你写啥就是啥。
接下来我们自己写一个,因为我要获取日期,上面的模板还得我们手动添加。
所以我就简单研究了一下vimscript里面的函数,吭哧瘪肚的写出来下面的内容
vim ~/.vimrc
autocmd bufNewFile *.py,*.sh,*.java exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1, "#!/bin/bash")
call setline(2, "# File Name: ".expand("%"))
call setline(3, "# Version: v1.1 ")
call setline(4, "# Author: DriverZeng")
call setline(5, "# Mail: [email protected] ")
call setline(5, "# Domain: www.oldboydeu.com ")
call setline(6, "# Date Time: ".expand(strftime("%Y-%m-%d %H:%M")))
endif
endfunc
autocmd bufNewFile *.py,*.sh,*.java exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1, "#!/bin/bash")
call setline(2, "")
call setline(3, "# File Name: __".expand("%") . "__")
call setline(4, "# Version: __v1.1__ ")
call setline(5, "# Author: __DriverZeng__ ")
call setline(6, "# Mail: [email protected]__ ")
call setline(7, "# Blog: __https://blog.driverzeng.com__ ")
call setline(8, "# DateTime: __".expand(strftime("%Y-%m-%d %H:%M")) .
"__")
endif
endfunc
如果想要学习vimscript编程,请前往:WC3School一个很牛逼的网站,前端语言,后端语言,都可以学习。
开发语言中程序代码的分类
解释型
脚本在运行时解释器逐行解释并执行
编译型
源代码在运行之前先经过编译器的编译过程
生成二进制的代码
生成完再运行
# 编译型
vim hello.c
#include <stdio.h>
void main(){
printf("hello world");
}
# 编译成二进制文件
gcc hello.c -o hello.bin
# 执行脚本
[root@m01 scripts]# ./hello.bin
hello world
变量
变量介绍
变量即变化的量,核心是“变”与“量”二字,变即变化,量即衡量状态。
name=zls
age=18
例如:
1.在游戏中,英雄的等级为1,打怪升级(变)10级
2.游戏中人物名字:Driver_Zeng,使用了改名卡,变为:曾老湿
3.植物大战僵尸:僵尸的存活状态为True,被植物打死了,变为False
变量的使用
vim test.sh
#!/bin/bash
name=zls
age=18
echo $name
echo $age
[root@m01 ~]# sh test.sh
zls
18
name = lisi
变量名 赋值符号 变量值
定义变量的语法(分三部分):
1)变量名
相当于一个门牌号,便于取出变量值,是访问到值的唯一方式
2)赋值符号
将值的内存地址,绑定给变量名
3)变量值
用来表示状态
变量的使用规则:先定义,在通过变量名去引用。
变量的规范
1.大前提:变量名的命名应该能够反映出值记录的状态。
2.变量名只能是 字母、数字或下划线的任意组合(区分大小写)
#!/bin/bash
x=1
X=2
echo $X
2.变量名的第一个字符不能是数字
[root@m01 scripts]# cat 4.sh
#!/bin/bash
1x=1
1X=2
echo $1X
[root@m01 scripts]# sh 4.sh
4.sh: line 2: 1x=1: command not found
4.sh: line 3: 1X=2: command not found
X
尽量不要使用命令设置变量
定义变量名的方式
### 1.下划线(纯小写)
#!/bin/bash
stu_name=zhangsan
echo $stu_name
### 2.驼峰体
#!/bin/bash
Stu_Of_Name=zhangsan
echo $Stu_Of_Name
3.不好的方式
1)变量名为中文、拼音
2)变量名过长
3)变量名词不达意
变量的分类
###### 环境变量 ####
# 查看方式
env
declare
export
# 重点记住
LANG # 当前系统使用的语言
PATH # 记录可执行文件的路径
PS1 # 记录命令提示符的格式
UID # 记录当前登录用户的uid
HOSTNAME # 记录当前主机名
# 了解历史相关变量
HISTSIZE # 历史记录能记录1000条
HISTFILESIZE # 历史记录文件能记录1000条
HISTFILE # 历史命令记录的文件路径和文件名
TMOUT # 设置超时时间 如果一定的时间内没有操作就会退出登录 /etc/profile source
HISTCONTROL: export HISTCONTROL=ignorespace # 离职专用变量 任何命令前面加上空格都不
会被history记录 /etc/profile source
PROMPT_COMMAN # 跳板机专用变量 记录上一条命令
特殊变量-位置
符号 |
含义 |
应用 |
$0 |
脚本名字 |
脚本使用方法常用:给出错误提示或者使用帮助 |
$n |
脚本的第n个参数 |
命令传参,传递给脚本,在脚本中使用 |
$# |
传递给脚本的参数个数 |
判断脚本是否传参 |
$* |
获取脚本所有的参数 |
将所有参数当成是一个整体,对传递的参数进行判断 |
$@ |
获取脚本中所有的参数 |
将每一个参数当成是一个整体,对传递的参数进行判断 |
$0
记录脚本名称
$n
#!/bin/bash
echo $1
echo $2
echo $3
[root@m01 ~]# sh 1.sh 1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
[root@m01 ~]# sh 1.sh a b c d e f g h i j k l
a b c d e f g h i a0 a1 a2
# 规范书写
#!/bin/bash
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12}
# $@ 和 $*的区别
#!/bin/bash
echo '$@输出结果如下'
for num1 in "$@";do
echo $num1
done
echo '$*输出结果如下'
for num2 in "$*";do
echo $num2
done
特殊变量-状态
符号 |
含义 |
应用 |
$? |
上一条命令的返回值 |
判断命令执行的是否成功 |
$$ |
当前脚本允许的pid |
在脚本允许时将pid记录到文件中,方便kill |
$! |
上一个运行脚本的pid |
|
$_ |
上一个命令或者脚本的最后一个参数 |
类似于esc + . |
# $?
作用上一条命令的返回值
注意点:并不是所有的命令成功执行都为0
# 另类
false
diff
变量子串(复杂,但实用)
这个东西,怎么说呢,比较复杂,不容易学懂,比较高级,很实用,但是不用行不行呢,有些时候可以用其他命令来代替,有些时候,就够呛了。当然,如果学不会这个,使用其他命令也可以,比如sed 、awk 、grep这几个组合也能实现功能,但是效率肯定没有直接使用子串的效率高。
语法 |
含义 |
${变量名} |
调用变量 |
${#变量名} |
变量的长度 |
${变量名:offset} |
截取变量,从offset之后 |
${变量名:offset:length} |
截取变量,从offset之后取指定长度 |
${变量名#word} |
从变量开头,删除最短匹配word的子串 |
${变量名##word} |
从变量开后,删除最长匹配的word子串 |
${变量名%word} |
从变量结尾,删除最短匹配的word的子串 |
${变量名%%word} |
从变量结尾,删除最长匹配的word的子串 |
${变量名/pattern/string} |
使用string替换第一个pattern |
${变量名//pattern/string} |
使用string替换全局的pattern |
# ${变量名}------------调用变量
[root@m01 ~]# cat 1.sh
#!/bin/bash
num=$1
echo ${num}
# ${#变量名}----------统计变量长度
[root@m01 ~]# cat 1.sh
#!/bin/bash
num=$1
echo ${#num}
[root@m01 ~]# sh 1.sh 123456
6
[root@m01 ~]# sh 1.sh 1234567
7
[root@m01 ~]# sh 1.sh 12345678
8
# ${变量名:偏移量:步长} ------ 取变量中的n位字符
[root@m01 ~]# cat 1.sh
#!/bin/bash
geming='xiangtianjie500'
echo ${geming}
echo ${geming:4:2}
[root@m01 ~]# sh 1.sh
xiangtianjie500
gt
[root@m01 ~]# vim 1.sh
[root@m01 ~]# sh 1.sh
xiangtianjie500
gti
# ${变量名#字符串} ------ 从变量开头,删除最短匹配word的子串
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/fff
echo ${baby#*/}
[root@GIAO ~]# sh 6.sh
bbb/ccc/ddd/eee/fff
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/fff
echo ${baby#*ccc/}
[root@GIAO ~]# sh 6.sh
ddd/eee/fff
# ${变量名##字符串} ------ 从变量开头,删除最长匹配word的子串
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/fff
echo ${baby##*/}
[root@GIAO ~]# sh 6.sh
fff
# ${变量名%字符串} ------ 从变量结尾,删除最短匹配的word的子串
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/fff
echo ${baby%/ddd*}
[root@GIAO ~]# sh 6.sh
aaa/bbb/ccc
# ${变量名%%字符串} ------ 从变量结尾,删除最长匹配的word的子串
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/fff
echo ${baby%%/*}
[root@GIAO ~]# sh 6.sh
aaa
# ${变量名/原内容/替换内容} ------ 使用string替换第一个pattern
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/ff/aaa/ccc/dddaaa
echo ${baby/aaa/ggg}
[root@GIAO ~]# sh 6.sh
ggg/bbb/ccc/ddd/eee/ff/aaa/ccc/dddaaa
# ${变量名//原内容/替换内容} ------ 使用string替换所有的pattern
[root@GIAO ~]# cat 6.sh
#!/bin/bash
baby=aaa/bbb/ccc/ddd/eee/ff/aaa/ccc/dddaaa
echo ${baby//aaa/ggg}
[root@GIAO ~]# sh 6.sh
ggg/bbb/ccc/ddd/eee/ff/ggg/ccc/dddggg
[root@GIAO ~]#
拓展变量
写法 |
含义 |
${parameter:-string} |
如果parameter没被赋值或其值为空,就以string作为默认值 |
${parameter:=string} |
如果parameter没被赋值或其值为空,就以string作为默认值,并将string赋值给parameter |
${parameter:?string} |
如果parameter没被赋值或其值为空,就以string作为错误输出,否则显示parameter内容 |
${parameter:+string} |
如果parameter没被赋值或其值为空,就什么都不做,否则用string替换变量内容 |
# ${变量名:-字符串}
# 如果parameter没被赋值或其值为空,就以string作为默认值
echo ${name:-haha}
# 前提是如果parameter没被赋值或其值为空
[root@m01 ~]# echo $name
[root@m01 ~]# echo ${name:-haha}
haha
# 前提该变量名已经被赋值 则无法将string作为他的默认值
[root@m01 ~]# name=xxx
[root@m01 ~]# echo $name
xxx
[root@m01 ~]# echo ${name:-haha}
xxx
# ${变量名:=字符串}
# 如果parameter没被赋值或其值为空,就以string作为默认值,并将string赋值给parameter
[root@m01 ~]# echo $name
[root@m01 ~]# echo ${name:=haha}
haha
[root@m01 ~]# echo ${name:=haha}
haha
[root@m01 ~]# echo $name
haha
# ${变量名:?字符串}
# 如果parameter没被赋值或其值为空,就以string作为错误输出,否则显示parameter内容
[root@m01 ~]# echo ${name:?haha}
-bash: name: haha
[root@m01 ~]# echo $?
1
[root@m01 ~]# name=xxx
[root@m01 ~]# echo ${name:?haha}
xxx
# ${变量名:+字符串}
# 如果parameter没被赋值或其值为空,就什么都不做,否则用string替换变量内容
[root@m01 ~]# name=xxx
[root@m01 ~]# echo ${name:+haha}
haha
[root@m01 ~]# echo $name
xxx