shell开发

shell基础

shell脚本的目的:将复杂重复的执行过程,通过逻辑代码组成一个脚本文件,只需要执行脚本文件即可

脚本中的变量被引用时,会被赋值,脚本执行完后会根据执行脚本的方式决定变量赋值是否保留

执行脚本的方式:

source 脚本名

. 脚本名

#以上两种方式执行脚本时,被赋值的变量会保留在当前shell

bash 脚本名 

./脚本名

#以上方式执行脚本时,变量会在shell执行完脚本后消失

数值计算命令

双小括号

双小括号"(())"会运算里面的数值,并返回运算结果

[root@test ~]# echo $((10*2))
20
[root@test ~]# ((b=10*2))
[root@test ~]# echo $b
20
[root@test ~]# 

let命令

let命令用于数值计算,效果等同于双小括号"(())",但是双小括号的效率更高

[root@test ~]# a=10
[root@test ~]# let a=a+10 && echo $a
20
[root@test ~]# 

expr命令

expr命令可以用于数值计算、逻辑判断等

#查看expr命令的帮助文档
[root@test ~]# expr --help  
Usage: expr EXPRESSION
  or:  expr OPTION

      --help     display this help and exit
      --version  output version information and exit

       .........

or available locally via: info '(coreutils) expr invocation'
[root@test ~]# 

#expr用于数值计算,需要传入参数进行计算,每个参数以空格隔开
[root@test ~]# expr 10 - 5
5

#但是使用有特殊含义的元字符时(例如*、/),会识别失败,需要加上反斜杠转义
[root@test ~]# expr 10 * 5
expr: syntax error: unexpected argument ‘1.txt’
[root@test ~]# expr 10 \* 5
50

#通过length选项可以统计字符长度
[root@test ~]# expr length abcde
5

#除了数值计算、字符长度统计,还可以进行逻辑判断,0为假,1为真
[root@test ~]# expr 1 \> 10
0
[root@test ~]# expr 1 \< 10
1

expr模式匹配

#expr支持模式匹配功能,有两个特殊符号,":"和".*" 
#":"表示计算字符的长度
#".*"表示匹配任意长度的字符,这个可以自定义,安装需求匹配
#用法:expr [字符串] ":" [匹配要求]
[root@test ~]# expr abcde,abcde,abcde ":" ".*"
17

#根据文件的后缀来统计文件名的长度
[root@test ~]# expr test.sh ":" ".*\.sh"
7

expr检查文件名是否合法

[root@test ~]# cat test1.sh 
#! /bin/bash

if expr $1 ":" ".*\.sh" &> /dev/null
    then
      echo "this is a script file"
else
    echo "this is not a script file"
fi
[root@test ~]# chmod +x test1.sh 
[root@test ~]# ./test1.sh abcd.sh
this is a script file
[root@test ~]# ./test1.sh abcd.dasda
this is not a script file
[root@test ~]# 

expr找出长度不大于6的单词

[root@test ~]# cat test1.sh 
#! /bin/bash

for a in a ab abc abcd abcde abcdef abcdefg
    do
        if [ `expr length $a ` -le 5 ];then 
            echo $a
	fi
    done
[root@test ~]# chmod +x test1.sh 
[root@test ~]# ./test1.sh 
a
ab
abc
abcd
abcde
[root@test ~]# 

bc命令

bc命令是一个在命令行中运行的计算器,支持交互式,并且支持小数

#直接输入bc命令可以进入交互式界面,如果没有bc命令就yum安装
[root@test ~]# bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
10 - 5
5
2*10
20
~~~

bc命令结合管道符计算

~~~bash
#echo不识别乘号,加上管道符和bc命令就可以识别出来
[root@test ~]# echo "2*4"
2*4
[root@test ~]# echo "2*4" | bc
8
[root@test ~]# 
~~~

计算1到1000的总和

~~~bash
#方法一
[root@test ~]# echo {1..1000} | tr " " "+" | bc
500500
[root@test ~]# 

#方法二
#seq生成序列,-s选项指定分隔符
[root@test ~]# seq -s "+" 1000 | bc
500500
[root@test ~]# 

#方法三
#expr接受参数,所有在seq -s替换时主动加上空格,再传给expr进行计算
[root@test ~]# seq -s " + " 1000 |xargs expr 
500500
[root@test ~]# 

~~~



### awk命令进行数值计算

awk一般用于处理文本,也可以用于数值计算

~~~bash
[root@test ~]# echo "10 20" | awk '{print $1*$2}'
200
[root@test ~]# 
~~~



### 中括号进行数值计算

~~~bash
[root@test ~]# num=$[5*2] && echo $num
10
[root@test ~]# 
~~~



## 数值比较

### 数值比较的符号
![在这里插入图片描述](https://img-blog.csdnimg.cn/c25d5331fabb4805822ed1d85308c94d.png#pic_center)


注意!使用数学符号时需要加上反斜杠“\”转义,不然无法识别

双中括号与单中括号的用法、效果一致,但是双中括号**支持正则表达式**,而且**不需要转义**,一般使用的是单中括号,但是在复杂的脚本中会使用到双中括号。



## 逻辑判断

### 逻辑判断符号
![在这里插入图片描述](https://img-blog.csdnimg.cn/6bf868765dc043559cac742d75795635.png#pic_center)
## 编写脚本常用命令

### read

~~~bash
#一般用于接收用户输入的参数
#-p 设置提示信息
#-t 设置过期时间
[root@test ~]# read -p "请输入姓名和年龄:" -t 20 name age
请输入姓名和年龄:tom 18
[root@test ~]# echo $name $age
tom 18
[root@test ~]# 

~~~



### test

~~~bash
#test命令用于条件测试,判断表达式结果的真假,真为0,假为非0,通过“$?”取值
#-e 判断该文件(普通文件)是否存在,存在为真,不存在为假
[root@test ~]# ls
anaconda-ks.cfg  a.txt  
[root@test ~]# test -e a.txt 
[root@test ~]# echo $?
0
[root@test ~]# test -e b.txt 
[root@test ~]# echo $?
1
[root@test ~]# 

#-f 只判断文件是否存在
#-d 只判断目录是否存在
#test简单用法:检查目录是否存在,不存在就创建。
[root@test ~]# cd /opt/
[root@test opt]# ls
data
[root@test opt]# test -d "sakura" && echo "该目录已经存在" || mkdir sakura
[root@test opt]# ls
data  sakura
[root@test opt]# test -d "sakura" && echo "该目录已经存在" || mkdir sakura
该目录已经存在
[root@test opt]# 
~~~



### 中括号[ ]

中括号可以用来条件测试,效果与test命令相同

~~~bash
[root@test opt]# ls
data  sakura
[root@test opt]# [ -d sakura ] && echo "该目录存在" || echo "该目录不存在"
该目录存在

#如果使用变量,需要加上双引号
[root@test opt]# file=sakura123
[root@test opt]# [ -d "$sakura123" ] && echo "该目录存在" || echo "该目录不存在"
该目录不存在
[root@test opt]# 
~~~







## 函数

在脚本中定义的函数可以在后面的代码中调用,可以将一些需要多次执行、重复的操作写成一个函数,需要的时候直接调用即可。

~~~bash
#标准shell函数写法
function 函数名(){

   函数主体
   return 返回值
   
}

#偷懒shell函数写法
function 函数名{
    
    函数主体
    return 返回值
    
}

#简洁shell函数写法
函数名(){

    函数主体
    return 返回值

}

#需要调用时,输入函数名即可调用。例:
[root@test ~]# cat a.txt 
#! /bin/bash

printf_a(){
    a=10
    echo $a

}

printf_a  
[root@test ~]# ./a.txt 
10
[root@test ~]# 

#注意,exit和return都是返回状态值,但是return只能在脚本中使用,表示结束当前函数,exit是结束当前的shell。
#如果将函数写入到一个文件中,再进行调用,需要使用source读取

~~~



## if条件语句

if语句在脚本中比较常见,在命令行中也可以直接使用,以分号结尾

~~~bash
#语法:(单分支)
if [条件表达式];then
    [代码]
if
#if后面跟判断条件表达式,以“;then”结束


#语法:(双分支)
if [条件表达式];then
    [代码]
    if [条件表达式];then
        [代码]
    if
fi 

#语法:(if--eles)
if [条件表达式];then
    [代码]
else
    [代码]
fi

#语法:(多分支)
if [条件表达式];then
    [代码]
elif [条件表达式];then
    [代码]
else
    [代码]
fi
~~~

### if实践

**if单分支**

~~~bash
#if中的条件判断语句可以使用单中括号,双中括号和test命令
#判断文件是否存在,存在返回yes
[root@test ~]# touch sakura.txt
[root@test ~]# vim test1.sh 
[root@test ~]# cat test1.sh 
#! /bin/bash

if [ -f ./sakura.txt ]; then
    echo ":yes  []"
fi

if [[ -f ./sakura.txt ]]; then
    echo ":yes  [[]]"
fi

if test -f ./sakura.txt; then
    echo ":yes  test"
fi
[root@test ~]# bash test1.sh 
:yes  []
:yes  [[]]
:yes  test
[root@test ~]# rm -rf sakura.txt 
[root@test ~]# bash test1.sh 
[root@test ~]# 


#模拟监控内存并发送告警邮件
[root@test ~]# vim test1.sh 
[root@test ~]# cat test1.sh 
#! /bin/bash

free_size=`free -m | awk 'NR==2 {print $NF}'`
mail_content="free size deficiency"

if [ "$free_size" -lt "10000" ];then
    #本机还未配置邮件服务,此处发送邮件命令供参考
    #语法:mail -s "邮件主题" 收件人地址 < 写有发送内容的文件
    #echo $mail_content | tee /tmp/mail_content.txt
    #mail -s "free size deficiency" 123456@qq.com < /tmp/mail_content.txt
    
    #这里模拟效果,就直接输出提示
    echo "free size deficiency!!!"
fi
[root@test ~]# bash test1.sh 
free size deficiency!!!
#加入计划任务
[root@test ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@test ~]# crontab -l
*/3 * * * * bash ./test1.sh &> /dev/null
[root@test ~]# systemctl restart crond.service 
~~~

**if多分支**

~~~bash
#在进行多次判断时,相比于单分支,多分支if更加简洁
#例:输入两个数进行大小比较

~~~



## case条件语句

case一般用于多分支判断,并且判断条件较简单时

![在这里插入图片描述](https://img-blog.csdnimg.cn/62ad2956d5aa4be8ba52b3d9283bd452.png#pic_center)

~~~bash
#语法:
case 变量 in 
    "条件1")
        "代码1"
        ;;
    "条件2")
        "代码2"
        ;;
        
        .......
        
    "条件n")
        "代码n"
        ;;
esac 
~~~



## for循环

~~~bash
#语法
for 循环变量 in 循环范围
do
    "代码"
done
~~~





# shell开发实战

**用户输入内容,判断输入的是否符合要求**

~~~bash
#只能输入1和2,输入其他的内容输出提示信息
[root@test ~]# cat test1.sh 
#! /bin/bash

read -p "请输入数字1或2:" num

[ "$num" -eq "1" -o "$num" -eq "2" ] && {
echo "$num"
exit 0
}

[ "$num" -ne "1" -a "$num" -ne "2" ] && {
echo "请输入1或2"
exit 1
}

#由用户输入选项来选择安装lnmp或lamp的web架构(这里的lanp和lnmp并不是实际的安装脚本,此处只是用来代替选项)
[root@test ~]# mkdir scripts_file
[root@test ~]# cd scripts_file/
[root@test scripts_file]# touch lamp.sh lnmp.sh
[root@test scripts_file]# ls
lamp.sh  lnmp.sh
[root@test scripts_file]# echo "echo lamp install script" > lamp.sh 
[root@test scripts_file]# echo "echo lnmp install script" > lnmp.sh 
[root@test scripts_file]# chmod +x lamp.sh lnmp.sh 
[root@test scripts_file]# ll
total 8
-rwxr-xr-x. 1 root root 25 Mar 31 13:43 lamp.sh
-rwxr-xr-x. 1 root root 25 Mar 31 13:44 lnmp.sh
[root@test scripts_file]# 


~~~



选择安装lamp或lnmp,这里只是实现选择执行哪个脚本,具体的安装lamp、lnmp的脚本在后文

~~~bash
[root@test scripts_file]# vim install_lamp_or_lnmp.sh 
[root@test scripts_file]# cat install_lamp_or_lnmp.sh 
#!/bin/bash

install_path=./script_files

echo "请选择需要执行的操作:"
echo "1、install LAMP"
echo "2、install LNMP"
echo "3、exit"
read -p "请输入:" num

#判断输入的是否是数字,使用expr命令对变量num进行处理,如果处理的不是数字,那么返回值就会显示非零,根据返回值来判断输入的是否是数字
expr $num+1 > /dev/null
[ `echo $?` -ne "0" -o "$num" -gt "3" ] && {
echo "输入内容有误,请重新执行脚本并输入正确的选项"
}

[ "$num" -eq "3" ] && {
exit
}

#####################################################

#当输入1时,调用LAMP的安装脚本
[ "$num" -eq "1" ] && {
echo "正在执行安装LAMP脚本,请稍等。。。。"
sleep 2;
#判断脚本是否有执行权限,有就继续执行,没有就提示并退出
[ -x "$install_path"/LAMP.sh ] || {
echo "脚本不存在或没有执行权限,请切换root用户并确认有执行权限后再重试"
exit 1
}

#执行LAMP安装脚本
source ${install_path}/LAMP.sh 
exit $?
}

######################################################

#当输入2时,调用LNMP脚本
[ "$num" -eq "2" ] && {
echo "正在执行安装LNMP脚本,请稍等。。。。"
sleep 2;
#判断脚本是否有执行权限
[ -x "$install_path"/LNMP.sh ] || {
echo "脚本不存在或没有执行权限,请切换root用户并确认有执行权限后再重试"
exit 1
}

#执行LNMP安装脚本
source ${install_path}/LNMP.sh
exit $?
}
~~~



**MySQL服务监控**
![在这里插入图片描述](https://img-blog.csdnimg.cn/face7a97adfc497aae14401d7714203c.png#pic_center)


~~~bash
#在服务器本地监控MySQL端口
#通过netstat或ss命令过滤出MySQL的端口号,通过端口监控得知MySQL状态
[root@test ~]# netstat -tunlp | grep mysql
tcp6       0      0 :::3306                 :::*                    LISTEN      3333/mysqld         
#统计行数,非零表示MySQL存活
[root@test ~]# netstat -tunlp | grep mysql | wc -l
1

#远程监控MySQL端口
#命令需要安装。(nmap:端口扫描);(telnet:);(nc:)
[root@test ~]# yum -y install telnet nmap nc
#nmap [ip地址] -p [端口] 
[root@test ~]# nmap 127.0.0.1 -p 3306
Starting Nmap 7.70 ( https://nmap.org ) at 2023-04-03 12:04 CST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000062s latency).   #host存活

PORT     STATE SERVICE
3306/tcp open  mysql    #MySQL3306端口是打开状态

Nmap done: 1 IP address (1 host up) scanned in 0.26 seconds
#进行过滤
[root@test ~]# nmap 127.0.0.1 -p 3306 | grep open | wc -l
1
~~~

通过访问应用程序接口,读取数据库,查看是否可以读取到数据,从而判断MySQL是否运行

~~~bash
#通过php
#卸载php的旧依赖,安装新依赖
[root@test ~]# yum remove php-mysql
No match for argument: php-mysql
No packages marked for removal.
Dependencies resolved.
Nothing to do.
Complete!
[root@test ~]# yum -y install php-mysqlnd php
#编写php代码
[root@test ~]# vim mysql_test.php
[root@test ~]# cat mysql_test.php 
<?php
$mysql_id=mysqli_connect("localhost","root","sakura123!") or mysql_error();
if ($mysql_id){
  echo "mysql success!!!!!!!";
}else{
  echo mysql_error();
}
[root@test ~]# php mysql_test.php 
mysql success!!!!!!![root@test ~]# 


#通过python
#安装python3开发环境依赖
[root@test ~]# yum -y install python3 python3-devel python3-pip
[root@test ~]# pip3 install pymysql
#编写python连接MySQL代码
[root@test ~]# vim test_python.py
[root@test ~]# python3 test_python.py 
数据库连接正确,版本是:10.3.28-MariaDB
[root@test ~]# vim test_python.py
[root@test ~]# cat test_python.py 
import pymysql

db = pymysql.connect(
    host="localhost",
    user='root',
    port=3306,
    password='sakura123!', 
    db='mysql',
    charset='utf8'  
)

cursor=db.cursor()
cursor.execute('select version()')

data=cursor.fetchone()

print("数据库连接正确,版本是:%s"%data)
db.close()
[root@test ~]# python3 test_python.py 
数据库连接正确,版本是:10.3.28-MariaDB
[root@test ~]# 

~~~

**编写脚本监控MySQL**

~~~bash
[root@test ~]# cat test1.sh 
#! /bin/bash

###方法一:
if [ `netstat -tunlp | grep mysql | wc -l` -eq "1"  ];then
    echo "数据库服务正常运行"
else
    echo "数据库服务停止"
    systemctl restart mariadb
fi

###方法二:
if [ `ss -tunlp | grep mysql | wc -l` -eq "1"  ];then
    echo "数据库服务正常运行"
else
    echo "数据库服务停止"
    systemctl restart mariadb
fi

###方法三:
php ./mysql_test.php

if [ "$?" -eq "0" ];then
    echo "数据库服务正常运行"
else
    echo "数据库服务停止"
    systemctl restart mariadb
fi

###方法四:
python3 test_python.py

if [ "$?" -eq "0" ];then
    echo "数据库服务正常运行"
else
    echo "数据库服务停止"
    systemctl restart mariadb
fi

[root@test ~]# bash test1.sh 
数据库服务正常运行
数据库服务正常运行
mysql success!!!!!!!数据库服务正常运行
数据库连接正确,版本是:10.3.28-MariaDB
数据库服务正常运行
[root@test ~]# 

~~~



**开发rsync启停脚本**

~~~bash
#安装rsync服务,并启动
[root@test ~]# yum -y install rsync*
[root@test ~]# /usr/bin/rsync --daemon
[root@test ~]# ss -anltup | grep 873
tcp   LISTEN 0      5            0.0.0.0:873       0.0.0.0:*    users:(("rsync",pid=12933,fd=4))  
tcp   LISTEN 0      5               [::]:873          [::]:*    users:(("rsync",pid=12933,fd=5))  


#编写rsync的启动脚本
[root@test ~]# cat rsync.sh 
#! /bin/bash

#判断用户输入的参数个数是否为1个,如果不符合要求,提示用户重新输入正确参数
if [ "$#" -ne "1" ];then
    echo "Usage: $0 {start|stop|restart}"
    exit 1
fi

#当选择启动rsync时
if [ "$1" == "start" ];then
    /usr/bin/rsync --daemon
    sleep 2
    #验证端口是否存活
    if [ `ss -anltup | grep rsync | wc -l` -eq "0" ];then
        echo "服务端口未启动!!!" 
	exit 1
    else
        echo "服务端口已启动"
	exit 0
    fi

elif [ "$1" == "stop" ];then
    killall rsync &> /dev/null
    sleep 2
    if [ `ss -anltup | grep rsync | wc -l` -ne "0" ];then
	echo "服务未关闭,端口还存在!!!"
	exit 1
    else
	echo "服务端口已正常关闭"
	exit 0
    fi

elif [ "$1" == "restart" ];then 
    killall rsync &> /dev/null
    sleep 1
    stop_result=`ss -anltup | grep rsync | wc -l` 
    /usr/bin/rsync --daemon 
    sleep 1
    start_result=`ss -anltup | grep rsync | wc -l` 
    if [ "$stop_result" -eq "0" -a "$start_result" -ne "0" ];then
        echo "服务重启成功"
        exit 0	
    else
	echo "服务重启失败"
    fi
else 
    echo "请输入正确的参数!"
    echo "Usage: $0 {start|stop|restart}"
fi
[root@test ~]# 


~~~



**监测网站是否存活**

~~~bash
[root@test ~]# cat ./scripts_file/check_web_survival.sh 
#!/bib/bash

if [ "$#" -ne "1" ];then
    echo "提示,请输入正确的参数格式"
    echo "Usage:$0 web_url "    
    exit 1
fi

yum -y install wget &> /dev/null && \
wget --spider -q -o /dev/null --tries=1 -T 5 $1
if [ "$?" -eq "0" ];then
    echo "$1网站存活,正常运行中。。。。。"
else
    echo "$1网站无法访问,请检查网站服务!!!!"
fi
[root@test ~]# 

~~~


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值