shell编程

shell的作用

解释执行用户输入的命令或程序等。

用户输入一条命令,shell就解释一条键盘输入命令,Linux给与响应的方式,称之为交互式。

shel是一块包裹看系统核心的壳,处于操作系统的最外层,与用户直接对话,把用户的输入, 解释 给操作 系统,然后处理操作系统的输出结果,输出到屏幕给与用户看到结果。

什么是shell脚本

当命令或者程序语句写在文件中,我们执行文件,读取其中的代码,这个程序文件就称之为shel脚本。在shel脚本里定义多条Linux命令以及循环控制语句,然后将这些Linux命令一次性执行完毕,执行脚本文件的方式称之为,非交互式方式。

  • windows中存在 *.bat 批处理脚本

  • Linux中常用 *.sh 脚本文件

shell脚本规则

在Linux系统中,shel脚本或者称之为 (bash shel程序) 通常都是vim编辑,由Linux命令、bash shell指令、逻辑控制语句和注释信息组成。

shebang

计算机程序中, shebang 指的是出现在文本文件的第一行前两个字符 #! 在Unix系统中,程序会分析 shebang 后面的内容,作为解释器的指令,例如

以 #!/bin/sh 开头的文件,程序在执行的时候会调用 /bin/sh ,也就是bash解释器。以 #!/usr/bin/python 开头的文件,代表指定python解释器去执行。

以 #!/usr/bin/env 解释器名称 ,是一种在不同平台上都能正确找到解释器的办法。 注意事项: 如果脚本未指定 shebang ,脚本执行的时候,默认用当前$shell去解释脚本,即 $SHELL如果 shebang 指定了可执行的解释器,如 /bin/bash /usr/bin/python ,脚 本在执行时,文件名会作为参数传递给解释器。

如果#!指定的解释程序没有可执行权限,则会报错"bad interpreter: Permission denied”如果#!指定的解释程序不是一个可执行文件,那么指定的解释程序会被忽略,转而交给当前的SHELL去执行这个脚本。 如果#!指定的解释程序不存在,那么会报错“bad interpreter: No such file or directory”。

#!之后的解释程序,需要写其绝对路径 (如: #!/bin/bash) ,它是不会自动到$PATH中寻找解释器的。如果你使用"bash test.sh"这样的命令来执行脚本,那么#!这一行将会被忽略掉,解释器当然是用命令行中显式指定的bash

脚本注释

以#

执行shell脚本的方式

  • bash script.sh 或 sh sripte.sh ,文件本身没权限执行,没x权限,则使用的方法,或脚本未指定 shebang ,重点推荐的方式

  • 使用 绝对/相对 路径执行脚本,需要文件含有x权限

  • source script.sh 或者 .script.sh ,代表 执行的含义,source等于点

  • 少见的用法sh < script.sh>

shell和运维

shel脚本语言很适合处理纯文本类型数据,目Linux的哲学思想就是一切皆文件,如日志、配置文件、文本、 网页文件,大多数都是纯文本类型的,因此shell可以方便的进行文本处理,好比强大的Linux三剑客(grep、sed、awk)

bash

  • bash是一个命令处理器,运行在文本窗口中,并能执行用户直接输入的台bash还能从文件中读取linxu命令,称之为脚本。

  • bash支持通配符、管道、命令替换、条件判断等逻辑控制语句。

  • bash有诸多方便的功能,有助于运维人员提升工作效率。

bash的历史文件

 ~/.bash_history

执行历史命令

!历史id

shell变量

变量含义

学生时代所学的数学方程式,如x=1,y=2,那会称之为x,y是未知数对于计算机角度,x=1,y=2等于定义了两个变量,名字分别是x,y,且赋值了1和2。

变量是暂时存储数据的地方,是一种数据标记(房间号,标记了客人所在的位置),数据存储在内容空间,通过调用正确的变量名字,即可取出对应的值。

变量名规则

变量如果用''包裹起来能识别特殊符号

用""不能识别特殊符号

名称定义要做到见名知意,切按照规则来,切不得引用保留关键字(help检查保留字。

  • 只能包含数字、字母、下划线

  • 不能以数字开头

  • 不能用标点符号

  • 变量名严格区分大小写

作用域

pstree查看检查进程树

环境作用域

全局作用域

本地变量:相当于局部变量

环境变量:也是全局变量

局部变量:针对在shell函数或是脚本中定义

1.每次调用bash/sh解释器执行脚本,都会开启一个子shell,因此不保留当前的shell变量,通过pstree 命令检查进程树(会显示父shell得内容) 2.调用source或者点符号,在当前shell环境加载脚本,因此保留变量

面试题

问以上内容会输出什么内容c

环境变量设置

环境变量一般指的是用export内置命令导出的变量,用于定义shel的运行环境、保证shell命令的正确执行。

shell通过环境变量确定登录的用户名、PATH路径、文件系统等各种应用环境变量可以在命令行中临时创建,但是用户退出shel终端,变量即丢失,如要永久生效,需要修改 环境变量配置文件

#用户个人配置文件 
~/.bash profile  ~/.bashrc #远程登录用户特有文件
#全局配置文件
/etc/profile 、 /etc/bashrc 
#且系统建议最好创建在 
/etc/profile.d/ 
#而非直接修改主文件,修改全局配置文件,影响所有登录系统的用户

检查系统环境变量的命令

  • set,输出所有变量,包括全局变量、局部变量(shell脚本文件中定义的变量)

  • env,只显示全局变量

  • declare,输出所有的变量,如同set

  • export,显示和设置环境变量值

  • unset, 取消变量的值,删除变量或者函数

  • readonly,只读变量,只有shell结束,只读变量失效

环境变量文件加载顺序

特殊变量

参数变量

shell的特殊变量,用在如脚本,函数传递参数使用,有如下特殊的,位置参数变量

$0  #获取she11脚本文件名,以及脚本路径;
$n  #获取shel1脚本的第n个参数,n在1~9之间,如$1 ,$2,$9 ,大于9则需要写,${10},参数空格隔开;
$#  #获取执行的she11脚本后面的参数总个数;
$*  #获取shel1脚本所有参数,不加引号等同于$@作用,加上引号"$*"作用是 接收所有参数为单个字符串,"$1 $2
$@  #不加引号,效果同上,加引号,是接收所有参数为独立字符串,如"$1”"$2”"$3”..,空格保留

面试题

$*和$@j加双引号的区别

$*如果用循环打印的话,会把所有的变量都作为一个整的字符串打印

$@会把所有的变量作为独立的字符串循环打印出来

状态变量

脚本返回值 : $?

#bin/bash
[ $# -ne 2 ]&&{
  echo "must two args"
  exit 119   #退出程序,且返回119的状态码,提供当前shell  $?变量的值,如是在函数中可以使用return 119的用法
}
echo '没错就是两个参数'


#[root@localhost ~]# vim test1.sh
#[root@localhost ~]# sh test1.sh 1 2
#没错就是两个参数
#[root@localhost ~]# sh test1.sh 1 2 3
#must two args
#[root@localhost ~]# echo $?
#119

获取上次后台执行程序的pid : $!

 nohup ping baidu.com & 1 >/dev/null
 #这个就是让命令在后台一直运行
 #echo $!  获取上次后台运行的进程号
 

获取脚本的id : $$

#bin/bash
[ $# -ne 2 ]&&{
  echo "must two args"
  exit 119   #退出程序,且返回119的状态码,提供当前shell  $?变量的值,如是在函数中可以使用return 119的用法
}
echo '没错就是两个参数'
echo "当前脚本的id是: $$"

shell变量扩展

#1、如果parameter变量值为空,返回word字符串,赋值给result变量
result = ${parameter:-word}    #
#2、如果para变量为空,则word替代变量值,且返回其值
result = ${parameter:=word}
#3、如果para变量为空,word当作stderr输出,否则输出变量值用于设置变量为空导致错误时,返回的错误信息
result = ${parameter:?word}
#4、如果para变量为空,什么都不做,否则word返回
result = ${parameter:+word}


# 1、如果parameter变量值为空,那result的值就是word
#如果parameter变量值不为空,那result的值就是parameter


#2、如果parameter变量值为空,那result的值就是word,parameter的值变为word
#如果parameter变量值不为空,那result的值就是parameter,parameter的值变为word

#3、如果parameter变量值为空,那末会提示word的提示
#如果parameter变量值不为空,那result的值就是parameter

实际应用

数据备份,删除过期数据的脚本

find xargs  搜索且删除
#删除7天以上的数据
# find 需要搜索的目录 -name 你要搜索文件的名称 -type 文件类型 -mtime +7|xargs rm -f
#如果这个path为空,就会从当前目录开始找
#这个就是一个漏洞
#也可以定义  path="/data/home"
find ${path} -name '*.tar' -type f -mtime +7|xargs rm -f

#也可以使用上面的变量扩展,如果path为空就会使用后面的地址
find ${path:=/data/home} -name '*.tar' -type f -mtime +7|xargs rm -f

shell子串

内置shell命令

echo:输出命令

#参数
#-n 不换行输出
#-e 解析字符串中的特殊符号
#\n 换行
#\r 回车
#\t 制表符 四个空格
#\b 退格
#打印命令,能够自己识别特殊符号
#printf "nish\tdasd\n"

eval:执行多个命令​​​​​​​

eval ll;cd /

exec:不创建子进程,执行后续命令,且执行命令后自动退出

exec date
#退出当前用户返回root用户,其中root用户

shell子串的花式用法

${变量}                   #返回变量值
${#变量}                  #返回变量长度,和字符串的长度
${变量:start}             #返回变量start(4)如果是4就是从4开始数值之后的字符且包含4的符号
${变量:start:length}      #提取start之后的length限制的字符
${变量#word}              #从变量开头删除最短匹配的word子串
${变量##word}             #从变量开头,删除最长匹配的word
${变量%word}              #从变量结尾删除最短的word
${变量%%word}             #从变量结尾开始删除最长匹配的word
${变量/pattern/string}    #用string代替第一个匹配的pattern
${变量//pattern/string}   #用string代替所有的pattern
[root@localhost ~]# name="heguli12113"
[root@localhost ~]# echo $name
heguli12113
[root@localhost ~]# echo ${name}
heguli12113
[root@localhost ~]# echo ${#name}
11
[root@localhost ~]# echo ${name:4}
li12113
[root@localhost ~]# echo ${name:4:1}
l

计算变量长度的各种用法

#利用wc
echo $name|wc -L   #-L统计长度最长的一行的元素的长度     -l统计行数

#利用数值计算expr命令
expr length "${name}"

#利用awk统计长度
echo "${name}" |awk `{print length($0)}`

#最快的统计方式
echo ${#name}

统计计算长度的时间

Shell编程,尽量使用linux内置的命令,内置的操作,和内置的函数,效率最高C语言开发,效率最高,尽可能的减少,管道符的操作

字符串截取

${变量#word}              #从变量开头删除最短匹配的word子串
${变量##word}             #从变量开头,删除最长匹配的word
${变量%word}              #从变量结尾删除最短的word
${变量%%word}             #从变量结尾开始删除最长匹配的word
${变量/pattern/string}    #用string代替第一个匹配的pattern
${变量//pattern/string}   #用string代替所有的pattern


[root@localhost ~]# name="abc123dsujfieabc"
[root@localhost ~]# echo $name
abc123dsujfieabc
[root@localhost ~]# echo ${name:2:3}
c12
[root@localhost ~]# echo ${name#a*c}
123dsujfieabc
[root@localhost ~]# echo ${name##a*c}

批量修改文件名

for filename in `ls`;do mv $filename `echo ${filename/luoyue/heguoli}`;done

父子shell

1.source和点,执行脚本,只在当前的shell环境中执行生效

2指定bash sh解释器运行脚本,是开启subshell,开启子shell运行脚本命令

3../script,都会指定shebang,通过解释器运行,也是开启subshell运行命令

父shell

通过pstree展示出来能够看到的

还可以通过一条命令来查看父子关系

子shell

多个子shell

内置命令和外置命令

1、什么事内置命令,什么是外置命令

  • 内置命令:在系统启动时就加载入内存,常驻内存,执行效率更高,但是占用资源。cd

  • 外置命令:系统需要从硬盘中读取程序文件,再读入内存加载

外置命令,也称之为,自己单独下载的文件系统命令,处于bash shell之外的程序。

外置命令特点:外置命令执行一定会产生子shell

内置命令 内置命令不会产生子进程去执行 内置命令和shell是为一体的,是shell的一部分,不需要单独去读取某个文件,系统启动后,就执行在内存中了 type命令验证即可

对于linux特殊符号的整理

shell

${vars}         #取出变量结果
$()             #再括号中执行命令,且拿到命令的执行结果
``              #再括号中执行命令,且拿到命令的执行结果
()              #开启子she11执行命令结果
$vars           #取出变量结果

shell数学计算

运算符号

算数运算命令

双小括号(())

注意:计算只能是整数,小数是不会计算出来的

计算脚本

#bin/bash
#编写一个计算的程序
#1、让用户输入两个数字,并判断数字是否合理
#2、判断用户输入的计算符号是否和理

jisuan(){
 echo "你输入有误"
#错误返回码 
 exit 1

}
#获取用户输入的信息
# read -p "提示用户的信息" 获取输入的值
read -p "请输入数字:" num1

#if []这个两边必须要有空格,固定格式
#-n 判断是否为空,为空执行下一步,反之不成立
if [ -n "`echo $num1|sed 's/[0-9]//g'`" ]
 then
  jisuan
fi


#第二步输入计算符号
read -p "请输入计算符号(只能是+,-,*,/):" fun
if [ "${fun}" != "+" ] && [ "${fun}" != "-" ] && [ "${fun}" != "*" ] && [ "${fun}" != "/" ]
 then
   echo"你输入的运算符有误!!!"
   jisuan
fi

#输入第二个数字
read -p "请输入数字:" num2

if [ -n "`echo $num2|sed 's/[0-9]//g'`" ]
 then
  jisuan
fi

#计算结果,利用(())
echo "${num1}${fun}${num2}的计算结果是:$((${num1}${fun}${num2}))"
let命令

let也可以用来进行数值计算,只是他的效率没有(())高

[root@localhost ~]# num=1
[root@localhost ~]# let num=num+1
[root@localhost ~]# echo num
num
[root@localhost ~]# echo $num

[root@localhost ~]# 

检查网站是否正常运行

#bin/bash
chechk_nginx(){
   timeout=5
   #相当于一个计数器
   fails=0
   success=0
   #循环检测
   while true
     do
      wget --timeout=${timeout} --tires=1 http://www.baidu.com -q -0 /dev/null
      #echo $?如果上条命令正确执行了,这个值就会返回0
      #-ne 是不等于的意思
      if [ $? -ne 0 ]
        then
      #计算
          let fails=fails+1
      else
          let success=success+1
      fi
      #判断成功次数大于等于1。
      #$获取到变量的值
      if [ $success -ge 1 ]
         then
           echo"这个网站能够成功访问没有问题"
           #返回一个成功的状态码为0
           exit 0
      fi
      #判断网站链接有问题
      if [ $fails -ge 1 ]
        then
          echo"这个网站连接有问题"
          exit 1
      fi
   done
}
chechk_nginx
expr命令

这个命令不太好用,使用这个命令要给它传入参数,参数都是用空格隔开的

像特殊符号要在前面加个转义符

[root@localhost ~]# expr 3 + 5
8
[root@localhost ~]# expr 3 * 5
expr: 语法错误
[root@localhost ~]# expr 3 \* 5
15
[root@localhost ~]# #逻辑判断
[root@localhost ~]# expr 5 \> 6
0
[root@localhost ~]# #计算长度
[root@localhost ~]# expr length 123456665tg
11

expr模式匹配

[root@localhost ~]# #统计文件字符个数
[root@localhost ~]# expr check_nginx.sh ":" ".*\.sh"
14
[root@localhost ~]# 

判断文件名是否合法

#bin/bash
#使用expr判断文件名是否合法
if expr "$1" ":" ".*\.sh" &> /dev/null
  then
    echo "这是一个正确的脚本文件"
else
    echo "文件名不合法"
fi

判断字符串长度

#bin/bash
str1="i am he guo li, i come from YongZhou"
for str in $str1
 do
    if [ `expr length $str` -le 3 ]
      then
        echo "$str"
    fi
 done
bc命令

bc命令也可以用来进行简单运算

[root@localhost ~]# 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'. 
1+1
2
1+2
3
1.1*2
2.2

复杂的计算你用管道符

bc命令

[root@localhost ~]# echo {1..100}
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
[root@localhost ~]# echo {1..100} |bc
(standard_in) 1: syntax error
#利用echo输出一串数字,再利用tr换掉空格,再用bc命令进行计算
[root@localhost ~]# echo {1..100} |tr " " "+"|bc
5050
[root@localhost ~]# echo {1..100} |tr " " "+"
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+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100
#也可以利用seq生成一个序列
[root@localhost ~]# echo `seq -s "+" 100`|bc
5050
[root@localhost ~]# 

双小括号

[root@localhost ~]# echo $((`seq -s "+" 100`))
5050

expr命令

[root@localhost ~]# #expr命令计算,有一定的复杂性,它需要接受参数才能进行计算
[root@localhost ~]# #接受以空格分开的多个参数
[root@localhost ~]# #这个时候需要用到参数构造函数xargs
[root@localhost ~]# seq -s "+" 100 |xargs
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+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100
[root@localhost ~]# seq -s "+" 100 |xargs|expr
expr: 缺少操作数
Try 'expr --help' for more information.
[root@localhost ~]# seq -s "+" 100 |xargs expr
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+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100
[root@localhost ~]# seq -s " + " 100 |xargs expr
5050
[root@localhost ~]# 
awk命令
[root@localhost ~]# #利用awk计算
[root@localhost ~]# echo

[root@localhost ~]# echo "1.1 2.2"|awk '{print($1+$2)}'
3.3
[root@localhost ~]# echo "1.1 2.2"|awk '{print($1*$2)}'
2.42
[root@localhost ~]# echo "1.1 2.2"|awk '{print($2/$2)}'
1
[root@localhost ~]# 
中括号[]
[root@localhost ~]# echo $[num+1]
6
[root@localhost ~]# echo $[num-1]
4

shell条件测试

shell条件测试得出真假的概念

有两种形式

1、test命令

2、[]中括号

test条件测试

test命令评估一个表达式为真还是假,如果为真它的状态码为0,如果为假则是其他的状态码,通过#?进行取值

#test命令的参数
#-e 判断该文件是否存在,(普通文件,目录)存在则为真,不存在则为假


[root@localhost ~]# test -e test.sh
[root@localhost ~]# echo $?
0
[root@localhost ~]# 

test命令一般用来测试一个文件是否存在或者是否有某个权限,以及两个对象的比较等等

文件类型判断

	示例命令 test -e filename
  		-e :该文件是否存在
  		-f :该文件是否存在且是file类型
  		-d : 该文件是否存在且为目录
  		-b:该文件是否存在且为block device装置
  		-c:该文件是否存在且为character device装置
  		-S:该文件是否存在且为Socket文件
  		-p:该文件是否存在且为pipe文件
  		-L:该文件是否存在且为连接档

文件权限测试

	示例命令 test -r filename
	-r:该文件是存在且具有可读属性
	-w:该文件是否存在且具有可写属性
	-x:该文件是否存在且具有可执行权限
	-u:该文件是否存在且具有SUID
	-g:该文件是否存在且具有SGID
	-k:该文件是否存在且Sticky bit属性
	-s:该文件是否存在且为非空白文件

两文件之间的比较

示例命令 test  file1 -nt file2
	-nt:(newer than)file1是否比file2新
	-ot: (older than)file1是否比file2旧
	-ef:判断file1与file2是否为同一文件

两整数间的判断

	示例命令 test n1 -eq n2
	-eq :两整数是否相等   equal
	-ne: 两整数不相等    not equal
	-gt:  n1是否比n2大    great than
	 -lt:  n1是否比n小       less than
	 -ge:n1是否大于等于n2 greater than or equal
	 -le:n1是否小于等于n2   less than or equal

判断字符串

	示例命令  test -z string  
	-z:判断字符串是否为0.若为空字符串,返回true,否则返回false
	-n:判断字符串是否非为0。若为空字符串,则返回false,否则返回false
	另外 判断两个字符串是否相等或不等,还可以用 == 或 != 判断,和其他语言一样

多重条件判断

	-a  作用就是and 如 test -r file -a -x file 只有当file有读,可执行权限才返回true
	-o	  作用就是or  如 test -r file -o -x file 当file有读,可执行权限,只要有一个满足就返回true
	!反状态	如 test ! -r file 当file没有可读权限时返回true

命令实践

#-e 判断文件是否存在,存在就为真,否则就为假she11对于真假判断的逻辑,提供 && 与运算,并且的,并且的两端,是递进的关系 , 
#A条件 && B条件当A条件成立,并且执行B条件
#A条件||B条件当A条件不成立的时候,才会执行B条件

这个用来进行简单的判断

[root@localhost ~]# test -e test.sh && echo "文件已存在" || touch test.sh 
文件已存在
[root@localhost ~]# test -e test3.sh && echo "文件已存在" || touch test3.sh 
[root@localhost ~]# ll

中括号的条件测试[ ]

脚本中经常进行条件测试,用的最多的,都是中括号 [ ] test和[ ]的作用是一样 注意的点:中括号,前后的空格必须有。

[ -n "$filename"]
注意! ! !
在条件测试中使用变量的时候,要加上双引号
[root@localhost ~]# [ -f jisuan.sh ] && echo "这是一个文件" || echo "这不是一个文件"
这是一个文件
[root@localhost ~]# filname = test1.sh
bash: filname: 未找到命令...
[root@localhost ~]# filname=test1.sh
[root@localhost ~]# [ -f "$filname" ] && echo "这是一个文件" || echo "这不是一个文件"
这是一个文件
[root@localhost ~]# 

字符串比较测试

比较两个字符串是否相等的情况

=  判断是否相等
!= 判断是否不相等
!  取结果的反义

注意

  • 对于字符串变量的比较

  • 一定要记住给变量添加双引号

  • 使用等于号的值判断,左右两边也必须有空格

数值比较测试

1、[]括号:在括号里面要加转译符号,才能成功识别到

[root@localhost ~]# [ 2 \> 1 ] && echo "yes" || echo "no"
yes
[root@localhost ~]# [ 2 \< 1 ] && echo "yes" || echo "no"
no
[root@localhost ~]# [ 2 != 1 ] && echo "yes" || echo "no"
yes

[]括号和test这个都支持-eq 或者 == 的符号

2、双中括号

对单中括号的补充,还支持正则表达式

在双括号中,就不需要转译符号了

在公作中用的比较多的是中括号

逻辑判断符号

逻辑运算脚本简单数值判断

#bin/bash

#判断用户输入的数值是否等于1或2
#1、接受用户输入的数值
read -p "请输入数字:" num
#进行判断
[ "$num" -ne 1 -a "$num" != 2  ] && {
    echo "脚本出错,请你输入正确的数值"
    exit 1
}
[ "$num" -eq 1 ] &&{
    echo "$num"
    exit 0
}
[ "$num" = 2 ] &&{
    echo "$num"
    exit 0
}

简单脚本

#bin/bash
#安装两个软件的脚本,一个是taobao.sh,一个是jingdong.sh
#1、要获取到这两个脚本文件的文件路径
path=/home
#2、判断这个文件夹下是否有这两个文件
#判断要优先处理错误的情况
[ !-d "&path" ] && {
    mkdir "$path" -p
}
#提醒用户输入数字
cat <<END
    1.安装淘宝
    2.安装京东
    3.退出安装
END
read -p "请输入你选择安装的程序:" num
#对输入的数字进行逻辑判断,看输入的数字是否为数字的正确格式
expr $num + 1 &> /dev/null

#判断上次的结果是否为正确的
[ "$?" -ne 0 ] &&{
    echo "你输入的不是数字"
    exit 1
}
#如果文件夹以经存在,进行数字判断
[ "$num" -eq 1 ]&&{
    echo "你正在安装淘宝"
    sleep 2
    echo "你已安装成功"
    exit 0
}
[ "$num" -eq 2 ]&&{
    echo "你正在安装京东"
    sleep 2
    echo "你已安装成功"
    exit 0
}
#
[ "$num" -eq 3 ]&&{
    exit 0
}
#限制用户的输入必须是1,2,3
#这个时候需要用到正则表达式
[[ ! "$num" =~ [1-3] ]]&&{
    echo "你输入的数字必须是1,2,3"
    echo "请按照提示输入"
    exit 4
}

if判断语句

单分支if语句

# 语法
if <条件测试>  #例如[],[[]],test
  then
    #执行别的语句
fi

双分支if语句

# 语法
if <条件测试>  #例如[],[[]],test
  then
    if <条件测试>
     then 
       #执行别的语句
    fi
fi

if-else

# 语法
if <条件测试>  #例如[],[[]],test
  then
       #条件成立执行的语句
else
       #条件不成立执行的语句
fi

多分枝处理

# 语法
if <条件测试>  #例如[],[[]],test
  then
       #条件成立执行的语句
elif <条件>
  then
       #执行语句
else
       #条件不成立执行的语句
fi

统计错误日志

#bin/bash
#1、首先要找到这个文件的具体位置
path=/jiaoben
#判断这个文件夹是否存在
if [ ! -d "$path" ]
  then
    echo"该目录不存在"
    exit 1
fi
#如果这个文件夹存在的话,查看文件
logs="$path"/log.txt
errorstr=`cat "$logs"|grep error`
#判断文件是否有error,有error就输出error
if [ `expr length $"errorstr"` -ge 1 ]
   then
     num=`cat "$logs"|grep error|wc -l`
     echo"日志中存在"$num"次错误日志,请注意查看"
else
     echo"日志正常"
fi

shell函数

函数的特点,类似于alias别名一样,能够简化linux命令的操作,让整个命令更易读,更易用

  • 函数,就是将你需要执行的shell命令,组合起来,组合成一个 函数体

  • 还得给这个函数体,起一个名字,这个名字就称之为 函数名

  • 函数名字+函数体

  • 以后你想执行这个函数,就使用这个函数名字即可

使用函数的好处是什么?

  • 将相同的程序,定义,封装为一个函数,能够减少程序的代码数量 。

  • 提高开发效率使用函数,能让你写更少的代码,早点写完代码。

  • 函数能够增加程序可读性,易读性,容器管理。

格式

# 标准she11函数定义
function 函数名(){
     函数体
     你想执行的linux命令。。。
     return 返回值
}

#当使用function关键字时候,可以省略
function 函数名{
       函数体
       你想执行的哪些命令。。。
       return 返回值
}
#超级懒人写法,she11老司机的时候必须有括号
函数名(){
       函数体
       代码。。
       return 返回值
} 
#执行函数
函数名

有关函数执行的基础概念

  • 执行shell函数,直接写函数名字即可,无需添加其他内容

  • 函数必须先定义,再执行,shell脚本自上而下加载

  • 函数体内定义的变量,称之为局部变量

  • 函数体内需要添加return语句,作用是退出函数,且赋予返回值给调用该函数的程序,也就是shell脚本

  • return语句和exit不同

  • return是结束函数的执行,返回一个 (退出值、返回值)

  • exit是结束shell环境,返回一个 (退出值、返回值) 给当前的shell函数如果单独写入一个文件里,需要用source读取

  • 函数内,使用local关键字,定义局部变量,

脚本美化

实战

日志压缩切割打包

脚本

#!/bin/bash

# 创建转储日志压缩存放目录
path=/root/jiaoben/logs
if [ ! -d "$path" ]; then
  echo "日志目录不存在,创建目录:$path"
  mkdir -p /root/jiaoben/logs
fi
# 当前时间
time=$(date -d "yesterday" +"%Y-%m-%d")
# 进入转储日志存放目录
cd /root/jiaoben/logs
# 对目录中的转储日志文件的文件名进行统一转换
for i in $(ls ./ | grep "^\(.*\)\.[[:digit:]]$"); do
  mv ${i} ./$(echo ${i}|sed -n 's/^\(.*\)\.\([[:digit:]]\)$/\1/p')-${time}
done
# 对转储的日志文件进行压缩存放,并删除原有转储的日志文件,只保存压缩后的日志文件
for i in $(ls ./ | grep "^\(.*\)\-\([[:digit:]-]\+\)$"); do
  tar cvf ${i}.tar ./${i}
  rm -rf ./${i}
done
# 只保留最近7天的压缩转储日志文件
find /root/jiaoben/logs/* -name "*.tar" -mtime 7 -type f -exec rm -rf {} \;

定时任务

#编辑定时任务
crontab -e
#查看定时任务
crontab -l
#里面的内容
* * * * * /bin/bash 脚本路径 &> /dev/null
crontab的命令构成为 时间+动作,其时间有分、时、日、月、周五种,操作符有
* 取值范围内的所有数字
*     *   *    *   *
分    时  日   月   周
/ 每过多少个数字
- 从X到Z
,散列数字
crontab 文件中的行由 6 个字段组成,不同字段间用空格或 tab 键分隔。前 5 个字段指定命令要运行的时间
	分钟 (0-59)
	小时 (0-23)
	日期 (1-31)
	月份 (1-12)
	星期几(0-6,其中 0 代表星期日)
	第 6 个字段是一个要在适当时间执行的字符串

#2.crontab实际操作
1分钟执行一次
*/1 * * * * /root/hello.sh >> /root/hello.txt(存入的名字和位置自选)(一定要绝对路径)



在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * myCommand.sh   与上面的步骤同上



每晚的21:30重启smb
30 21 * * * /etc/init.d/smb restart

 #定时任务重启
systemctl restart crond.service


#配置
*/1 * * * * /bin/bash /root/jiaoben/freeneicun.sh &> /dev/null
0 0 * * * /bin/bash /root/jiaoben/cutlogs.sh &> /dev/null

邮件服务Shell脚本发送邮件(CentOS+mailx+QQ邮箱)

  1. 准备工作 打开邮箱设置,开启pop3/smtp服务和imap/smtp服务

安装mailx:

yum install -y mailx

  1. 配置 设置/etc/mail.rc文件,在文件尾追加如下配置

set from=xxx@qq.com						#发件人邮箱
set smtp=smtp.qq.com
set smtp-auth-user=xxx@qq.com		#登录用户名
set smtp-auth-password=					#邮箱授权码,在QQ邮箱设置界面发短信生成
set smtp-auth=login							#登录
  1. 发送邮件

#/bin/bash
#获取可使用内存的值
freeused=`free -m | awk 'NR==2 {print $7}'`
datetime=`date +"%Y-%m-%d %H:%M:%S"`
# 设置收件人、发件人、邮件主题和正文
recipient="2158538204@qq.com"
subject="Test Email from Shell Script"
body=""$datetime"   可使用内存还剩余"$freeused",请清理空间"
if [ $freeused -lt 500 ]
  then 
   # 使用mailx发送邮件
   # echo "$body" | mailx -s "$subject" "$recipient"
   
   # 检查是否发送成功
   if [ $? -eq 0 ]; then
       echo "邮件发送成功!"
   else
       echo "邮件发送失败."
   fi
   echo "哈哈"
   echo ""$datetime"  可使用内存还剩余"$freeused"" >> /root/jiaoben/logs/log.1
else 
   echo ""$datetime"   可使用内存还剩余"$freeused,请放心使用""
   echo ""$datetime"  可使用内存还剩余"$freeused"" >> /root/jiaoben/logs/log.1
fi

数据库备份脚本

分库备份

#bin/bash
use=root
passwd=Abcdefg@123
backpath=/root/mysql/backup
#-判断文件夹是否存在,如果不存在创建文件夹
if [ ! -d "$backpath" ]
  then
    mkdir -p "$backpath"
    echo "文件夹创建成功"
fi
#登录数据库
cmd="mysql -u$use -p$passwd"
#备份数据库
dump="mysqldump -u$use -p$passwd"
#获取库名列表
list=`$cmd -e "show databases;" 2>/dev/null | sed 1d |egrep -v "_schema|mysql"`
echo "---------开始备份---------"
echo "$list"
for database in $list
 do
  $dump $database 2>/dev/null |gzip >${backpath}/${database}_$(date +%m%d).sql.gz
  echo "$database备份完成"
done
echo "全部备份完成"

分表备份

#bin/bash
use=root
passwd=Abcdefg@123
backpath=/root/mysql/backup
#-判断文件夹是否存在,如果不存在创建文件夹
if [ ! -d "$backpath" ]
  then
    mkdir -p "$backpath"
    echo "文件夹创建成功"
fi
#登录数据库
cmd="mysql -u$use -p$passwd"
#备份数据库
dump="mysqldump -u$use -p$passwd"
#获取库名列表
list=`$cmd -e "show databases;" 2>/dev/null | sed 1d |egrep -v "_schema|mysql|sys"`
echo "---------开始备份---------"
echo "$list"
for database in $list
 do
  #获取表名
  tables=`$cmd -e "use $database;show tables;" 2>/dev/null | sed 1d `
  for j in $tables
    do
  #备份 
    echo "正在备份$datatbase数据库的$j表"
    $dump -B --databases $database --tables $j 2>/dev/null  >${backpath}/${database}-${j}_$(date +%m%d).sql
    echo "$database数据库的$j表备份完成"
  done
done
echo "全部备份完成"

数据库状态检测

1、端口检测

本地监控

#netstat
netstat -nlp |grep mysql|wc -l
#ss
ss -pl|grep mysql|wc -l
#lsof
lsof -i |grep mysql|wc -l

远端服务器

#telnet
telnet 172.16.10.72 3306 |grep Connected 2>/dev/null |wc -l
#nmap
nmap 127.0.0.1 -р 3306
#ss
ss -tunlplgrep mysql |wc -1

进程监控

ps -ef |grep mysql|wc -l

rsync启停脚本

#查看安装的版本
rpm -qa rsync
rsync-3.1.2-12.el7_9.x86_64
#查看有没有rsync.cof的配置文件
ls -l /etc/rsyncd.cof
#查看reync占用的端口
netstat -nlp |grep 873
#启动rsync
/usr/bin/rsync --daemon
#!/bin/bash
#判断输入的参数不是一个的情况,$#返回脚本传递参数的个数,$0获取脚本文件名称
if  [ "$#" -ne 1 ]
  then
   echo "请输入正确的参数:start|stop|restart"
fi
#当用户选择启动
if [ "$1" = "start" ]
  then
    /usr/bin/rsync --daemon
    sleep 2
    if [ `ps -ef|grep rsync |wc -l` -ge 2 ]
      then
        echo "rsync启动成功"
        exit 0
    fi
elif [ "$1" = "stop" ]
  then
    killall rsync &> /dev/null
    sleep 1
    if [ `netstat -nlp|grep rsync |wc -l` -eq 0 ]
     then
        echo "rsync关闭成功"
        exit 0
    fi
elif [ "$1" = "restart" ]
  then
    killall rsync &> /dev/null
    sleep 2
    stoprsync=`netstat -nlp|grep rsync |wc -l`
    /usr/bin/rsync --daemon
    startrsync=`netstat -nlp|grep rsync|wc -l`
    if [ "$stoprsync" -eq 0 -a "$startrsync" -ge 2 ]
      then
        sleep 1
        echo "rsync重启成功"
        exit 0
    fi
else
     echo "请输入正确的参数:start|stop|restart"
     exit 1
fi


 

  • 14
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值