shell脚本编程

什么是shell

shell是一个命令解释器,在操作系统的最外层,将用户输入的命令翻译给操作系统.

什么是shell脚本

将系统命令堆积在一起,顺序执行;
特定的格式+特定的语法+系统命令 = 文件

shell的基本规范

  • 存放固定目录:/scripts
  • 开头加 #!/bin/bash 指定解析程序
  • 脚本扩展名:.sh

shell的执行

1.脚本中第一行 #!/usr/bin/bash
脚本中如果不写,在执行过程中如果./方式执行(需要权限),默认调用bash命令翻译该文件
脚本中如果写了使用什么解释器翻译,那么使用./时则会调用对用的解释器执行

首先chmod +x 文件名 加可执行权限
再 ./文件名执行
2.bash 脚本 —无需权限,直接调用解释器翻译

3.sh 脚本
/bin/bash 脚本名

shell变量

变量名不能使用“横杠”,首个字符必须为字母
变量中有空格则使用双引号
使用 $变量名 可以得到变量值,${变量名}也可以
双引号会将变量的值解析,单引号会直接输出内容,不进行解析
readonly 加变量名 只读,后面不能修改
unset 加变量名 删除变量 后面不能用
字符串的长度: ${#变量的名字}
提取子字符串: ${字符串的名字:1:4}从第2个字符开始截取4个字符

系统环境变量

export- - - 打印系统环境变量
export 变量名=变量值 - - - 将变量设置为环境变量,同一个Bash中可以使用

运算符

使用反引号:`expr 1+2`
两个变量相加:`expr ${a}+${b}`

执行脚本时传入参数

read:执行脚本后等待参数的输入

bash 文件名 参数1 参数2 …

echo"#当前shell脚本的文件名:$0"
echo"#第1个shell脚本位置参数:$1"
echo"#第2个shell脚本位置参数:$2”
echo"#第3个shell脚本位置参数:$3"
echo“#所有传递的位置参数是:$*"
echo"#所有传递的位置参数是:$@"
echo“#总共传递的参数个数是:$#”
echo“#当前程序运行的PID是:$$"
echo"#上一个命令执行的返回结果:$?"
注:第十个参数及以上使用:${ 数字}

将命令执行的结果传递给变量

$() 括号中一定是命令
例:
$(date +%Y) - - - 2020

运算$((表达式))
$(($(date +%Y)+1 ))- - - 2021

批量创建文件 touch 文件路径/{文件名}.文件后缀

例:touch /root/{1…10}.txt

压缩解压

打包压缩文件 tar zcvf 文件路径/文件名.tar.gz 被压缩文件
嵌套命令
tar zcvf /root/etc.tar.gz $(find /etc -name “*.conf”)

查看打包文件 tar tf 压缩文件名 | less
less命令退出 :键盘q
解压文件
tar -zxvf 压缩文件名 -C 解压路径 - - - 解压路径不写则默认本目录解压

read命令通过交互式方式传递变量

#!/bin/bash
read -p "请输入:" varfile
echo "要备份的为:" $varfile

#!/bin/bash
read -p "请输入IP:" var
ping -W1 -c1 $var &>/dev/null
rc=$?
if [ $rc -eq 0 ];then
        echo "$var 能正常通信"
else
        echo "$var 无法正常通信"
fi

man 命令 可得到命令的全部用法

&>/dev/null 输入到黑洞,不显示

例如ping -c2 www.baidu.com &>/dev/null 把ping 的结果输出du到一个黑洞
覆盖符:> 文件名
追加符:>> 文件名

字符串操作

在这里插入图片描述
开启转义功能:-e “字符串”

version=$(cat /etc/redhat-release | awk '{print $(NF-1)}')
echo $version
#7.7.1908
echo ${version#*.}
#从头开始删除 删除第一个.前的任意值 7.1908
echo ${version##*.}
#从头开始删除,最长删除,删除最后一个.前的任意值1908
echo ${version%.*}
#从尾开始删除,删除倒数第一个.后的任意值7.7
echo ${version%%.*}
#从尾开始删除,删除最远.后的任意值 7
echo ${version/7/8}
#替换一个字符 8.7.1908
echo ${version//7/8}
#替换所有字符 8.8.1908
echo ${version//./_} 
#7_7_1908

流程控制语句if

if [ 条件 ];then
   条件成立执行
fi

if文件比对方式

参数说明示例
-e 如果文件或目录存在则为真 [ -e $file ]
-s 如果文件存在且至少有一个字符则为真[-s $file]
-d 如果文件存在且为目录则为真[-d $file]
-f 如果文件存在且为普通文件则为真[-s $file]
-r 如果文件存在且可读则为真[-r $file]
-w 如果文件存在且可写则为真[-w $file]
-x 如果文件存在且可执行则为真[-x $file]

在同一路径下,可写相对路径,不在时,写绝对路径

if整数比对

在这里插入图片描述
编写一个脚本,检测服务是否运行

#!/bin/bash
if [ $# -ne 1 ];then
        echo "请输入一个服务名称"
        exit
fi
systemctl status $1 &>/dev/null
rc=$?
if [ $rc -eq 0 ];then
        echo "$1 服务正在运行"
else
        echo "$1 服务没在运行"
fi

if字符串比较

在这里插入图片描述
if通配符[[ ]]

#!/bin/bash
read -p "请输入用户前缀" qz
if [[ ! $qz =~ ^[a-Z]+$ ]];then
        echo "你输入的不是english"
        exit
fi
read -p "请输入创建用户的后缀" hz
if [[ $hz =~ ^[0-9]+$ ]];then
        user=${qz}${hz}
        id $user &>/dev/null
        if [ $? -eq 0 ];then
                echo "用户名已存在 $user"
        else
                useradd $user
                echo "用户创建成功 ${user}"
        fi
else
        echo "输入的不是数字"
fi

判断用户是否为root

if [ $UID -eq 0 ] && [ $USER == "root" ]

使用root用户清空/var/log/messages日志,并每次执行保留最近100行

#!/bin/bash
file=/var/log/messages
file_bak=/var/log/messages.bak
if [ $UID -eq 0 ] && [ $USER == "root" ];then
        if [ -f $file ];then
                tail -100 $file > $file_bak
                cat $file_bak > $file
                echo "==========备份成功============="
        else
                echo "文件不存在"
        fi
fi
	

cat -n 查看文件并带有行号 文件名
awk ‘/.* Active/’- - -表示匹配行内包括“Active”的一行
awk ‘/.* Active/ {print $2}’- - - 表示打印第二个整体
{print $(NF)} - - - 打印最后一个整体
{print $(NF-1)} - - - 打印倒数第二个整体
安装netstat命令 - - - yum install net-tools

#1.判断服务是否存在#3.判断进程是否存在
ssh_status=$(systemctl status sshd|awk '/.*Active/ {print $2}')
if [ "$ssh_status" == "active" ];then
        sleep 1
        echo "服务检测的是   $ssh_status"
else
        sleep 1
        echo "服务检测的是   $ssh_status"
fi
#2.判断端口是否存在
netstat -lntp|grep "sshd" &>/dev/null
if [ $? -eq 0 ];then
        sleep 1
        echo "sshd服务端口存活"
else
        sleep 1
        echo "sshd服务端口不存活"
fi
#3.判断进程是否存在
ps axu |grep sshd|grep -v grep|grep -v "pts" &>/dev/null
if [ $? -eq 0 ];then
        sleep 1
        echo "sshd服务进程存在"
else
        sleep 1
fi


查看版本信息
cat /etc/redhat-release

#!/bin/bash
version=$(cat /etc/redhat-release | awk '{print $(NF-1)}')
echo $version
if [ ${version%%.*} -eq "6" ];then
        echo " ${version%%*.}"
else
        echo " ${version%%.*}"
fi

if多分支

匹配1234

#!/bin/bash
read -p "请输入1-4  " install
if [[ ! $install =~ ^[1-4]$ ]];then
        echo "请按规定输入"
        exit
fi
if [ $install -eq 1 ];then
        echo "1"
elif [ $install -eq 2 ];then
        echo "2"
elif [ $install -eq 3 ];then
        echo "3"
elif [ $install -eq 4 ];then
        echo "4"
fi

脚本中使用action

#! /bin/bash
source /etc/init.d/functions 
# 引入函数
action "服务" /bin/true
action "服务" /bin/false

执行效果
在这里插入图片描述

寻找文件

find / -type f -name “script*” - - - 在根目录下寻找文件名前缀为script的文件

执行效果
在这里插入图片描述

case用法

#!/bin/bash
source /etc/init.d/functions

#加锁
if [ -f /tmp/nginx.lock ];then
        echo "此脚本正在执行,请稍后......"
        exit
fi
touch /tmp/nginx.lock

rc=$1
case rc in
        start)
        if [ -f /var/run/nginx.pid ];then
                action "nginx服务已经启动......" /bin/false
                exit
        else
                /usr/sbin/nginx
                if [ $? -eq 0 ];then
                        action "nginx服务启动成功......" /bin/true
                fi
        fi
        ;;

        stop)
        if [ -f /var/run/nginx.pid ];then
                /usr/sbin/nginx -s stop
                 if [ $? -eq 0 ];then
                        action "nginx服务关闭成功......" /bin/true
                 else 
                        action "nginx服务关闭失败......" /bin/false
                 fi
        else
                action "nginx服务未开启,不能进行关闭操作......" /bin/false
                exit
        fi
        ;;
        
        reload)
        if [ -f /var/run/nginx.pid ];then
                /usr/sbin/nginx -s reload
                if [ $? -eq 0 ];then
                        action "nginx服务重启成功......" /bin/true
                else
                        action "nginx服务重启失败......" /bin/false
                fi
        else
                action "nginx服务未开启,不能进行重启操作......" /bin/false
                exit
        fi
        ;;
esac
#解锁
rm -f /tep/nginx.lock

for循环

基本格式
for 变量 in 列表
do
  使用变量
done
列表的分隔方式
在这里插入图片描述

使用for循环探测局域网中设备

#!/bin/bash
> /tmp/ip.log
#清空ip.log中的内容
for i in {1..254}
do
        {
                ip=192.168.1.$i
                ping -c 1 -W 1 $ip &>/dev/null
                if [ $? -eq 0 ];then
                        echo "$ip is ok"
                        echo "$ip is ok" >>/tmp/ip.log
                else
                        echo "$ip is down"
                fi
        } &
        #异步for循环
done
        wait
        echo "Scan IP is Done"
        echo "--------------------------"

sed -n “行数p” - - - 文件名 取出文件中特定行内容
sed 行数d - - -删除指定的行内容

使用for循环实现数据库备份

#!/bin/bash
#获得数据库名称
db_name=$(mysql -uroot -p123456 -e "show databases;"|sed 1d |grep -v ".*_schema")
for i in $db_name
do
        #创建数据库备份目录
        DB_Path=/mysql_dump/$i
        #如果目录不存在就创建
        if [ ! -d ${DB_Path} ];then
                mkdir -p ${DB_Path}
        fi
        #备份数据库
        mysqldump -uroot -p219717 --single-transaction -B $i >${DB_Path}/${i}_database_$(date +%F).sql
        echo "${i} 数据库 已经备份完成......"
done

使用for循环备份库和表

#!/bin/bash
#source /etc/init.d/functions
#获得数据库名称
db_name=$(mysql -uroot -p123456 -e "show databases;"|sed 1d |grep -v ".*_schema")
for i in $db_name
do
        #创建数据库备份目录
        DB_Path=/mysql_dump/$i
        #如果目录不存在就创建
        if [ ! -d ${DB_Path} ];then
                mkdir -p ${DB_Path}
        fi
        #备份数据库
        mysqldump -uroot -p219717 --single-transaction -B $i >${DB_Path}/${i}_database_$(date +%F).sql
        #action "${i} 数据库 已经备份完成......" /bin/true
        echo "${i} 数据库 已经备份完成................................................................."
        #备份数据库中的表
        table_name=$(mysql -uroot -p123456 -e "use ${i};show tables;"|sed 1d)
        for j in $table_name
        do
                mysqldump -uroot -p123456 --single-transaction $i $j >${DB_Path}/${i}_${j}_table_$(date +%F).sql
                echo "${i} 数据库     ${j} 数据表  已经备份完成......"
        
        done
done

while循环

在这里插入图片描述
while读入文件方式
while read line - - - line->变量名 默认 按行取值
do
echo $line
done<文件名

函数

定义函数
在这里插入图片描述
在这里插入图片描述

调用函数
使用函数名直接调用

函数的传参
使用$进行传参

函数的返回值
return状态码(1-255)

数组

普通数组
声明:info=(linux age name)
取值:${数组名[索引号]}

关联数组
声明:declare -A 数组名
例:declare -A info
info=([name]=xxx [age]=18 [skill]=code)
取值:${info[age]}
取所有值: ${info[@]}或者 ${info[*]}

取所有索引: ${!info[@]}或者 ${!info[*]}
取数组长度: ${#info[@]}

#!/bin/bash
declare -A info_sex
while read line
do
        type=$(echo ${line}|awk '{print $2}')
        let info_sex[$type]++
done<sex.txt
for i in ${!info_sex[@]}
do
        echo "索引名称为:${i} 索引对应的次数为 ${info_sex[$i]}"
done

使用while循环查找自定义用户

#!/bin/bash
i=0
while read line
do
        User_id=$(echo $line|awk -F ":" '{print $3}')
        User_Shell=$(echo $line|awk -F ":" '{print $NF}')
        if [ $User_id -ge 1000 -a $User_Shell == "/bin/bash" ];then
                let i++
        fi
done</etc/passwd
echo "一共有$i个自定义用户"

正则表达式

过滤筛选作用

\ 转义符
^ 匹配字符串的开始
$ 匹配字符串的结尾
^$ 表示空行
. 匹配除换行符外的任意单个字符
[ ] 匹配包含在[字符]之中的任意一个字符
[^] 匹配[ ^] 之外的任意一个字符
? 匹配之前的项一次或零次
+ 匹配之前的项一次或多次
* 匹配之前的项零次或多次 .* 表示匹配所有
() 匹配表达式,创建一个用于匹配的字串
| 匹配两边的任意一项
{n} 匹配之前的项n次,n是可以为0的正整数
{n,} 匹配之前的项,至少匹配n次
{n,m} 匹配之前的项至少n次,最多m次

特定字符
[0-9]
[a-z]
[A-Z]
[a-Z]

sed文本处理

sed [options] ’ conmand’ file
选项
-n - - - 取消默认的输出,不写则完全输入加上本要输出的内容
-i - - - 将修改后的内容保存到文件
-r - - - 扩展正则,可以对/不进行转义
sed 命令参数
a 在当前行后添加一行或多行
sed -i ‘30a xxx’ passwd - - - 追加xxx在passwd文件的第30行

c 在当前行进行替换修改
sed -i ‘1c xxx’ test - - - 将test文件的第一行内容替换为xxx
sed -i ‘/^.inet./c yyy’ test - - -将正则匹配到的内容替换为yyy

d 在当前行进行删除操作
sed -i ‘3d’ test - - -删除 test文件中的第3行
sed -i ‘11,$d’ test - - - 删除第11行到最后一行
sed -i ‘$d’ test - - - 删除最后一行
sed -i /正则表达式/ test - - - 删除匹配的内容

i 在当前行之前插入文本

p 打印匹配的行或指定行
sed -n ‘/halt/p’ passwd - - - -打印匹配的行
sed -n ‘2p’ test - - - 打印第二行内容
sed -n ‘$p’ test - - - 打印最后一行

sed匹配替换 不改变文本内容
替换命令s 标志g行内全局替换i忽略大小写
sed ‘s/inet/alice/’ test.txt - - - 替换每行出现的第一个inet
sed ‘s/^ *inet/alice…/’ test.txt - - - 替换正则匹配的内容
sed ‘s/inet/alice…/g’ test.txt - - - 匹配包含有inet的行进行替换(行内全部)
sed ‘s#aa#TTT#g’ test.txt - - - 匹配每行的aa换成TTT
sed ‘s#aa#TTT#gi’ test.txt - - - 匹配每行的aa忽略大小写换成TTT
sed ‘s#/etc/test/123#/dev/null#g’ 1.txt - - - 匹配到/etc/test/123,替换为/dev/null,/不用转义
#!/ 都可用

awk

  • awk将文件中的每一行作为输入,并将每一行赋给变量$0,以换行符结束
  • awk开始进行字段分解,每个字符存储在已编号的变量中,从$1开始,默认空格分隔
  • awk默认字段分隔符是由内部FS变量来确定,可以使用-F修订
  • awk行处理时使用了print函数打印分割后的字段
  • awk在打印后的字段加上空格,因为$1,$3之间有一个逗号
  • awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容
[root@localhost ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@localhost ~]# awk 'BEGIN {print 1/2} {print "ok"} END {print "over"}' /etc/hosts
0.5
ok
ok
over

awk ‘BEGIN {print 1/2} {print “ok”} END {print “over”}’ /etc/hosts
BEGIN {print 1/2} - - -行处理前
{print “ok”} - - - 进行行处理 ,,,文本中有两行,所以打印两次ok
END {print “over”} - - - 行处理后

awk -F: ‘{print $1}’ /etc/passwd 以冒号为分隔符,打印每一行的第一个元素
awk ‘BEGIN{FS=":"} /root/{print $1}’ /etc/passwd 以冒号分隔,将匹配到root的行第一个元素打印
awk ‘$10 ~ 404 {code[$10]++}’ file - - - 匹配行第十个元素为404,将元素放入数组
awk -F “[: ]” ‘{print $2}’ file - - - 将冒号和空格都作为分隔符
awk -F “[: ]+” ‘{print $2}’ file - - -将冒号空格,一个/连续多个冒号,一个/连续多个空格都视为分隔符
awk ‘{print NF}’ file - - - 打印最后一个元素的位置
awk ‘{print $NF}’ file - - - 打印最后一个元素的内容
awk ‘{print $(NF-1)}’ file - - - 打印最后一个元素前面的内容
awk ‘{print NR}’ file - - - 打印行号
awk ‘NR==3{print $0}’ file - - - 打印第三行内容
awk ‘NR!=3{print $0}’ file - - - 打印除第三行外的内容
FNR - - - 处理多个文件,行号单独排序

awk判断语句
awk -F: ‘{ if(判断条件) {成功执行} else { 不成功执行} END {行处理完成后执行}}’ 文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值