shell编程

知识体系说明

工作、面试:

配合定时任务执行备份 检查

监控系统:自定义监控(只要能通过命令/脚本取出来的内容 就可以监控)

服务管理脚本:sersync 编译安装的软件 systemctl start|stop|network network

批量维护与管理

shell入坑指南

linux半边天

要求能力:

1. 熟练使用70-80个常见命令
2. 正则与三剑客
3. vim 快捷键 https://www.jianshu.com/p/c5e6724f4c3d
4. 掌握:根据需求 书写脚本能力

如何入坑:

书写建议

把需求拆分 3步或更多

分析每个步骤 给出每个步骤使用的命令 或语法 测试成功

每个步骤ok, 书写合并脚本

测试

学习建议

尽量分析 系统脚本(想得多) 别人发出来的脚本 读懂。

后面模仿

shell基础规则与习惯

基础规则- 执行脚本

#方法1 sh ※※※※※※
[root@manager /server/scripts]# sh 2.3-1-exec.sh
tar: 从成员名中删除开头的“/”
#方法2 .或source  
[root@manager /server/scripts]# . 2.3-1-exec.sh 
tar: 从成员名中删除开头的“/”
#方法3 输入重定向方法
[root@manager /server/scripts]# sh <2.3-1-exec.sh 
tar: 从成员名中删除开头的“/”
[root@manager /server/scripts]# ll /tmp/etc.tar.gz 
-rw-r--r-- 1 root root 10246600 1月   8 10:51 
/tmp/etc.tar.gz
#linux 支持 < 很多 tr xargs 三剑客
#方法4 绝对路径方法
[root@manager /server/scripts]# ll 
/server/scripts/2.3-1-exec.sh
-rwxr-xr-x 1 root root 31 1月   8 10:50 
/server/scripts/2.3-1-exec.sh
[root@manager /server/scripts]# /server/scripts/2.3-1-
exec.sh 
tar: 从成员名中删除开头的“/”
执行方法应用场景
sh执行各种命令 必备
./source在脚本中调用使用其他文件方法在脚本中实现nginx include功能 , ./etc/init.d/fuctions 服务、命令检查脚本
sh <几乎不会用
绝对路径系统脚本 系统使用的脚本 需要+x权限
#./source 了解
[root@manager /server/scripts]# . 
/etc/init.d/functions 
[root@manager /server/scripts]# action "crond is 
running" /bin/true 
crond is running                                       
    [ 确定 ]
[root@manager /server/scripts]# action "crond is not 
running" /bin/false  
crond is not running                                   
    [失败]

书写shell脚本的习惯

书写脚本 加上 命令解释器 #!/bin/bash 脚本默认使用的命令解释器
#! 幻数

[root@manager /server/scripts]# head -1 /bin/yum 
#!/usr/bin/python
[root@manager /server/scripts]# file 2.3-2-checkweb.sh
  3-2-check-web.sh: UTF-8 Unicode text
[root@manager /server/scripts]# 
[root@manager /server/scripts]# file 2.3-2-checkweb.sh
2.3-2-check-web.sh: Bourne-Again shell script, UTF-8 
Unicode text executable

shell变量

普通变量(局部变量)

变量:

存放我们经常使用的内容(shell脚本中)
本质:内存中空间

空间的位置 变量名
空间的内容 变量值

变量的命名规则

不能以数字开头 最好也不要包含特殊符号 ! - 最好用_ 下划线

命名规律: 推荐 多个单词通过下划线连接 (表名变量的作用)    bingbing_age=16

驼峰写法: 多个单词从第2个单词开始 首字母大写 lidaoAge=99  numberOfPeople=61

变量赋值注意事项

[root@manager /server/scripts]# oldbing=666
[root@manager /server/scripts]# echo $oldbing
666
[root@manager /server/scripts]# oldbing=爱生活 爱冰冰
-bash: 爱冰冰: 未找到命令
[root@manager /server/scripts]# oldbing="爱生活 爱冰冰"
[root@manager /server/scripts]# echo $oldbing 
爱生活 爱冰冰
引号含义
单引号所见即所得 单引号里面内容 原封不动输出
双引号与单引号类似 解析特殊符号 `` $() !
不加引号与双引号类似 支持通配符 * {}
反引号优先执行命令

example:

[root@manager ~]# echo '$PATH $(hostname) `whoami` 
{1..5}'
$PATH $(hostname) `whoami` {1..5}
[root@manager ~]# echo "$PATH $(hostname) `whoami` 
{1..5}"
/sbin:/usr/sbin:/bin:/usr/bin manager root {1..5}
[root@manager ~]# echo $PATH $(hostname) `whoami` 
{1..5}
/sbin:/usr/sbin:/bin:/usr/bin manager root 1 2 3 4 5

环境变量(全局变量)

特点

1.Linux系统创建
2.大写
3.Linux大部分地方都可以使用

查看所有环境变量

env
export 
declare

在这里插入图片描述

创建环境变量

[root@manager ~]# oldboy=666
[root@manager ~]# echo $oldboy 
666
[root@manager ~]# env |grep oldboy 
[root@manager ~]# #export 变量 变量成为环境变量
[root@manager ~]# export oldboy=666
[root@manager ~]# env |grep oldboy 
oldboy=666

环境变量相关的文件和目录

环境变量相关文件和目录应用场景
/etc/profile别名 环境变量
/etc/bashrc别名
~/.bashrc当前用户的别名
~/.bash_profile当前用户环境变量
/etc/profile.d/目录里面的内容 .sh结尾的 会在用户登录后运行存放shell跳板机脚本存放用户行为记录脚本

在这里插入图片描述

shell特殊变量

表示位置的特殊变量

位置变量例子含义
$数字$1,$1…脚本的第1个 第2个参数
$0echo "Usage: $0{start|restart|stop}"脚本的文件名
$#脚本参数的个数 脚本一共有几个参数
$*取出脚本所有的参数
$@取出脚本所有的参数

1. $数字

#基础用法
[root@manager ~]# cat   /server/scripts/2.5-1-arg.sh
#!/bin/bash
echo $1 $2
[root@manager ~]# sh /server/scripts/2.5-1-arg.sh a b 
a b
[root@manager ~]# 
#实际案例
/etc/init.d/network  start       ===   $1=start
#进阶: 脚本有多个参数
[root@manager ~]# echo echo \${1..12}
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12
[root@manager ~]# echo echo \${1..12} >> 
/server/scripts/2.5-1-arg.sh
[root@manager ~]# cat /server/scripts/2.5-1-arg.sh
#!/bin/bash
echo $1 $2
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12
[root@manager ~]# sh /server/scripts/2.5-1-arg.sh 
{1..12}
1 2
1 2 3 4 5 6 7 8 9 10 11 12
#脚本参数超过9个 脚本参数需要使用 ${10} ${11} ※※※※※※
[root@manager ~]# cat /server/scripts/2.5-1-arg.sh
#!/bin/bash
echo ${1} ${2}
echo ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9}
${10} ${11} ${12}
[root@manager ~]# sh /server/scripts/2.5-1-arg.sh 
{a..z}
a b
a b c d e f g h i j k l
#认识 ${} $ 一致 取出变量的内容
[root@manager ~]# age=18
[root@manager ~]# echo $age
18
[root@manager ~]# echo $agesui
[root@manager ~]# echo ${age}sui
18sui
[root@manager ~]# #金庸新作
[root@manager ~]# #${金庸}新作

小结

$数字 脚本传参 命令行内容 传递到脚本的内部 /etc/init.d/network start
#脚本参数超过9个 脚本参数需要使用 ${10} ${11}
$与${}

2. $0
脚本的名字

#简单案例
[root@manager ~]# cd /server/scripts/
[root@manager /server/scripts]# sh 2.5-1-arg.sh 
2.5-1-arg.sh
[root@manager /server/scripts]# sh 
/server/scripts/../../server/scripts/2.5-1-arg.sh 
/server/scripts/../../server/scripts/2.5-1-arg.sh
#实际应用
#书写脚本   如果脚本执行出错   错误提示会使用 $0 
##usage 使用帮助 使用说明
[root@manager /server/scripts]# /etc/init.d/network 
oldboy 
Usage: /etc/init.d/network {start|stop|status|restart|force-reload}
        $0  
[root@manager /server/scripts]# sh 2.5-1-arg.sh 
2.5-1-arg.sh
Usage: 2.5-1-arg.sh {start|stop|restart}
[root@manager /server/scripts]# cat 2.5-1-arg.sh
#!/bin/bash
echo ${1} ${2}
echo ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9}
${10} ${11} ${12}
echo $0
echo "Usage: $0 {start|stop|restart}"

小结

$0 使用在 脚本遇到错误的时候 错误提示

3. $# 脚本参数的个数

#基础用法
[root@manager /server/scripts]# cat 2.5-1-arg.sh
#!/bin/bash
#echo ${1} ${2} 
#echo ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} 
${10} ${11} ${12}
#echo $0
#echo "Usage: $0 {start|stop|restart}"
echo $1 $2   $#
[root@manager /server/scripts]# sh 2.5-1-arg.sh 
0
[root@manager /server/scripts]# sh 2.5-1-arg.sh 
oldboy oldbing lidao
oldboy oldbing 3
#实际应用
##一般与 判断一起使用   如果脚本参数个数=0 ? 提示报错信息
/etc/init.d/network   
案例 : /etc/init.d/functions  
452     if [ "$#" = 0 ] ; then
453         echo "Usage: status [-p pidfile] 
{program}"
454         return 1
455     fi

小结

$# 脚本参数的个数
一般配合判断 判断脚本参数个数如果是0 提示报错信息

4. $ 与 $@*

$*取出脚本所有参数 $1 $2 $3 …$999 一般配合循环加上双引号的时候区别 : 表示1个整体 1个参数
$@取出脚本所有参数 $1 $2 $3 …$999 一般配合循环加上双引号的时候区别 : 每个参数独立

$* 和 $@区别

#set 可以设置命令行参数
[root@manager ~]# set oldboy alex 
[root@manager ~]# echo $1 
oldboy
[root@manager ~]# echo $2 
alex
# 通过set 测试 $* $@ 区别
[root@manager ~]# set oldboy oldbing   oldlidao 
oldguo  
[root@manager ~]# for n in "$*"; do echo $n; done
oldboy oldbing oldlidao oldguo
[root@manager ~]# for n in $*; do echo $n; done
oldboy
oldbing
oldlidao
oldguo
[root@manager ~]# for n in   $@ ; do echo $n; done
oldboy
oldbing
oldlidao
oldguo
[root@manager ~]# for n in   "$@" ; do echo $n; done
oldboy
oldbing
oldlidao
oldguo
# 了解: $@ "$@" 区别
[root@manager ~]# set "I am" oldboy linux teacher 
[root@manager ~]# echo $# 
4
[root@manager ~]# for n in   $@ ; do echo $n; done
I
am
oldboy
linux
teacher
[root@manager ~]# for n in   "$@" ; do echo $n; done
I am
oldboy
linux
teacher

小结

$* $@ 取出脚本所有参数 一般配合for循环使用
$* $@ 区别

5. 位置参数小结

位置变量含义应用场景
$数字脚本的第1个 第2个参数实现脚本传参/etc/init.d/network start服务管理脚本
$0脚本的名称脚本执行报错 错误提示中 使用echo "Usage: $0 start
$#脚本参数的个数 脚本一共有几个参数一般与判断一起使用 检查脚本参数个数是否为0
$*取出脚本所有的参数一般与for循环一起使用 ; 与shell数组一起使用
$@取出脚本所有的参数一般与for循环一起使用 ; 与shell数组一起使用

表示状态变量

在这里插入图片描述
1. $?

# $? 上1个命令或脚本 返回值  
#简单含义 与 应用
##0 表示成功
##非0 表示故障 失败
root@manager ~]# ls 
ansible_playbook             ansible_tasks             
student.txt
ansible-project1             ansible_variables         
yj.sh
ansible_role                 ansible_variableszip.zip
ansible_role_2019-12-23.zip ssh-key.sh
[root@manager ~]# echo $?
0
#应用
##与判断 结合 检查命令 脚本执行是否成功
#ping wget 。。。。
[ "$?" -eq 0 ]   #equal 等于   判断返回值如果是0 则xxx

小结

$? 配合判断 检查命令 脚本 执行是否成功

2. $$

# $$ 当前脚本的pid 进程id
###pid文件
[root@manager ~]# systemctl start nginx 
[root@manager ~]# 
[root@manager ~]# ps -ef |grep nginx 
root       8504      1  0 11:33 ?        00:00:00 
nginx: master process /usr/sbin/nginx
nginx      8505   8504  0 11:33 ?        00:00:00 
nginx: worker process
root       8507   7560  0 11:33 pts/0    00:00:00 grep
--color=auto nginx
[root@manager ~]# #kill 8504
[root@manager ~]# cat /run/nginx.pid 
8504
[root@manager ~]# kill `cat /run/nginx.pid`
[root@manager ~]# ps -ef |grep nginx 
root       8519   7560  0 11:35 pts/0    00:00:00 grep
--color=auto nginx
### 手动创建pid文件
[root@manager ~]# cat /server/scripts/2.5-3-pid.sh
  
#!/bin/bash
#author:oldboy lidao
echo $$
sleep 9999
[root@manager ~]# 
[root@manager ~]# sh /server/scripts/2.5-3-pid.sh
8578
[root@manager ~]# ps -ef |grep 8578
root       8578   7560  0 11:36 pts/0    00:00:00 sh
/server/scripts/2.5-3-pid.sh
root       8579   8578  0 11:36 pts/0    00:00:00 
sleep 9999
root       8581   7493  0 11:37 pts/2    00:00:00 grep
--color=auto 8578
[root@manager ~]# 
[root@manager ~]# echo oldboy 
oldboy
[root@manager ~]# echo oldboy |tee oldboy.txt
oldboy
[root@manager ~]# cat oldboy.txt 
oldboy
[root@manager ~]# #tee 多向输出 前面的信息输出屏幕 同时写入
到文件
`
[root@manager ~]# cat /server/scripts/2.5-3-pid.sh
#!/bin/bash
#author:oldboy lidao
echo $$ |tee /run/lidao.pid
sleep 9999
[root@manager ~]# sh /server/scripts/2.5-3-pid.sh
8589
[root@manager ~]# cat /run/lidao.pid 
8589

小结

$$ 在脚本中获取 脚本的pid 创建pid文件

3. 表示状态环境变量小结
在这里插入图片描述

变量子串

对变量的内容 进行 替换 删除

变量子串 parameter表示变量
基础
${parameter}取变量内容
${#parameter}统计变量的长度(多少个字符)
截取 类似cut 命令
${parameter:1}
${parameter:1:2}
删除
${parameter#word}删除
${parameter##word}
${parameter%word}
${parameter%%word}
替换
${parameter/找谁/替换为什么}
${parameter//找谁/替换为什么}

1. ${#parameter}

#基础用法
[root@manager ~]# oldboy=oldbing
[root@manager ~]# echo ${oldboy}
oldbing
[root@manager ~]# echo ${#oldboy}
7

#企业面试题
##4.3-1面试题: I am oldboy linux,welcome to our 
training. 显示这串字符中 单词字符数大于6的单词
##分析:
###1.通过for循环 取出每个单词
###2.判断 字符数 > 6 ? 
###1)大于6显示
###2)不大于 继续 读取下1个单词
[root@manager ~]# vim /server/scripts/2.5-3-word.sh
#!/bin/bash
#author oldboy lidao
str="I am oldboy linux,welcome to our training. "
for n in  $str
do
    if [ ${#n} -gt  6 ]   #great than 
    then
        echo ${#n} $n
    fi
done

[root@yida scripts]# cat test_word.sh 
#!/bin/bash
str=$(echo 'I am oldboy linux,welcome to our training.' |sed 's#[,.]# #g')
for n in $str
do
  if [ ${#n} -gt 6 ]
  then
  echo ${#n} $n
  fi
done
[root@yida scripts]# sh test_word.sh 
7 welcome
8 training

[root@manager ~]# echo I am oldboy linux,welcome to our 
training.|
> awk -vRS="[ ,.]" 'length()>6'
welcome
training

2. 变量截取

[root@manager ~]# oldboy=oldboyedu.com
[root@manager ~]# #echo ${oldboy:起始点:一共取多少个字符}
[root@manager ~]# 
[root@manager ~]# echo ${oldboy:4:3}
oye
#截取功能字符是从0开始
[root@manager ~]# echo ${oldboy:3:3}
boy
[root@manager ~]# echo ${oldboy:3}
boyedu.com

在这里插入图片描述
3. 删除

${parameter#word}# 删除匹配前缀(去掉左边,最短匹配模式)
${parameter##word}## 删除匹配前缀(去掉左边最长匹配模式)
${parameter%word}% 删除匹配后缀( 去掉右边,最短匹配模式)
${parameter%%word}%% 删除匹配后缀(去掉右边,最长匹配模式)
#简单使用
[root@manager ~]# test='I am oldboy teacher'
[root@manager ~]# echo ${test#I}
am oldboy teacher
[root@manager ~]# echo ${test#o}
I am oldboy teacher
[root@manager ~]# echo ${test#I am o}
ldboy teacher
[root@manager ~]# echo ${test#*o}
ldboy teacher
[root@manager ~]# echo ${test##*o}
y teacher

[root@manager ~]# test='I am oldboy teacher'
[root@manager ~]# echo ${test%r}
I am oldboy teache
[root@manager ~]# echo ${test%er}
I am oldboy teach
[root@manager ~]# echo ${test%o*}
I am oldb
[root@manager ~]# echo ${test%%o*}
I am
#应用
##简单 sed 比较麻烦 使用 变量子串里面删除功能
[root@manager ~]# net='/etc/sysconfig/networkscripts/ifcfg-eth0'
[root@manager ~]# 
[root@manager ~]# echo ${net##*/}
ifcfg-eth0
[root@manager ~]# echo ${net%%/*}
[root@manager ~]# echo ${net%/*}
/etc/sysconfig/network-scripts
[root@manager ~]# 
[root@manager ~]# dirname /etc/sysconfig/networkscripts/ifcfg-eth0
/etc/sysconfig/network-scripts
[root@manager ~]# basename /etc/sysconfig/networkscripts/ifcfg-eth0
ifcfg-eth0
#使用linux命令 效率 比 变量子串 低
root@manager ~]# time   for n in {1..10000} ;do echo 
${#n} &>/dev/null ; done 
real 0m0.154s
user 0m0.097s
sys 0m0.056s
[root@manager ~]# time   for n in {1..10000} ;do 
echo ${n}|wc -L &>/dev/null ; done 
real 0m20.292s
user 0m8.485s
sys 0m11.692s

小结:

变量子串删除部分 主要用来在脚本中删除路径 里面的名字 或路径部分

4. 替换

替换
${parameter/找谁/替换为什么}只替换第1个
${parameter//找谁/替换为什么}全局替换
[root@manager ~]# test='I am oldboy teacher'
[root@manager ~]# echo ${test/[a-z]/oldboy}
I oldboym oldboy teacher
[root@manager ~]# echo ${test//[a-z]/oldboy}
I oldboyoldboy oldboyoldboyoldboyoldboyoldboyoldboy 
oldboyoldboyoldboyoldboyoldboyoldboyoldboy
[root@manager ~]# 
[root@manager ~]# test='I am oldboy teacher'
[root@manager ~]# echo ${test//oldboy/}
I am teacher
[root@manager ~]# echo ${test/oldboy/} #把oldboy替换为空
即删除
I am teacher

5. 变量子串小结

变量子串 parameter表示变量
基础
${parameter}取变量内容
${#parameter}统计变量的长度 (多少个字符)
截取(切片) 类似cut 命令用法:cut -c
${parameter:1}
${parameter:1:2}
删除处理文件名路径
${parameter#word}删除变量中开头的word 最小匹配
${parameter##word}删除变量中开头的word 最长匹配
${parameter%word}删除变量中结尾的word 最小匹配
${parameter%%word}删除变量中结尾的word 最长匹配
替换
${parameter/找谁/替换为什么}最小匹配
${parameter//找谁/替换为什么}最大匹配

#通配符

*
{}
[]
[^]
?

特殊变量

功能: 实现给变量设置默认值。

内容含义
${parameter:-word}如果parameter没有被赋值或者其值为空,那么就以word作为其值
${parameter:=word}如果parameter没有被赋值或者其值为空,那么就以word作为其值,并且将word赋值给parameter
${parameter:?word}如果parameter没有被赋值或者其值为空,那么就把word作为错误输出.否则显示parameter内容
${parameter:+word}如果parameter没有被赋值或者其值为空,就什么都不做.否则用word替换变量内容
[root@manager ~]# echo $oldbing
[root@manager ~]# echo ${oldbing:-14}
14
[root@manager ~]# oldbing=13
[root@manager ~]# echo ${oldbing:-14}
13
[root@manager ~]# echo ${lidao:-14}
14
[root@manager ~]# echo $lidao
[root@manager ~]# echo ${lidao:=14}
14
[root@manager ~]# echo $lidao
14
[root@manager ~]# echo ${lidao:?14}   
-bash: lidao: 14
root@manager ~]# lidao=99 
[root@manager ~]# echo ${lidao:+14}   
14
[root@manager ~]# echo ${lidaov2:+14}

6. 特殊变量总结

状态

位置变量          man bash Special Parameters 特殊参数
变量子串          man bash parameter expansion 变量扩展
位置变量
状态变量
变量子串
其他变量

特殊变量

位置变量$数字 $0 $# $ $@*
状态$? $$ $_ $!
变量子串基础${oldboy} ${#oldboy}
截取${parameter:1} ${parameter:1:2}
删除${oldboy#word} ${oldboy%word}
替换${oldboy/谁/替换为什么} ${oldboy//谁/替换为什么}
变量扩展给变量设置默认值:${oldboy:-word}${oldboy:=word}

运算

运算符

在这里插入图片描述
注:

i=i+1 i++      计数统计次数
sum=sum+xxx
sum+=xxxx      累加求和
[root@manager ~]# #生成指定范围的随机数
[root@manager ~]## echo $RANDOM%数字  |bc

Linux计算方法

计算方法
bc
(())
let
awk
expr
$[ ]

1. bc basic calc

#基础用法
[root@manager ~]# echo 1+2 |bc
3
[root@manager ~]# echo 10/3 |bc
3
[root@manager ~]# echo 1/3 |bc
0
#bc显示小数
[root@manager ~]# echo 1/3 |bc -l
.33333333333333333333
[root@manager ~]# echo 10/3 |bc -l
3.33333333333333333333
[root@manager ~]# 
#指定位数的小数 了解
[root@manager ~]# echo 'scale=2;10/3' |bc -l
3.33

2. (())

[root@manager ~]# ((1+1))
[root@manager ~]# ((a=1+1))
[root@manager ~]# echo $a
2
[root@manager ~]# ((i=i+1))
[root@manager ~]# echo $i
1
[root@manager ~]# ((i=i+1))
[root@manager ~]# echo $i
2
[root@manager ~]# ((i=i+1))
[root@manager ~]# echo $i
3
[root@manager ~]# echo $((1+1))
2

3. let

[root@manager ~]# unset i
[root@manager ~]# let i++
[root@manager ~]# echo $i 
1
[root@manager ~]# let i++
[root@manager ~]# echo $i 
2
[root@manager ~]# let a=1+1
[root@manager ~]# echo $a
2

4. awk

[root@manager ~]# awk 'BEGIN{print 1/3}'
0.333333
[root@manager ~]# awk 'BEGIN{print 1/3,2^10,2^16}'
0.333333 1024 65536

5. expr

#基本及小坑  
#使用 * 乘法 需要转义
[root@manager /opt]# expr 10 * 10 
100
[root@manager /opt]# expr 10 \* 10 
100
#隐藏功能 判断参数、变量是否为数字
[root@manager /opt]# expr   10 + 10 
20
[root@manager /opt]# echo $?
0
[root@manager /opt]# expr   a + 10 
expr: non-integer argument
[root@manager /opt]# echo $?
2
#判断参数、变量是否为数字
[root@manager /opt]# expr   10 + b  
expr: non-integer argument
[root@manager /opt]# echo $?
2
[root@manager /opt]# expr   10 + 10b  
expr: non-integer argument
[root@manager /opt]# echo $?
2
# 使用expr判断参数是否为数字 坑
[root@manager /opt]# x=0 
[root@manager /opt]# y=0
[root@manager /opt]# expr $x + $y 
0
[root@manager /opt]# echo $?
1
[root@manager /opt]# expr $x + $y + 1
1
[root@manager /opt]# echo $?
0

6. $[ ]

[root@manager /opt]# echo $[1+1]
2
[root@manager /opt]# echo $[1/3]
0

7. 运算方法小结

计算方法
bc计算 显示小数
(())计算整数 里面变量直接使用 不需要加上$ ((运算公式)) 输出到屏幕 echo $(())
let计算整数 里面变量直接使用 不需要加上$ 后面接上 公式
awk计算 显示小数 过滤
expr计算整数 判断参数或变量是否为数字
$[ ]计算整数

shell条件语句 条件表达式

条件表达式----通过 符号 判断 文件 变量 比较大小放在 if判断 或 循环中

基础格式

格式
test <条件>
[ <条件> ]一般情况通用
[[ <条件> ]][ ] 升级版 支持正则表达式
(( <条件> ))

判断文件相关

表达式符号
-ffile 判断文件是否存在 存在则为真
-ddirectory 判断目录是否存在 存在则为真
-eexist 判断这个是否存在(文件 目录 软连接)
-xexecute 判断是否有x权限
-ssize 判断文件是否为空 (大小是否为0) 如果大于0 则为真
-rread 是否有读
-wwrite 是否有写
-LSymlink (symbolic link或soft link) 判断文件是否存在并且 是否为软连接
f1 -nt f2file1 newer than file2
f1 -ot f2file2 older than file2

在这里插入图片描述

[root@manager /opt]# [ -f /etc/hosts ]
[root@manager /opt]# [ -f /etc/hos ]
[root@manager /opt]# echo $?
1
[root@manager /opt]# [ -f /etc/hosts ] && echo 真 存在
|| echo 假 不存在
真 存在
[root@manager /opt]# [ -f /etc/host ] && echo 真 存在 
|| echo 假 不存在
-bash: cho: command not found
假 不存在
[root@manager ~]# [ -f /etc/hosts ] && echo 真 存在 
|| echo 假 不存在
真 存在
[root@manager ~]# [ -d /etc/hosts ] && echo 真 存在 
|| echo 假 不存在
假 不存在
[root@manager ~]# [ -d /etc/init.d ] && echo 真 存在 
|| echo 假 不存在
真 存在
[root@manager ~]# [ -x /sbin/ip ] && echo 真 存在 || 
echo 假 不存在
真 存在
#
[ -x /sbin/ip ] || exit 1
#-s
[root@manager ~]# > oldboy.txt
[root@manager ~]# [ -s oldboy.txt ] && echo 真   || 
echo 假
假
[root@manager ~]# echo 1 >oldboy.txt 
[root@manager ~]# [ -s oldboy.txt ] && echo 真   || 
echo 假
真

字符串比较

符号含义
"串1" = "串2"判断两个字符串 是否相等 如果相等则真
"串1" != "串2"判断两个字符串 是否相等 如果不相等则真
-zzero 如果字符串、变量 是空的 则为真
-nnot zero 如果字符串、变量 不是空的 则为真
# 判断字符串是否相等
[root@manager ~]# [ "oldboy" = "oldboy" ] && echo 等于
||echo 不等于
等于
[root@manager ~]# [ "oldboy" != "oldboy" ] && echo 不等||echo 等于
等于
[root@manager ~]# 
# 小坑  
[root@manager ~]# [ "oldboy" = "oldboy" ] && echo 等于
||echo 不等于
等于
[root@manager ~]# [ "oldboy" != "oldboy" ] && echo 不等||echo 等于
等于
[root@manager ~]# 
[root@manager ~]# echo $oldboy 
[root@manager ~]# [ -z $oldboy ] && echo 空 || echo 不
空
空
[root@manager ~]# [ -n $oldboy ] && echo 不空 || echo 
空
不空
#在使用字符串 变量比较时候要使用双引号 把字符串或变量引起来
[root@manager ~]# 
[root@manager ~]# [ -n "$oldboy" ] && echo 不空 || echo 
空
空
#实际案例
[ "${NETWORKING}" = "no" ] && exit 6
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi

小结:

给字符串、变量 加上双引号

一般配合if

数字比较

在这里插入图片描述

[root@manager ~]# [ 1 -eq 1 ] && echo 真 ||echo 假[root@manager ~]# [ 99 -gt 1 ] && echo 真 ||echo 假[root@manager ~]# [ 1 -gt -10 ] && echo 真 ||echo 假[root@manager ~]# [ 1.1 -gt -10 ] && echo 真 ||echo 假
-bash: [: 1.1: 期待整数表达式
假
[root@manager ~]# [ 1 -gt -10 ] && echo 真 ||echo 假[root@manager ~]# test 1 -gt -10   && echo 真 ||echo 假[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# [[ 2 >= 10 ]] && echo 真 ||echo 假
-bash: 条件表达式中有语法错误
-bash: `10' 附近有语法错误
[root@manager ~]# [[ 2 > 10 ]] && echo 真 ||echo 假[root@manager ~]# (( 2 >= 10 )) && echo 真 ||echo 假[root@manager ~]# (( 2 <= 10 )) && echo 真 ||echo 假

条件表达式的使用格式

[ 条件 ] && {
命令1
命令2
命令3
}

[ 条件 ] || {
命令1
命令2
命令3
}

#脚本输入2个参数 比较两个是否相等 相等 显示相等 不相等显示不相

#脚本输入2个参数 比较两个数字大小 大于 显示 > 小于 <
等于 =
#脚本输入2个参数 比较两个数字大小 大于 显示 > 小于 <
等于 = 输入必须是数字
#脚本输入2个参数 比较两个是否相等 相等 显示相等 不相等显示不相

#脚本输入2个参数 比较两个是否相等 相等 显示相等 不相等显示不相

##分析:
###通过命令行传递 2个参数 给脚本
####判断参数个数如果不是2
###脚本对比两个参数 一致
####如果相等
####如果不等

在这里插入图片描述

[root@manager /server/scripts]# sh 2.5-4-comp.sh
Must have two args
[root@manager /server/scripts]# sh 2.5-4-comp.sh 10 
2b 
Usage: Must have two number
[root@manager /server/scripts]# sh 2.5-4-comp.sh 10 
20 
10 -lt 20
[root@manager /server/scripts]# sh 2.5-4-comp.sh 20 
10 
20 -gt 10
[root@manager /server/scripts]# sh 2.5-4-comp.sh 10 
10 
10 -eq 10

在这里插入图片描述
在这里插入图片描述

逻辑测试符号

逻辑运算符 [ ] 或 test[[ ]]
-aand并且&&
-oor或者||
!!取反!
[root@manager /server/scripts]# [ -d /etc   -a -f 
/etc/hosts ] && echo 1 真 || echo 0 假
1 真
[root@manager /server/scripts]# [ -d /et   -a -f 
/etc/hosts ] && echo 1 真 || echo 0 假
0 假
[root@manager /server/scripts]# [ -d /et   -o -f 
/etc/hosts ] && echo 1 真 || echo 0 假
1 真
[root@manager /server/scripts]# 
[root@manager /server/scripts]# [ ! -d /et   ] && 
echo 1 真 || echo 0 假
1 真
#表示大于等于10并且小于等于100的数字
[root@manager /server/scripts]# num=4
[root@manager /server/scripts]# [ $num -ge 10 -a $num 
-le 100 ] && echo 1 || echo 0
0
[root@manager /server/scripts]# num=50
[root@manager /server/scripts]# [ $num -ge 10 -a $num 
-le 100 ] && echo 1 || echo 0
1
[root@manager /server/scripts]# test $num -ge 10 -a 
$num -le 100 && echo 1 || echo 0
1
[root@manager /server/scripts]# 
[root@manager /server/scripts]# [[ $num -ge 10 && $num 
-le 100 ]] && echo 1 || echo 0
1
[root@manager /server/scripts]# # 10 ~ 100
[root@manager /server/scripts]# # <10   >100
[root@manager /server/scripts]# 
[root@manager /server/scripts]# num=1
[root@manager /server/scripts]# [ ! $num -ge 10 -o ! 
$num -le 100 ] && echo 1 || echo 0
1
[root@manager /server/scripts]# [ $num -lt 10 -o 
$num -gt 100 ] && echo 1 || echo 0
1

正则表达式

[[ “oldboy123” =~ ^[0-9]+$ ]]

[root@manager ~]# [[ "12345" =~ [0-9] ]] && echo 1 
|| echo 0
1
[root@manager ~]# [[ "oldboy" =~ [0-9] ]] && echo 1 
|| echo 0
0
[root@manager ~]# [[ "oldboy123" =~ [0-9] ]] && echo 
1 || echo 0
1
#精确匹配数字
[root@manager ~]# [[ "oldboy123" =~ ^[0-9]+$ ]] && 
echo 1 || echo 0
0
命令行传入1个字符或数字,数字等于1则显示1,如果等于2则显示2,如果
既不等于1也不等于2,就显示输入不对,然后退出程序
从命令行传入1个参数
是否为1或2,否则退出
如果1 显示1 
如果2 显示2
[root@manager ~]# cat /server/scripts/2.5-5-input.sh 
#!/bin/bash
#author: oldboy
str=$1
#[ "$str" -ne 1 -o "$str" -ne 2 ]
[[ ! "$str" =~ ^[12]$ ]] && {
echo input error
exit 1
}
[ "$str" -eq 1 ] && echo 1
[ "$str" -eq 2 ] && echo 2
[root@manager ~]# sh /server/scripts/2.5-5-input.sh  
input error
[root@manager ~]# sh /server/scripts/2.5-5-input.sh 3
input error
[root@manager ~]# sh /server/scripts/2.5-5-input.sh 
12
input error
[root@manager ~]# sh /server/scripts/2.5-5-input.sh 1
1
[root@manager ~]# sh /server/scripts/2.5-5-input.sh 2
2
[root@manager ~]# sh /server/scripts/2.5-5-input.sh a
input error
[root@manager ~]# [[ "oldboy123" =~ [12] ]] && echo 
1 || echo 0
1
[root@manager ~]# [[ "1" =~ [12] ]] && echo 1 || 
echo 0
1
[root@manager ~]# [[ "2" =~ [12] ]] && echo 1 || 
echo 0
1
[root@manager ~]# [[ "12" =~ [12] ]] && echo 1 || 
echo 0
1
[root@manager ~]# [[ "12" =~ ^[12]$ ]] && echo 1 || 
echo 0
[root@manager ~]# [[ "12" =~ ^[12]$ ]] && echo 1 || 
echo 0
0
[root@manager ~]# [[ "1111" =~ ^[12]$ ]] && echo 1 
|| echo 0
0
[root@manager ~]# [[ "1" =~ ^[12]$ ]] && echo 1 || 
echo 0
1
[root@manager ~]# [[ "2" =~ ^[12]$ ]] && echo 1 || 
echo 0
1

条件表达式总结

内容
符号test [ ] [[ ]] (())
文件-d -f -x -s -r -w -L -h
字符串使用双引号 = != -z -n
数字-eq -ne -gt -ge -le -lt
逻辑-a -o !
正则[[ 变量/字符 =~ 正则 ]]

在这里插入图片描述

变量与后台运行

变量赋值方式

赋值方式案例
直接赋值oldboy=123 ; name=`hostname`
参数传递(脚本传参)oldboy=$1 sh oldboy.sh 10
通过read赋值 交互式赋值read -p ‘input password:’ pass
#read交互式 复制
[root@manager ~]# read -p 'input password:' pass
input password:*******      
[root@manager ~]# read -p 'input password:' pass
input password:oldboy
[root@manager ~]# echo $pass
oldboy
#read交互式赋值多个变量
[root@manager ~]# read -p 'input num1 num2:' n1 n2  
input num1 num2:10 20
[root@manager ~]# echo $n1 
10
[root@manager ~]# echo $n2 
20
#把 之前比较大小 脚本修改为read命令方式
[root@manager ~]# cat /server/scripts/2.8-1-compread.sh
#!/bin/bash
#author: oldboy
read -p "input num1 num2:" num1 num2
#number
#expr $num1 + $num2 + 1   &>/dev/null 
#[ $? -ne 0 ] && {
[[ "$num1" =~ ^[0-9]+$ && "$num2" =~ ^[0-9]+$ ]] || {
echo "Usage: Must have two number"
exit 2
}
#compare 
[ $num1 -gt $num2 ] && echo  "$num1 -gt $num2"
[ $num1 -lt $num2 ] && echo  "$num1 -lt $num2"
[ $num1 -eq $num2 ] && echo  "$num1 -eq $num2"
[root@manager ~]# 
[root@manager ~]# sh   /server/scripts/2.8-1-compread.sh
input num1 num2:10 20
10 -lt 20
[root@manager ~]# sh   /server/scripts/2.8-1-compread.sh
input num1 num2:10 10b
Usage: Must have two number
[root@manager ~]# sh   /server/scripts/2.8-1-compread.sh
input num1 num2:10 
Usage: Must have two number
[root@manager ~]# sh   /server/scripts/2.8-1-compread.sh
input num1 num2:20b
Usage: Must have two number
[root@manager ~]# sh   /server/scripts/2.8-1-compread.sh
input num1 num2:
Usage: Must have two number

命令、脚本后台运行

让命令或脚本去后台运行 防止断网 远程连接工具突然断开

后台运行方法
& 或 nohup command &
ctrl + z 与 bg
screen

1. & 或 nohup command &

[root@manager ~]# sleep 99 & 
[1] 7965
[root@manager ~]# ps -ef |grep sleep 
root       7965   7944  0 11:14 pts/0    00:00:00 sleep
99
root       7967   7944  0 11:14 pts/0    00:00:00 grep
--color=auto sleep

2. ctrl + z配合 bg

#ctrl + z 让进程去后台挂起 (暂停)
[root@manager ~]# sleep 666 
^Z
[2]+ 已停止               sleep 666
#bg 让后台挂起的 继续运行 background  
[root@manager ~]# bg 
[2]+ sleep 666 &
[1]   完成                  sleep 99
#查看后台运行
jobs 
#应用场景:杀掉 顽固进程
##执行顽固进程
##ctrl + z 
##kill %1 #数字

3. screen

#screen基础用法
screen   
xshell断开
xshell重新连接
[root@manager ~]# screen -ls 
There is a screen on:
 7977.pts-0.manager (Detached)
1 Socket in /var/run/screen/S-root.
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# 
#查看所有screen窗口
[root@manager ~]# screen -ls 
There is a screen on:
 7977.pts-0.manager (Detached)
 1 Socket in /var/run/screen/S-root.
#重新连接到指定窗口
[root@manager ~]# screen -r 7977

快捷键:

ctrl + a d 退出screen窗口 窗口会继续会继续运行
ctrl + a k 结束当前screen窗口
检查 自己是否在 screen中 ctrl +a v #version

判断

if 判断3种格式
1.单分支判断

在这里插入图片描述
# 单分支判断
应用在脚本开头 做检查,检查失败退出脚本 参数个数 脚本 命令是否有权限

if [ 条件 ];then
   命令
fi

2. 双分支判断
在这里插入图片描述
#双分支判断
检查 服务 进程

if [ 条件 ]
then
   命令
else     
   命令    
fi

Example
检查 crond服务是否运行中 如果运行提示 crond is running 否则 提示 crond is failed
#后面检查服务的脚本 检查哪个服务脚本名字不要以服务命名

[root@yida scripts]# cat check_cr.sh 
#!/bin/bash
#检查  crond服务是否运行中  如果运行提示 crond is running   否则 提示 crond is failed
.  /etc/init.d/functions
Name=$(ps -ef |grep crond |grep -vc grep)
if [  $Name -ge 1 ];then
 action "crond is running" /bin/true

else
 action "crond is failed" /bin/false
fi

3. 多分支判断

[root@manager ~]# vim /server/scripts/2.8-1-comp-readmulti-if.sh
  
#!/bin/bash
#author: oldboy
read -p "input num1 num2:" num1 num2
#number
#expr $num1 + $num2 + 1   &>/dev/null 
#[ $? -ne 0 ] && {
if [[ ! "$num1" =~ ^[0-9]+$ || !  "$num2" =~ ^[0-9]+$ 
]]
then
    echo "Usage: Must have two number"
    exit 2
fi
#compare 
if [ $num1 -gt $num2 ]
then
    echo  "$num1 -gt $num2"
elif [ $num1 -lt $num2 ]   #else if 
then
    echo  "$num1 -lt $num2"
else                  
    echo  "$num1 -eq $num2"
fi

在这里插入图片描述

服务检查方式及命令

内容方法
端口本地检查: netstat -lntup/ss -lntup /lsof -i:80
远程检查: telnet ip port /nc ip port /nmap
进程ps -ef/ ps aux
客户端模拟监控ping -c1 -i1 -W1 ip /curl /wget -q --spider
数据库mysql -e 'show databases;'

端口检查

#ss 或 netstat 
[root@manager ~]# ss -lntup |grep 22 
udp   UNCONN     0      0      127.0.0.1:323         
          *:*                   users:
(("chronyd",pid=5220,fd=1))
udp   UNCONN     0      0       ::1:323               
  :::*                   users:
(("chronyd",pid=5220,fd=2))
tcp   LISTEN     0      128       *:22               
    *:*                   users:
(("sshd",pid=7061,fd=3))
[root@manager ~]# ss -lntup |grep -w :22 
tcp   LISTEN     0      128       *:22               
    *:*                   users:
(("sshd",pid=7061,fd=3))

#lsof 
[root@manager ~]# lsof -i :22 
COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE 
NAME
sshd    7061 root   3u IPv4  39278     0t0 TCP 
*:ssh (LISTEN)
sshd    7322 root   3u IPv4  40265     0t0 TCP 
manager:ssh->10.0.0.100:49510 (ESTABLISHED)
sshd    7392 root   3u IPv4  43630     0t0 TCP 
manager:ssh->10.0.0.100:50037 (ESTABLISHED)

#nc telnet  
[root@manager ~]# telnet 10.0.0.61 22 
Trying 10.0.0.61...
Connected to 10.0.0.61.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.4
Protocol mismatch.
Connection closed by foreign host.
[root@manager ~]# nc 10.0.0.61 22 
SSH-2.0-OpenSSH_7.4
Protocol mismatch.

#nmap 
nmap -p22   ip/url 
namp -p1-1024   ip/url     #端口范围 1-65535  
nmap -p22,80 ip/url
[root@manager ~]# nmap -p80 baidu.com
Starting Nmap 6.40 ( http://nmap.org ) at 2020-01-14
09:29 CST
Nmap scan report for baidu.com (220.181.38.148)
Host is up (0.0088s latency).
Other addresses for baidu.com (not scanned): 
39.156.69.79
PORT   STATE SERVICE
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 0.21 
seconds

模拟用户访问网站

[root@manager ~]# wget --spider   www.oldbing.com  
开启 Spider 模式。检查是否存在远程文件。
--2020-01-14 09:38:43-- http://www.oldbing.com/
正在解析主机 www.oldbing.com (www.oldbing.com)... 失败:
未知的名称或服务。
wget: 无法解析主机地址 “www.oldbing.com”
[root@manager ~]# echo $?
4
[root@manager ~]# wget -q(定向为空) --spider   www.oldbing.com 
[root@manager ~]# echo $?
4

面试题
1. 通过脚本传参的方式,检查Web网站URL是否正常

[root@m01 /scripts]# cat check_url.sh 
#!/bin/bash
url=$1

if ping -c1 $url &>/dev/null;then
   echo "$url is ok"
else
   echo "$url is failed" 
fi

2. 通过脚本传参的方式,检查Web网站URL是否正常

[root@m01 /scripts]# cat check_url2.sh 
#!/bin/bash
url=$1
if [[ ! "$url" =~ ^[a-zA-Z.]*[a-zA-Z0-9]+\.(com|org|cn)$  ]]
then
    echo "$url  is not ok"
    exit 1 
fi  
#wget url 
wget -T 1 -q --spider  $url 
if [ $? -eq 0 ]
then
   echo $url is ok
else
   echo $url is failed 
fi

3. 检查系统可用内存
企业案例:监控系统可用内存,小于100M就发送报警邮件 否则,提示内存充足,定时任务每3分钟1次

[root@manager ~]# cat   /server/scripts/2.10.2-
chk_mem.sh
#!/bin/bash
#author:oldboy
mem=`free -m |awk 'NR==2{print $NF}'`
if [ $mem -lt 10000 ]
then
   mail -s "mem is bugoule"   918391635@qq.com </etc/hosts
fi
[root@manager ~]# sh /server/scripts/2.10.2-chk_mem.sh
[root@manager ~]# crontab -l
#check mem   by liyy at 20200202
*/3 * * * * /bin/sh /server/scripts/2.10.2-chk_mem.sh &>/dev/null

服务管理类脚本

1. 服务管理脚本书写

rsync

目标:书写 服务管理脚本
分步:
基础要求:
sh rsyncd.sh start
sh rsyncd.sh stop
sh rsyncd.sh restart 
进阶:
rsync服务开机自启动
#rsync管理命令   
###   sh   rsyncd.sh start     === rsync   --daemon 
  #rsyncd   sshd   crond
  ###   sh   rsyncd.sh stop     === kill `cat 
pidfile` 
###   sh rsyncd.sh   restart   ===   stop start   
#准备 rsync的配置文件
#Rsync server
#created by oldboy 15:01 2009-6-5
##rsyncd.conf start##
uid = root
gid = root
use chroot = no
max connections = 2000
timeout = 600
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = 10.0.0.0/24
hosts deny = 0.0.0.0/32
auth users = rsync_backup
secrets file = /etc/rsync.password
#####################################
[www]
comment = www by old0boy 14:18 2012-1-13
path = /oldboy
[root@oldboyedu-c6 ~]# rsync --daemon
[root@oldboyedu-c6 ~]# ss -lntup |grep 873
tcp   LISTEN     0      5                     :::873 
                :::*     users:(("rsync",2364,5))
tcp   LISTEN     0      5                     *:873 
                  *:*     users:(("rsync",2364,3))
[root@oldboyedu-c6 ~]# 
[root@oldboyedu-c6 ~]# kill `cat /var/run/rsyncd.pid`
[root@oldboyedu-c6 ~]# ss -lntup |grep 873

在这里插入图片描述
#服务管理脚本 基本形式

[root@oldboyedu-c6 /server/scripts]# vim rsyncd.sh 
#!/bin/bash
choice=$1
if [ "$choice" = "start" ]
then
   rsync --daemon
fi
if [ "$choice" = "stop" ]
then
    kill  `cat /var/run/rsyncd.pid`
fi
if [ "$choice" = "restart" ]
then
    kill  `cat /var/run/rsyncd.pid`
    sleep 1
   rsync --daemon
fi
"rsyncd.sh" [New] 20L, 254C written                   
                        
[root@oldboyedu-c6 /server/scripts]# 
[root@oldboyedu-c6 /server/scripts]# sh   rsyncd.sh 
[root@oldboyedu-c6 /server/scripts]# pkill rsyncd 
[root@oldboyedu-c6 /server/scripts]# pkill rsync 
[root@oldboyedu-c6 /server/scripts]# ss -lntup |grep 
873 
[root@oldboyedu-c6 /server/scripts]# sh rsyncd.sh 
start 
[root@oldboyedu-c6 /server/scripts]# ss -lntup |grep 
873
tcp   LISTEN     0      5                     :::873 
                :::*     users:(("rsync",3947,5))
tcp   LISTEN     0      5                     *:873 
                  *:*     users:(("rsync",3947,3))

在这里插入图片描述
在这里插入图片描述

让脚本(服务能开机自启动)或通过service管理

方法1 /etc/rc.local (centos 7 ) 需要加上 执行权限
方法2 通过chkconfig(c6) 管理 或 systemctl管理(c7)

chkconfig管理脚本要求
脚本必须放在 /etc/init.d/ 并且 有执行权限
脚本开头 必须要有chkconfig要求的格式
#chkconfig: 2345(运行级别) 99 98 99开机顺序 98关机顺序
添加到chkconfig管理 : chkconfig --add rsyncd.sh

CentOS 6.x 方法

#chkconfig 管理开机自启动

[root@oldboyedu-c6 /server/scripts]# chkconfig |grep ipt 
iptables       0:off 1:off 2:on 3:on 4:on 
5:on 6:off
[root@oldboyedu-c6 /server/scripts]# chkconfig 
iptables off 
[root@oldboyedu-c6 /server/scripts]# 
[root@oldboyedu-c6 /server/scripts]# chkconfig |grep ipt 
iptables       0:off 1:off 2:off 3:off 4:off 
5:off 6:off

#chkconfig管理 服务脚本 实现开机自启动
###1. 脚本必须放在 /etc/init.d/ 并且 有执行权限

[root@oldboyedu-c6 /server/scripts]# mv   rsyncd.sh 
/etc/init.d/
[root@oldboyedu-c6 /server/scripts]# chmod +x 
/etc/init.d/rsyncd.sh 
[root@oldboyedu-c6 /server/scripts]# ll 
/etc/init.d/rsyncd.sh
-rwxr-xr-x. 1 root root 342 Jan 14 15:28 
/etc/init.d/rsyncd.sh

###2. 脚本开头 必须要有chkconfig要求的格式

[root@oldboyedu-c6 /server/scripts]# head -2 
/etc/init.d/rsyncd.sh 
#!/bin/bash
# chkconfig: 2345 99 98

###3. 添加到chkconfig管理 : `chkconfig --add rsyncd.sh

[root@oldboyedu-c6 /server/scripts]# chkconfig --add 
rsyncd.sh 
[root@oldboyedu-c6 /server/scripts]# chkconfig |grep 
rsync 
rsyncd.sh     0:off 1:off 2:on 3:on 4:on 
5:on 6:off

CentOS 7.x 8.x systemctl 管理方法

#环境准备

[root@manager ~]# cat /etc/rsyncd.conf
#Rsync server
#created by oldboy 15:01 2009-6-5
##rsyncd.conf start##
uid = root
gid = root
use chroot = no
max connections = 2000
timeout = 600
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = 10.0.0.0/24
hosts deny = 0.0.0.0/32
auth users = rsync_backup
secrets file = /etc/rsync.password
#####################################
[www]
comment = www by old0boy 14:18 2012-1-13
path = /oldboy
[root@manager ~]# systemctl disable rsyncd 
[root@manager ~]# systemctl stop rsyncd

#准备管理脚本

[root@manager ~]# scp   
10.0.0.202:/etc/init.d/rsyncd.sh   /etc/init.d/
root@10.0.0.202's password: 
rsyncd.sh                                             
                         100%  384   321.1KB/s   00:00 
   
[root@manager ~]# ss -lntup |grep 873 
[root@manager ~]# uname -r 
3.10.0-957.el7.x86_64
[root@manager ~]# /etc/init.d/rsyncd.sh start 
[root@manager ~]# ss -lntup |grep 873 
tcp   LISTEN     0      5         *:873               
    *:*                   users:
(("rsync",pid=11087,fd=3))
tcp   LISTEN     0      5       :::873               
  :::*                   users:
(("rsync",pid=11087,fd=5))
[root@manager ~]# /etc/init.d/rsyncd.sh stop 
[root@manager ~]# ss -lntup |grep 873 
[root@manager ~]# /etc/init.d/rsyncd.sh restart 
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# ss -lntup |grep 873 
tcp   LISTEN     0      5         *:873               
    *:*                   users:
(("rsync",pid=11097,fd=3))
tcp   LISTEN     0      5       :::873               
  :::*                   users:
(("rsync",pid=11097,fd=5)

#书写systemctl配置
systemctl cat rsyncd
systemctl cat nginx

[root@manager ~]# systemctl cat   nginx.service 
# /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nsslookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
#Nginx will fail to start if /run/nginx.pid already 
exists but has the wrong
#SELinux context. This might happen when running 
`nginx -t` from the cmdline.
#https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID    #nginx -s 
reload
ExecStop=
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl 配置文件说明
[Unit]1. 说明信息 2. 依赖关系 After 在后面服务之后运行
[Service]1. 说明 start stop restart 对应的命令或脚本ExecStart ExecStop ExecReload 2. 类型 Type=forking 服务模式
[Install]运行级别(target)
[root@manager ~]# cat   
/usr/lib/systemd/system/rsyncd-new.service
[Unit]
After=network.target remote-fs.target
[Service]
Type=forking
ExecStart=/etc/init.d/rsyncd.sh  start
ExecStop=/etc/init.d/rsyncd.sh  stop
ExecReload=/etc/init.d/rsyncd.sh  restart
[Install]
WantedBy=multi-user.target
[root@manager ~]# pkill rsync 
[root@manager ~]# pkill rsync 
[root@manager ~]# systemctl start rsyncd-new.service 
[root@manager ~]# systemctl status rsyncd-new.service 
● rsyncd-new.service
   Loaded: loaded (/usr/lib/systemd/system/rsyncdnew.service; disabled; vendor preset: disabled)
   Active: active (running) since 二 2020-01-14
16:10:58 CST; 9s ago
 Process: 11339 ExecStart=/etc/init.d/rsyncd.sh start
(code=exited, status=0/SUCCESS)
 Main PID: 11341 (rsync)
   CGroup: /system.slice/rsyncd-new.service
           └─11341 rsync --daemon
1月 14 16:10:58 manager systemd[1]: Starting rsyncdnew.service...
1月 14 16:10:58 manager systemd[1]: Started rsyncdnew.service.
[root@manager ~]# 
[root@manager ~]# systemctl enable rsyncd-new.service 
Created symlink from /etc/systemd/system/multiuser.target.wants/rsyncd-new.service to 
/usr/lib/systemd/system/rsyncd-new.service.
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# systemctl status rsyncd-new.service 
● rsyncd-new.service
   Loaded: loaded (/usr/lib/systemd/system/rsyncdnew.service; enabled; vendor preset: disabled)
   Active: active (running) since 二 2020-01-14
16:10:58 CST; 37s ago
 Main PID: 11341 (rsync)
   CGroup: /system.slice/rsyncd-new.service
           └─11341 rsync --daemon
1月 14 16:10:58 manager systemd[1]: Starting rsyncdnew.service...
1月 14 16:10:58 manager systemd[1]: Started rsyncdnew.service.

小结

Linux各种服务软件 管理脚本

1. 找出 服务 start |stop|restart 对应的命令
2. 书写脚本 if 
3. 服务开机自启动systemctl/chkconfig

case语句

分支结构 条件选择语句
应用场景: 服务管理脚本(start|stop|restart) 菜单功能

#格式

case  "选择"  in
   条件1)   
       命令
       ;;
   条件2)  
       命令
       ;;
     *)
       默认的内容
esac

#案例

[root@manager ~]# vim /server/scripts/2.12-1-case.sh  
  
#!/bin/bash
#author: oldboy
choice=$1
case "$choice"  in
    start)
         echo  start
         ;;
    stop)
         echo stop
         ;;
    restart)
         echo restart
         ;;
       *)
          echo "Usages: $0 {start|stop|restart}"
          exit 1
esac

sh与source(.)

含义区别应用
sh(bash)都可以运行脚本运行的时候会创建1个子shell通用执行脚本方法
source(.)都可以运行脚本是在当前shell环境运行加载 /etc/init.d/functions 系统的函数库 source/etc/init.d/functions

在这里插入图片描述

[root@manager /server/scripts]# cat 2.13-1-shsource.sh
#!/bin/bash
#author:oldboy
echo $OLDBOY
[root@manager /server/scripts]# OLDBOY=666
[root@manager /server/scripts]# sh 2.13-1-sh-source.sh
[root@manager /server/scripts]# . 2.13-1-sh-source.sh
666

函数

别名 :给命令或脚本设置别名 alias rm='echo oldboy’

函数:给一段代码设置1个名称 ,代码:函数体 名称:函数名字 (专业 规范)

函数的基础格式

#格式
##格式1

function 函数名() {
函数体(命令)
函数体(命令)
return 
}

##格式2

function 函数名 {
函数体(命令)
函数体(命令)
return 
}

##格式3 ※※※※※

函数名() {
函数体(命令)
函数体(命令)
return 
}

函数传参

名称shell脚本函数
$1 $2 $数字脚本的第1个 第2个 参数函数的第1个 第2个 参数
$0脚本名字脚本名字
$#脚本参数个数函数参数的个数
$*取出脚本所有的参数取出函数所有的参数
$@取出脚本所有的参数取出函数所有的参数
[root@manager /server/scripts]# cat 2.14.2-rsyncd.sh
#!/bin/bash
# chkconfig: 2345 99 98
# author:oldboy 
choice=$1
pidfile=/var/run/rsyncd.pid
start() {
   [ -f $pidfile ] || rsync --daemon
}
stop() {
   [ -f $pidfile ] && kill  `cat 
/var/run/rsyncd.pid`
}
restart() {
   [ -f $pidfile ] && kill  `cat 
/var/run/rsyncd.pid`
    sleep 1
   rsync --daemon
}
case "$choice" in
    start)
     start
         ;;
     stop)
          stop
         ;;
  restart)
          restart
         ;;
       *)
           echo "Usage $0 {start|stop|restart}"
           exit 1
esac

循环语句

while当型循环 基础

for通用
while 当型循环死循环,读取文件的内容

#while 循环

while   条件    
do
     命令
done
[root@manager /server/scripts]# cat   2.15.1-
while.sh
#!/bin/bash
#author:oldboy
while true    #死循环 true 条件永久成立
do
   date 
    sleep 2
done

#eg: 使用while循环 输出1 2 3 … 10 类似 seq 10

[root@manager /server/scripts]# vim   2.15.2-seqwhile.sh
  
#!/bin/bash
#author:oldboy
i=0
while [ $i -lt 10 ]
do 
  ((i++))
  echo $i
done

#面试题: 计算1+2+3+4+5…+10 求总和
###方法1: while

[root@manager /server/scripts]# cat 2.15.3-sumwhile.sh
#!/bin/bash
#author:oldboy
i=1
sum=0
while [ $i -le 10 ]
do
   ((sum=sum+i))
   ((i++))
done
echo $sum

###方法2:

[root@manager /server/scripts]# echo $((`seq -s+ 10` ))
55
[root@manager /server/scripts]# seq -s+ 10 
1+2+3+4+5+6+7+8+9+10
[root@manager /server/scripts]# seq -s+ 10 |bc 
55

#脚本修改为函数 并且使用while 死循环

[root@manager /server/scripts]# cat 2.8-1-comp-readmulti-if.sh 
#!/bin/bash
#author: oldboy
read -p "input num1 num2:" num1 num2
if [[ ! "$num1" =~ ^[0-9]+$ || !  "$num2" =~ ^[0-9]+$ 
]]  
then  
    echo "Usage: Must have two number"
    exit 2
fi
#compare 
if [ $num1 -gt $num2 ] 
then
    echo  "$num1 -gt $num2"
elif [ $num1 -lt $num2 ]   #else if 
then
    echo  "$num1 -lt $num2"
else
    echo  "$num1 -eq $num2"
fi
[root@manager /server/scripts]# cat 2.15.3-comp-readmulti-if.sh
#!/bin/bash
#author: oldboy
input() {
read -p "input num1 num2:" num1 num2
}
#number
#expr $num1 + $num2 + 1   &>/dev/null 
#[ $? -ne 0 ] && {
check() {
if [[ ! "$num1" =~ ^[0-9]+$ || !  "$num2" =~ ^[0-9]+$ 
]]  
then  
    echo "Usage: Must have two number"
   continue
fi
}
#compare 
compare() {
if [ $num1 -gt $num2 ] 
then
    echo  "$num1 -gt $num2"
elif [ $num1 -lt $num2 ]   #else if 
then
    echo  "$num1 -lt $num2"
else
    echo  "$num1 -eq $num2"
fi
}
main() {
while true
do
   input
   check
   compare
done
}
main

while 当型循环 读取文件

通过while read读取文件内容 ip 把ip通过iptables 封掉

#方式1:采用exec读取文件后,然后进入while循环处理

exec<FILE
while read line
do
   cmd
done

#方式2:使用cat读取文件内容,然后通过管道进入while循环处理

cat FILE|while read line
do
   cmd
done

#※※※※※※方式3:在while循环结尾done通过输入重定向指定读取的文件

while read line
do
   cmd
done<FILE

#eg: while read line

[root@m01 /server/scripts]# cat stu.txt 
01 oldbing  18
02 oldxia   19
03 oldlidao 19
04 oldguo   66

##通过while循环 求和 stu.txt第3列的内容

[root@manager /server/scripts]# cat   2.15.5-whileread-sum.sh
#!/bin/bash
#author:oldboy
file=/server/scripts/stu.txt
sum=0
while read line
do
    num=`echo $line|awk '{print $3}'`
   ((sum+=num))   #sum=sum+num 
done <$file
echo $sum

###企业案例:写一个Shell脚本解决类DDOS攻击的生产案例。请根据web日志或者或者系统网络连接数,监控当某个IP并发连接数,若短时内并发连接数达到100(阈值),即调用防火墙命令封掉对应的IP。防火墙命令为:iptables -I INPUT -s IP地址 -j DROP。

分析:
 1.通过awk分析日志、连接数 每个ip的次数 结果存放在文件中
 2.通过while read line 读取文件

判断次数如果大于100 并且 iptables -nL中没有这个ip   则封掉
DOS   Denial of Service 拒绝式服务攻击
DDOS 分布式       
系统网络连接数:ss  -ant /netstat -ant  
分析netstat.log找出每个ip的连接数量(出现次数)
如果次数大于100则通过iptables封掉
[root@m01 /scripts]# cat check_while.sh
#!/bin/bash

file=/root/netstat.log
tmp_file=/scripts/tmp.txt
awk -F'[ :]+' '/ESTABLISHED/ {print $6}' $file |sort |uniq -c |sort -n > $tmp_file

while read line;do
 count=`echo $line |awk '{print $1}'`
 ip=`echo $line |awk '{print $2}'`
 if [ "$count" -gt 2 -a `iptables -nL |grep -wc $ip` -eq 0 ];then
    iptables -I INPUT  -s $ip  -j DROP 
 fi
done <$tmp_file
[root@manager ~]# while read x y z 
> do
> echo "x:"$x "y:"$y "z:$z"
> done </server/scripts/stu.txt 
x:01 y:oldbing z:18
x:02 y:oldxia z:19
x:03 y:oldlidao z:19
x:04 y:oldguo z:66
[root@manager ~]# while read x y ; do echo "x:$x 
y:$y"; done </server/scripts/stu.txt 
x:01 y:oldbing  18
x:02 y:oldxia   19
x:03 y:oldlidao 19
x:04 y:oldguo   66

while小结

1. 死循环 while true ; do ;done while : ; do 
;done

2. while读取文件的内容

直到型循环 until

until 话费是否充足
do
       发短信
done

for型循环

通用

for n in 列表(名单)
do
命令
done

数字循环(C语言循环)

for((i=1;i<=10;i++))
do
命令
done

#生成随机字符 数字方法
##方法1 RANDOM

[root@manager ~]# echo $RANDOM 
14966
[root@manager ~]# 
[root@manager ~]# 
[root@manager ~]# echo $((RANDOM + 100000))
125107

##方法2 date + md5sum

[root@manager ~]# date +%N |md5sum| cut -c 1-8
7d178a23

##方法3 tr + /dev/urandom
###/dev/urandom 字符文件、字符设备 不断输出字符

[root@manager ~]# tr -cd 'a-zA-Z0-9' </dev/urandom 
|head -c8 
for n  in  1 2 3 4 {1..10}  `seq 10`   {1..10..2} 
`seq 1 2 10`
do
    echo $n
done

#批量创建文件
企业面试题2:
使用for循环在/oldboy目录下通过随机小写10个字母加固定字符串oldboy批量创建10个html文件

#!/bin/bash
[ -d /oldboy ] || mkdir /oldboy
for i  in {1..10};do
 name=`uuidgen |sed "s#[0-9-]##g" |head -c10`
 touch /oldboy/${name}_oldboy.html
done
#!/bin/bash
#author:oldboy
dir=/oldboy
[ -d "$dir" ] || mkdir -p $dir
for n  in {1..10}
do
    name=`tr -cd 'a-zA-Z' </dev/urandom |head -c10`
    touch  $dir/${name}_oldboy.html 
done

#批量重命名 把上面创建的文件名中 oldboy替换为 oldgirl

#!/bin/bash
cd /oldboy
for n in `ls *`;do
  rename html txt *
done
#!/bin/bash
cd /oldboy
for n in `ls *`;do
 mv $n ${n/oldgirl/oldboy}
done

#批量添加用户
企业面试题4:
##批量创建10个系统帐号oldboy01-oldboy10并设置密码(密码为随机8位字符串)

#!/bin/bash
for user in oldboy{01..10};do
useradd $user
num=`uuidgen |head -c 8`
echo $num |passwd --stdin $user
echo $user $num >> /scripts/tmp_user.txt
done
#!/bin/bash
for n in oldboy{01..10}
do
   useradd  $n
    pass=`tr -cd 'a-zA-Z' </dev/urandom |head -c8`
    echo "$pass" |passwd --stdin $n
    echo $n $pass >>/root/pass.txt
done

流程控制语句

流程控制语句含义应用场景
return函数中 在函数执行完成后 给函数返回值函数中 在函数执行完成后 给函数返回值
exit直接退出脚本 返回值书写在 脚本报错的时候 提示信息然后退出脚本
continue n控制循环 结束本次循环 进行下次循环循环中跳过
break n跳过所有循环
checkpid() {
local i #设置局部变量i
for i in $* ; do #函数所有参数 循环
[ -d "/proc/$i" ] && return 0
done
return 1
}
函数checkpid
checkpid
如果这个pid存在 return 0

#continue 基本含义

[root@m01 ~]# for n in {1..5}; do [ $n -eq 3 ] &&continue ; echo $n ;done
1
2
4
5
for pid in $pids ; do
[ ! -e "/proc/$pid" ] && continue #如果pid目录不存在 则跳过本次循环 读取下1个pid目录

#break 基本含义

[root@manager ~]# for n in {1..10}; do [ $n -eq 5 ]&&break ; echo $n ;done
1
2
3
4

#continue break 扩展
#continue 2 结束当前循环跳到第2层循环 从第2层循环开始

for n in {A..E}
do
for m in {a..e}
do
for i in {1..5}
do
echo $n $m $i
done
done
done
for n in {A..E}
do
for m in {a..e}
do
for i in {1..5}
do
[ $i -eq 3 ] &&continue
echo $n $m $i
done
done
done
for n in {A..E}
do
for m in {a..e}
do
for i in {1..5}
do
[ $i -eq 3 ] &&continue 2
echo $n $m $i
done
done
done

#break 2

for n in {A..E}
do
for m in {a..e}
do
for i in {1..5}
do
[ $i -eq 4 ] &&break 2
echo $n $m $i
done
done
done

eg:乘法口诀表
精确

for i in {1..9}
do
for((j=1;j<=i;j++))
do
echo "$j*$i=$((i*j))"
done
done

精确加上格式

for i in {1..9}
do
for((j=1;j<=i;j++))
do
echo -n "$j*$i=$((i*j)) "
done
echo
done |column -t

Linux加上颜色与vimrc

颜色

Linux命令行给字体加颜色命令

[root@oldboy scripts]# echo -e "\E[1;31m红色字
oldboy\E[0m"
红色字oldboy
[root@oldboy scripts]# echo -e "\033[31m红色字oldboy
\033[0m"

在上述命令中:

echo -e可以识别转义字符,这里将识别特殊字符的含义,并输出。
\n \t
Linux下面回车是 \n
Windows下面回车是 \r\n
#巨坑: windows下面书写脚本或SQL语句 放入到linux执行 失败
#解决: dos2unix

\E也可以使用\033替代


[1数字1表示加粗显示(这个位置可以加不同的数字代表不同的意思,详细信息可man console_codes得)


31m表示为红色字体,这个位置可以换不同的数字,以代表不同的意思


“红色字oldboy”表示待设置的内容


[0m表示关闭所有属性,这个位置可以换不同的数字,以代表不同的意思


echo -e "\E[5;31m红色字oldboy\E[0m"
echo -e "\E[5;32m绿色字oldboy\E[0m"
echo -e "\E[5;33m棕色字oldboy\E[0m"
echo -e "\E[5;34m颜色字oldboy\E[0m"
echo -e "\E[5;35m紫色/红色oldboy\E[0m"

在这里插入图片描述

[root@manager ~]# echo -e "\E[1;31m红色字oldboy\E[0m"
红色字oldboy
[root@manager ~]# echo -e "\E[1;31;42m红色字绿色背景
oldboy\E[0m"
红色字绿色背景oldboy
[root@manager ~]# echo -e "\E[5;31;42m红色字绿色背景 闪烁
oldboy\E[0m"

红色字绿色背景 闪烁oldboy

在这里插入图片描述


案例
sh color.sh 执行脚本后 给 内容加上对应的颜色
1.input red 内容
2.input green 内容
3.input blue 内容
例子:选择1 oldboy
则oldboy显示为红色

[root@manager ~]# cat /server/scripts/2.18.1-color.sh
#!/bin/bash
#author:oldboy
RED="\E[1;31m"
GREEN="\E[1;32m"
BLUE="\E[1;34m"
END="\E[0m"
input() {
cat <<EOF
1.input red 内容
2.input green 内容
3.input blue 内容
EOF
read -p "input choice:" cho
read -p "内容:" text
}
choice() {
case "$cho" in
1)
echo -e "${RED} $text ${END}"
;;
2)
echo -e "${GREEN} $text ${END}"
;;
3)
echo -e "${BLUE} $text ${END}"
;;
*)
echo "Usage: input {1|2|3}"
exit 1
esac
}
main() {
input
choice
}
main
[root@m01 /scripts]# cat test.sh 
#!/bin/bash
red="\e[1;31m"
green="\e[1;32m"
blue="\e[1;34m"
end="\e[0m"

while true;do
  echo  "1.input red 内容"
  echo  "2.input green 内容"
  echo  "3.input blue  内容"
  read -p "please input number:" choice
  if [ $choice -le 3 ];then
  read -p "内容:" text
  fi
  case $choice in
     1)
       echo -e  "${red}${text}${end}"
       exit 1
       ;;
     2)
       echo -e  "${green}${text}${end}"
       exit 1
       ;;
     3)
       echo -e  "${blue}${text}${end}"
       exit 1
       ;;
     *)
         if [ $choice -gt 3 ];then
       echo "请输入正确编号"
         fi
  esac
done

vimrc

通过vim编辑文件的配置文件
创建新文件 .sh 文件 自动加上版权说明


vim格式
##简易版本

#创建新文件 .sh 文件 自动加上版权说明
##/etc/vimrc 全局
##~/.vimrc 当前用户生效 √√√√√


autocmd BufNewFile *.py,*.cc,*.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.0")
call setline(5, "# Author: oldboy")
call setline(6, "# Organization:
www.oldboyedu.com")
call setline(7, "# Created Time :
".strftime("%F %T"))
call setline(8, "# Description:")
call setline(9,
"#####################################################
#########")
call setline(10, "")
endif
endfunc

##完整的配置

###vim 给光标所在行 加上提示 下划线
###tab键 修改为 4个空个长度
###自动 缩进 自动对齐

set nocompatible
set history=100
filetype on
filetype plugin on
filetype indent on
set autoread
set mouse=c
syntax enable
set cursorline
hi cursorline guibg=#00ff00
hi CursorColumn guibg=#00ff00
set foldenable
set foldmethod=manual
set foldcolumn=0
setlocal foldlevel=3
set foldclose=all
nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc'
: 'zo')<CR>
set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4
set smarttab
set ai
set si
set wrap
set sw=4
set wildmenu
set ruler
set cmdheight=1
set lz
set backspace=eol,start,indent
set whichwrap+=<,>,h,l
set magic
set noerrorbells
set novisualbell
set showmatch
set mat=4
set hlsearch
set ignorecase
set encoding=utf-8
set fileencodings=utf-8
set termencoding=utf-8
set smartindent
set cin
set showmatch
set guioptions-=T
set guioptions-=m
set vb t_vb=
set laststatus=4
set pastetoggle=<F9>
set background=dark
highlight Search ctermbg=black ctermfg=white
guifg=white guibg=black
autocmd BufNewFile *.py,*.cc,*.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.0")
call setline(5, "# Author: oldboy")
call setline(6, "# Organization:
www.oldboyedu.com")
call setline(7, "# Created Time :
".strftime("%F %T"))
call setline(8, "# Description:")
call setline(9,
"#####################################################
#########")
call setline(10, "")
endif
endfunc

shell数组

ip1=10.0.0.7
ip2=10.0.0.8
ip3=192.168.1.20
echo $ip1 $ip2 $ip3

#存放或使用 没有太多规律的信息
#使用shell数组
#array[1]
#数组名称[下标] #数组名称[元素名称]

[root@manager ~]#
[root@manager ~]# array[1]=10.0.0.7
[root@manager ~]# array[2]=10.0.0.61
[root@manager ~]#
[root@manager ~]# echo ${array[1]}
10.0.0.7
[root@manager ~]# echo ${array[*]}
10.0.0.7 10.0.0.61

数组的赋值方式
在这里插入图片描述
#手动批量创建 数组

[root@manager ~]# lidao=(oldboy alex oldbing)
[root@manager ~]# echo ${lidao[1]}
alex
[root@manager ~]# echo ${lidao[0]}
oldboy
[root@manager ~]# echo ${lidao[1]}
alex
[root@manager ~]#
[root@manager ~]# echo ${lidao[*]}
oldboy alex oldbing

#通过文件创建 数组

[root@manager ~]# name=(`awk -F: '{print $1}'
/etc/passwd`)
[root@manager ~]# echo ${name[0]}
root
[root@manager ~]# echo ${name[*]}
root bin daemon adm lp sync shutdown halt mail
operator games ftp nobody systemd-network dbus polkitd
tss abrt sshd postfix chrony ntp oldboy nginx tcpdump
mysql oldboy01 oldboy02 oldboy03 oldboy04 oldboy05
oldboy06 oldboy07 oldboy08 oldboy09 oldboy10
[root@manager ~]# echo ${#name[*]}
36

eg:
环境

cat >/server/scripts/ip_list.txt<<EOF
10.0.0.61
10.0.0.71
10.0.0.81
10.0.0.202
EOF

#检查文件中 指定的ip是否存在(ping通)
#方法1

cat /server/scripts/2.19.1-chk-ip.sh
#!/bin/bash
ip_list=( `cat /server/scripts/ip_list.txt` )
check_ip() {
ping -c1 -i1 -W1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo "$ip is ok"
else
echo "$ip is failed"
fi
}
main() {
for ip in ${ip_list[*]}
do
check_ip
done
}
main

#方法2

[root@manager ~]# ip_list=(`cat/server/scripts/ip_list.txt`)
[root@manager ~]# echo ${ip_list[*]}
10.0.0.61 10.0.0.71 10.0.0.81 10.0.0.202
[root@manager ~]# for((i=0;i<${#ip_list[*]};i++));do
echo ${ip_list[i]} ;done
10.0.0.61
10.0.0.71
10.0.0.81
10.0.0.202
[root@manager ~]# for ip in ${ip_list[*]}; do echo
$ip ;done
10.0.0.61
10.0.0.71
10.0.0.81
10.0.0.202

shell总结

# Log that something succeeded
success() {
[ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] &&
echo_success
return 0
}
action() {
local STRING rc #创建变量
STRING=$1 #函数第1个参数赋值给 STRING="ip is ok"
echo -n "$STRING " #显示 变量内容 不换行
shift #移动脚本或函数的参数 #执行后
$1是 /bin/true
"$@" && success $"$STRING" || failure $"$STRING"
#/bin/true && success || failure `
#success 显示 [OK] [确定]
rc=$? #命令执行结果
echo
return $rc
}
action "ip is ok" /bin/true
#屏幕输出
ip is ok [OK]
#补充
[root@manager ~]# set oldboy alex
[root@manager ~]# echo $1 $2
oldboy alex
[root@manager ~]# shift
[root@manager ~]# echo $1
alex
[root@manager ~]# echo $2
[root@manager ~]#

三剑客

sed

sed执行流程

在这里插入图片描述

sed N

[root@manager ~]# sed 'N;s#\n# #g' num.txt
1 2
3 4
5 6
7 8
9 10
[root@manager ~]# sed 'N;N;N;N;N;N;N;N;s#\n# #g'
num.txt
1 2 3 4 5 6 7 8 9
10
[root@manager ~]# sed 'N;N;N;N;N;N;N;N;N;s#\n# #g'
num.txt
1 2 3 4 5 6 7 8 9 10
#使用sed命令的中循环
#sed标签功能
[root@manager ~]# sed ':label ;N;s#\n# #g;t label'
num.txt
1 2 3 4 5 6 7 8 9 10
[root@manager ~]# tr '\n' ' ' <num.txt
1 2 3 4 5 6 7 8 9 10 [root@manager ~]#
[root@manager ~]# xargs <num.txt
1 2 3 4 5 6 7 8 9 10
[root@manager ~]# awk -vORS=" " '1' num.txt
1 2 3 4 5 6 7 8 9 10 [root@manager ~]#

sed功能

sed:功能:
增删改查
p(查) print
-n ‘3p’
-n ‘1,3p’
-n ‘/oldboy/p’
过滤日志: 时间范围 -n ‘/开始/,/结束/p’ access.log
d(删除) delete
cai (cia) c( replace 替换这一行的内容) a(append) i(insert)
s(替换) sub substitute
补充符号:
&

[root@manager ~]# seq 5 |sed '3c oldboyedu.com '
1
2
oldboyedu.com 
4
5
[root@manager ~]# seq 5 |sed '3a oldboyedu.com '
1
2
3
oldboyedu.com 
4
5
[root@manager ~]# seq 5 |sed '3i oldboyedu.com '
1
2
oldboyedu.com 
3
4
5

#&

[root@manager ~]# echo {1..20} |sed -r 's#[0-9]+#
<&>#g'
<1> <2> <3> <4> <5> <6> <7> <8> <9> <10> <11> <12> 
<13> <14> <15> <16> <17> <18> <19> <20>
[root@manager ~]# echo {1..20} |sed -r 's#[0-9]+#
<&>#g'

正则表达式

正则vs通配符

在这里插入图片描述

正则

在这里插入图片描述在这里插入图片描述
man perlretut

#取出 id:右边的数字
echo 'id:1 id:999 id:12306 id:996 oldboy666
alex777 12580' >id.txt
[root@manager ~]# #取 xxxx右边/左边 的内容
[root@manager ~]# #取出的位置
[root@manager ~]# ##perl正则 零宽断言 lookaround
[root@manager ~]# ###lookahead 匹配左边
[root@manager ~]# ###lookbehind 批量右边
[root@manager ~]# echo 'by oldboy linux' |grep -P '(?
<=old)boy'
by oldboy linux
[root@manager ~]# echo 'by oldboy linux' |grep -Po
'(?<=old)boy'
boy
[root@manager ~]# ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:d9:30:f5 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.61/24 brd 10.0.0.255 scope global
noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::a6c9:6aee:108b:2757/64 scope link
noprefixroute
valid_lft forever preferred_lft forever
[root@manager ~]# ip a s eth0 |grep -Po '[0-9.]+(?=/24)'
10.0.0.61
[root@m01 ~]# ip a s eth0 |grep -Po '(?<=inet )[0-9.]+'
10.0.0.61

在这里插入图片描述
在这里插入图片描述

awk

内容

awk格式
awk执行过程


内置变量
awk条件
比较表达式
正则
特殊 BEGIN和END
范围
if fork
awk数组
awk数组分析日志


格式与参数

awk 参数 ‘条件{动作}’ 文件 …

参数含义
-F指定分隔符
-v创建或修改awk变量 1次只能创建或修改1个变量

shell脚本中的变量 传递到awk中

[root@manager ~]# x=1
[root@manager ~]# y=21
[root@manager ~]# awk -vn1=1 -vn2=21 'BEGIN{print 
n1/n2}'
0.047619
[root@manager ~]# awk -vn1=$x -vn2=$y 'BEGIN{print 
n1/n2}'
0.047619

awk完整的执行过程

awk执行过程

1 读取文件内容之前执行awk命令行参数 -F或 -v执行BEGIN{}模块
2 正在读取文件读取文件的1行判断这一行是否满足条件满足 执行对应的动作不满足 读取下一行 直到文件结尾
3 读取文件后执行END{}里面的内容

在这里插入图片描述

行与列

名称含义
record 记录 行
field 字段 域 列

#取出第1行

[root@m01 ~]# awk 'NR==1' /etc/passwd
root:x:0:0:root:/root:/bin/bash

#取多行 取出 从第5行到最后1行

awk   'NR>=5' /etc/passwd

#取出2-5行的内容

[root@m01 ~]# awk 'NR>=2 && NR<=5' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

#过滤

[root@m01 ~]# awk '/oldboy/' /etc/passwd
oldboy01:x:1000:1000::/home/oldboy01:/bin/bash
oldboy02:x:1001:1001::/home/oldboy02:/bin/bash
oldboy03:x:1002:1002::/home/oldboy03:/bin/bash
oldboy04:x:1003:1003::/home/oldboy04:/bin/bash
oldboy05:x:1004:1004::/home/oldboy05:/bin/bash
oldboy06:x:1005:1005::/home/oldboy06:/bin/bash
oldboy07:x:1006:1006::/home/oldboy07:/bin/bash
oldboy08:x:1007:1007::/home/oldboy08:/bin/bash
oldboy09:x:1008:1008::/home/oldboy09:/bin/bash
oldboy10:x:1009:1009::/home/oldboy10:/bin/bash

#扩展
##awk只写条件 条件满足后 默认执行 {print $0}显示这一行的内容

[root@m01 ~]# awk '/oldboy/{print $0}' /etc/passwd
oldboy01:x:1000:1000::/home/oldboy01:/bin/bash
oldboy02:x:1001:1001::/home/oldboy02:/bin/bash
oldboy03:x:1002:1002::/home/oldboy03:/bin/bash
oldboy04:x:1003:1003::/home/oldboy04:/bin/bash
oldboy05:x:1004:1004::/home/oldboy05:/bin/bash
oldboy06:x:1005:1005::/home/oldboy06:/bin/bash
oldboy07:x:1006:1006::/home/oldboy07:/bin/bash
oldboy08:x:1007:1007::/home/oldboy08:/bin/bash
oldboy09:x:1008:1008::/home/oldboy09:/bin/bash
oldboy10:x:1009:1009::/home/oldboy10:/bin/bash

#RS 每一行结束标记 默认是回车

[root@m01 ~]# awk -vRS='/' '{print NR,$0}' /etc/passwd

[root@m01 ~]# seq 10|awk -vORS=' ' '{print $0}'
1 2 3 4 5 6 7 8 9 10 [root@m01 ~]# 
# 创建行分隔符
[root@manager ~]# awk -F: '{print $1,$3}' /etc/passwd

#调换 /etc/passwd 第1列和最后一行 内容

[root@m01 ~]#  sed -r 's#(^.*)(:x.*:)(.*)#\3\2\1#g' /etc/passwd

[root@m01 ~]# awk -F: -vOFS=: '{print $NF,$2,$3,$4,$5,$6,$1}' /etc/passwd

[root@m01 ~]#  awk -F: -vOFS=: '{tmp=$1;$1=$NF;$NF=tmp;print }' /etc/passwd

内置变量

内置变量说明
NRNumber of Record 记录号 行号
RSRecord Separator 记录分隔符 记录着每一行的结束标记支持正则
ORSOutput Record Separator awk显示每一行的时候 每一行之间的分隔符

$数字去列
$0表示一整行的内容
FS-F: === -vFS=: Field Separator 字段分隔符 菜刀
OFSOutput Field Separator 输出字段分隔符 输出每一列的时候 每一列之间分隔符 默认是空格 OFS内容 相当于是 ,的内容
NFNumber of Field 每一行有多少列

awk条件

比较表达式
正则
BEGIN{} 和END{}
范围

比较

#取行

[root@manager ~]# awk 'NR>=5' /etc/passwd

#取出/etc/passwd 中第3列 大于0并且小于1000的行

[root@m01 ~]#  awk -F: '$3>0 && $3<1000' /etc/passwd

#取出磁盘使用率高于20%的名字

[root@m01 ~]# df -h|awk -F'[ %]+' 'NR>1 && $5>2 {print $1,$5}'
/dev/sda1 3

#小坑预警:
##通过awk进行比较 如果某一列中有符号 awk会认为是字符串的对比 字符串的对比先比较第1位

[root@m01 ~]# df -h|awk -F'[ ]+' 'NR>1 && $5>20 {print $1,$5}'
/dev/sda1 3%
正则
符号含义
~匹配 $3 ~ /^[01]/
!~不匹配 排除 $3 !~ /^[01]/

# ^ 行开头 某一列的开头
# $ 行结尾 某一列的结尾


#取出 /etc/passwd中第3列 以数字1或0开头的行

[root@manager ~]# awk -F: '$3 ~ /^[01]/' /etc/passwd

#统计 access.log中 请求是.jpg或 .gif结尾的图 流量总和
##类型 $7
##流量 $10
##条件 : 找出第7列以.jpg或.gif结尾的 $7 ~ /.jpg$|.gif$/
##{动作}: {sum=sum+$10}

[root@m01 ~]#  awk '$7~/.jpg$|.gif$/ {sum=sum+$10}END{print sum/1024^2}' access.log
90.7682
[root@m01 ~]#  awk ' {sum=sum+$10}END{print sum/1024^2}' access.log
2363.68
BEGIN{} vs END{}
应用场景
BEGIN{}BEGIN里面的内容会在awk读取文件之前 运行1. 用来进行测试 与计算2.BEGIN定义 awk内置变量3.显示某列的时候 提前显示的标题
END{}END里面的内容 会在awk读取完文件后运行1. 先进行计算 最后在END{}输出结果
[root@manager ~]# #awk -F: '$3 ~ /^[01]/' /etc/passwd
[root@manager ~]# #awk -vFS=: '$3 ~ /^[01]/' /etc/passwd
[root@manager ~]# #awk 'BEGIN{FS=":"}$3 ~ /^[01]/' /etc/passwd
[root@manager ~]# awk -F: 'BEGIN{print "用户名","UID"}{print $1,$3}' /etc/passwd |column -t

范围
[root@m01 ~]#  awk 'NR==1,NR==5' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@manager ~]# awk '/root/,/nobody/' /etc/passwd
[root@m01 ~]# awk -F: '$3==0,$3==5' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
[root@m01 ~]# awk '$1~/root/,$1~/nobody/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
awk条件小结
名称应用场景
比较表达式通过awk内置变量使用 NR>5 $3>=10
正则配置某一列中 包含/不包含xxxx 日志过滤$3~/^[01]/
BEGIN{} 和END{}END{}输出最后的结果;BEGIN{}计算
范围过滤时间 /2015:11:02/,/2015:11:59/

if

#单分支 条件

if(条件)
   print
[root@manager ~]# awk 'NR==3' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@manager ~]# awk '{if(NR==3) print $0}' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin

#双分支

if(条件)
   print 
else
   print

#企业面试题:请过滤range.log中在device: {}里面出现了多少次oldboy,过滤并统计出来
环境

[root@m01 ~]# cat range.log 
oldboy is a linuxer.
device: {
    oo
        oldboy
        no sql
        this is log
        niu niu
}
oldboy
device: {
    oldboy
        no sql
        this is log
        niu niu
}
oldboy
device: {
    oldboy
        no sql
        this is log
        niu niu
}
device: {
            oldboy
                no sql
                this is log
                niu niu
        }
[root@m01 ~]# awk '/{/,/}/{if(/oldboy/) i++}END{print i}' range.log 
4
awk '
/{/ , /}/{  #条件 匹配 {} 里面的内容
  if(/oldboy/)    #二次过滤 找出{}中 并且 还是oldboy的
     i++          #计数    
 }
 END{
 print i          #显示结果
 }' range.log

for循环

c语言形式
专门用来给awk数组 循环

shellawk
for((i=1;i<=10;i++));do echo $i; donefor(i=1;i<=10;i++) print i

#显示 1…10 seq 10

[root@m01 ~]# awk 'BEGIN{for(i=1;i<=10;i++) print i }'
1
2
3
4
5
6
7
8
9
10

#计算 1+2+3…+10

[root@m01 ~]#  awk 'BEGIN{for(i=1;i<=10;i++) sum+=i ;print sum }'
55
[root@m01 ~]#  awk 'BEGIN{for(i=1;i<=10;i++) {sum+=i ;print sum} }'
1
3
6
10
15
21
28
36
45
55

#for配合NF
环境

cat chengji.txt
waiwai 90 98 98 96 96 92
xiaoyu 70 77 85 83 70 89
gege   85 92 78 94 88 91
xingxing 89 90 85 94 90 95
bingbing 84 88 80 92 84 82
dandan 64 80 60 60 61 62

#显示出姓名及每个人的平均数

[root@manager ~]# awk '{sum=$2+$3+$4+$5+$6+$7;print 
$1,sum/6}' chengji.txt 
waiwai 95
xiaoyu 79
gege 88
xingxing 90.5
bingbing 85
dandan 64.5
[root@manager ~]# awk '{sum=0;for(i=2;i<=NF;i++) 
sum+=$i;print $1,sum/(NF-1)}' chengji.txt 
waiwai 95
xiaoyu 79
gege 88
xingxing 90.5
bingbing 85
dandan 64.5
awk  '{
sum=0;
for(i=2;i<=NF;i++) 
   sum+=$i;
print $1,sum/(NF-1)
}' chengji.txt
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值