Linux之Shell脚本

发布于:2024-03-18 ⋅ 阅读:(53) ⋅ 点赞:(0)
shell脚本组成
声明解释器
注释
代码正文
脚本的执行方式
1、为脚本添加x权限,使用相对或者绝对路径执行
chmod u+x /xxx 赋予.sh文件执行权限

2、使用解释器程序执行脚本,无需x权限
bash  /xxx 通过bash解释器执行

3、使用source或者 .执行脚本,无需x权限
source /xxx通过source执行,简写为 . /xxx
第一个脚本
#!/bin/bash
#这是一个yum仓库
echo "[haha]
name=haha
baseurl=file:///mydvd
gpgcheck=0" > /etc/yum.repos.d/haha.repo 
重定向黑洞
ls ksdjfhksdj 2> /aaa.txt  收集错误信息
ls test.sh sljfls &> /aaa.txt  收集所有信息
第二个脚本
#!/bin/bash
yum -y remove vsftpd &> /dev/null  将不需要的输出信息扔进黑洞
yum -y install vsftpd &> /dev/null
systemctl restart vsftpd
systemctl enable vsftpd                 
变量/常量
自定义变量 变量名称=值  
调用变量 $变量名称
unset a 或者 a=     删除变量

echo ${a}RMB 使用大括号隔离常量
环境变量
系统提前定义好,使用时直接调用
echo $USER 用户名
echo $UID 用户ID
echo $HOME 当前用户家目录
echo $SHELL 解释器
echo $HOSTNAME 主机名
echo $PWD 当前路径
echo $PATH 执行程序
位置变量与预定义变量
$1  执行脚本后跟的第1个位置参数
$2  执行脚本后跟的第2个位置参数
$3  执行脚本后跟的第3个位置参数
$*  所有传入的值
$#  传入了几个值
$$  当前程序的进程号
$?  判断上一条命令是否成功,0是成功,非0是失败

[root@www ~]# bash /opt/test05.sh a b c d
a
b
c
a b c d
4
2770
0
传参
#!/bin/bash
useradd $1
echo $2 | passwd --stdin $1

bash /opt/test06.sh tom 123456   test06传参,用户名tom 密码123456
扩展知识
引号
" " 双引号  界定范围
' ' 单引号  界定范围  屏蔽特殊符号的功能
` ` 反撇号  获取命令的执行结果 或使用$()
	a=`date`  将date执行结果赋值给a
交互式(read)
#!/bin/bash
read -p "请输入用户名" u   输入后传值给u
useradd $u
read -p "请输入密码" n
echo $n | passwd --stdin $u
屏蔽回显
stty -echo 屏蔽回显
stty echo 关闭屏蔽回显
运算
加 减 乘 删 求模(取余)
1、expr命令。可以运算并输出结果,必须全部有空格
	expr 2 - 1
	expr 2 + 1
	expr 2 \* 2 乘法需要转义
	expr 4 / 2
	expr 5 % 2 取余
2、$[2*4] 把结果当命令执行,显示需要echo 
	echo $[a+a]  可以直接用变量计算
	另一种写法 $((a+a))
3、使用let命令 不输出结果,专用于变量的创建或变量的自增减
	let a=1+1 变量创建并运算赋值
	let a++ 自增1
	let a+=2 自增2
	let a*=2 相当于a=a*2
	let a/=2 相当于a=a/2
	let a%=3 相当于a=a%3
4、bc命令,计算小数
	echo "1.1+1" | bc
	echo "10/3" | bc
	echo "scale=3;10/3" | bc   计算小数,保留小数点后三位
	
全局变量
export a
a=10
echo $a
条件测试
1、test 表达式
	test a == a
	test a != b
2、[ 表达式 ]    格式都有空格
	[ a == a ]
	[ a != b ]
	1、可以对字符串进行测试
		== 两边是否相等
		!= 两边是否不等
		[ -z $c ] 判断变量$c的值是否为空
		[ ! -z $c ]判断变量$c的是是否非空
    2、数字表达式
        -eq 是否相等
        -ne 是否不等
        -gt 是否大于
        -ge 是否大于等于
        -lt 是否小于
        -le 是否小于等于
    3、文件
    	-e 判断文件是否存在,不关系类型
    		[ -e /opt/test01.sh] 判断是否有文件
    		[ -e abc123 ] || touch abc123 判断是否有这个文件,如果没有创建这个文件
    	-f 判断文件是否存在,必须是普通文件
    	-d 判断目录是否存在
    	-r 判断当前用户对文件是否有读权限
    	-w 判断当前用户对文件是否有写权限
    	-x 判断当前用户对文件是否有x权限
逻辑符号
成功 && 指令   前面指令成功,执行后面指令
	[ $USER != root ] && exit 判断当前用户是否不为root。如果判断成功,则执行exit

失败 || 指令   前面指令失败,执行后面命令
	[ $USER == root] || exit 判断当前用户是否为root,如果为root放行,如果不为root 执行exit

多个逻辑符号组合使用
A && B A和B都成功算成功
A || B A和B有一个成功算成功

案例
每隔两分钟检测用户是否增多,如果增多发送邮件

if
if分支

1、单分支

	if 条件测试;then     if后面需要加空格
	执行指令1
	执行指令2
	......
	fi 
2、双分支
 
  	if 条件测试:then
  	执行指令
  	else
  	执行指令
  	fi
3、多分支
	
	if 条件测试:then
	执行指令
	elif 条件测试:then
	执行指令
	elif 条件测试:then
	执行指令
	eles
	执行指令
	fi 

for循环
for 变量名称 in 值1 值2 值3 ......
do
 任务
done


#!/bin/bash
for i in a b c
do
   echo $i
done
输出 a b c

#!/bin/bash
for i in {1..100} 不支持变量
do
   echo $i
done
输出1-100

#!/bin/bash
a=10
for i in $(seq $a) 支持变量
do
   echo $i
done
输出1-10

批量创建用户,用户在name.txt中
#!/bin/bash
for i in $(cat /opt/name.txt)
do
   useradd $i
done

批量ping
#!/bin/bash
for i in {200..254} {50..60} 68 {120..130}
do
  ping -c 1 -i 0.2 -W 1 192.168.88.$i &> /dev/null
  if [ $? -eq 0 ];then
    echo 192.168.88.$i 通了
  else
    echo 192.168.88.$i 没通
  fi
done


for循环
for((初值;条件;步长))
do
  指令
done

for((i=1;i<=5;i++))
do
 指令
done 

while循环
while 条件测试
do 
	指令
done

while : 冒号代表永远正确,死循环 
do 
	指令
done

控制循环
exit 可以终止循环,也终止脚本
break 可以终止循环,继续循环后的任务
continue 可以终止当前循环

case分支
case 调用的变量名 in
 模式1)
     执行指令;;
 模式2)
     执行指令;;
 模式3)
     执行指令;;
esac
     
case $1 in
t)
  touch $2;;
m)
  mkdir $2;;
r)
  rm -rf $2;;
*)
  echo "请输入 t m r";;
esac

nginx
#!/bin/bash
yum -y install gcc make pcre-devel openssl-devel
tar -xf /opt/lnmp_soft/nginx-1.17.6.tar.gz -C /opt/
cd /opt/nginx-1.17.6
./configure
make
make install


/usr/local/nginx/sbin/nginx  启动nginx,不支持systemctl
/usr/local/nginx/sbin/nginx -s stop

#!/bin/bash
case $1 in
start|kai|s)  |可做或运算,开启nginx
   /usr/local/nginx/sbin/nginx;;
stopt|guan|)  关闭nginx
   /usr/local/nginx/sbin/nginx -s stop
chongqi)      重启nginx
   /usr/local/nginx/sbin/nginx -s stop 
   /usr/local/nginx/sbin/nginx;;
zhuangtai)     查询nginx状态
   netstat -ntulp | grep nginx &> /dev/null
   [ $? -eq 0 ] && echo "运行成功" || echo "运行失败"
*)
  echo "输入错误"
esac

netstat服务端口查询
netstat -ntulp
-n 以数字格式显示端口号
-t 显示TCP连接的端口
-u 显示UDP连接的端口
-l 显示服务正在监听的端口信息,汝httpd启动后,会一直监听80端口
-p 显示监听端口的服务名称是什么(也就是程序名称)

netstat -ntulp | grep nginx 查询nginx服务是否开启

函数
函数名(){
    指令
}

a(){
    echo -e "\033[$1m$2\033[0m"   字体变色
}
a 31 ABCD

function a {
    echo abc
}

字符串
1、字符串的截取   从0开始截取
 ${变量名称:截取位置:截取长度}

x=abcd..XYZ...0123456789
for i in {1..8}
do
   n=$[RANDOM%62]
   a=${x:n:1}
   c=$a$c
done

2、字符串替换
 ${变量名/旧/新} 只换第一个
 ${变量名//旧/新} 两个//换所有
 ${a//22/66} 将两个2换成两个6
 ${a//22/} 将所有2替换成空,相当于删除
 
3、字符串删除
 ${变量名#要删除的内容} 掐头
 ${变量名%要删除的内容} 去尾
  a=abcdefg
  echo ${a#*e} 删除到e以后截止  掐头
  echo ${a%e*} 删除到e之前截止  去尾
  
  a=abcdabcd
  echo ${a##*c} 两个#号,删除到最后一个c
  echo ${a%%c*} 两个#号,删除到第一个c
 
 定义变量初值
 ${变量名:-初值}  变量如果有值,就用变量的值,如果变量没有值,则用初值

$RANDOM随机数
$[RANDOM % 65] 输出随机数0-64

touch abc{01…10}.txt

sleep 1 等待一秒

正则表达式
描述 正则符号
^ 匹配行首
$ 匹配行尾
[] 集合,匹配集合中的任意单个字符
[^] 对集合取反
. 匹配任意单个字符
* 匹配前一个字符任意次数(不允许单独使用)
\{n,m\} 匹配前一个字符可以出现n到m次 n-m之间次数都算{n,m}
\{n\} 匹配前一个字符出现n次{n}
\{n,\} 匹配前一个字符n次及以上{n,}
\(x\) 保留/组合为整体()
正则表达式用引号引起来,用来界定范围
grep ^root user   在user文件中匹配开头为root的行
grep root$ user   在user文件中匹配以riit结尾的行
grep ^$ usr       在user文件中匹配空行

grep [root] user  在user中只要找到r、o、o、t任意一个就匹配
grep [0-9] user  在user中匹配0-9任意一个数字的行
grep [A-Z] user  在user中匹配A-Z任意一个字母
grep [a-z] user  在user中匹配a-z任意一个字母

#!/bin/bash    判断输入的是否为数字
read -p “请输入一个数字” n   输入一个数字
echo $n | grep -q [^0-9]  过滤输入的数字,如果有除了0-9以外的数字,则进行下一步
if [ $? -eq 0 ];then  判断上一步是否有除了0-9以外的数字
 echo "必须是数字"
else
 echo OK
fi

[a-Z0-9]找所有字母数字
[^a-Z0-9]找除了所有字母数字的字符

roo[tx] 找root或者roox
roo. 找roo开头的四个字母,后面一个随意
roo.. 找roo开头的五个字母,后面两个随意

roota. 找含有root 且含有任意次数(包括0次)a出现的地方

.*  通配符

"ro\{1,3\}" 找ro,中间的o可以有1-3个都可以

"ro\{2\}t"  找ro,中间的o必须且只有2个

"ro\{2,\}t" 找ro,中间的o出现两次及以上

"0:\{2\}t"  找0::,但是现在要找0:0:
"\(0:\)\{2\}t"  0: 出现两次

扩展正则表达式

正则符号 描述
+ 最少匹配一次
? 最多匹配一次
{n,m} 匹配n到m次
() 组合为整体,保留
| 或者
\b 单词边界
\w 必须有数字、字母、下划线
\d 相当于[0-9] 需要配合-P使用
grep不支持扩展正则,需要使用egrep 

grep "ro\{1,\}t" user o出现1次以上

grep "ro{1,}t" user    o出现1次以上

grep "ro+t" user        o出现1次以上


grep "roo\{0,1\}t"     o出现0次或1次

grep "roo?t"               o出现最多一次,和上面一样


egrep "^root|^bin" user 搜索以bin或者root开头的文件

egrep "the\b" user  there只搜索the,精确搜索

egrep "roo\w" user 找oo后面是数字、字母、下划线的字符串

sed
流式编辑器
可以对文档进行非交互式增删改查,逐行处理
用法:
1、 前置指令 | sed 选项 条件 指令
2、 sed 选项 条件+指令 被处理文档
	选项:-n 屏蔽默认输出
	     -r 支持扩展正则
	     -i 修改源文件
	条件:行号  /字符串/  $(最后一行)
	指令:p 输出
	     d 删除
	     s 替换
	     = 行号
	     a 行下追加
	     i 行上添加
	     c 替换整行
	p指令
	sed -n '1p' user 查看user文件第1行
	sed -n '1,5p' user 查看user文件第1-5行
	sed -n '1p;4p' user 查看user文件第一行、第四行
	sed -n '1,+1p' user 查看user文件第一行,在多看一行(第二行)
	
	sed -n '/root/p' user  查看root所在的行 支持正则
	sed -nr '/^root|^bin/p' user  查看以root开头或者bin开头的文件 因为|是扩展正则,所以要加r
	
	sed -n '1!p' 取反,看除了第一行之外其他所有行
	sed -n '/root/!p' 查看除了root的行
	sed -n '=' user  显示行号
	sed -n '/^bin/=' user查看以bin开头的行号
	sed -n '$=p' user 查看最后一行的行号
	
	d指令
	sed '1d' user 删除第一行  删除需要显示内容,所以不需要-n
	sed '/^bin/!d' user  将除了以bin开头的行进行删除
	sed '$d' user 将最后一行删除
	sed '/^$/d' user 将空行删除.
	
	s替换指令
	sed 's/旧内容/新内容/' /只要是三个一样的就可以,###也可以
	
	初始内容
	2017 2011 2018
    2017 2017 2024
    2017 2017 2017
    
	sed 's/2017/666/' user  将所有行的第一个2017换成666
	666 2011 2018
    666 2017 2024
    666 2017 2017
    
    sed 's/2017/666/2' user  将所有行的第二个2017换成666
    2017 2011 2018
    2017 666 2024
    2017 666 2017

	sed '3s/2017/666/3' user 将第三行的第三个2017换成666
	2017 2011 2018
    2017 2017 2024
    2017 2017 666
   
    sed 's/2017/666/g' user 将所有行的所有2017替换成666
    666 2011 2018
    666 666 2024
    666 666 666
    
    sed '/2024/s/2017/6666/g' user 先找到含有2024的行,再将该行所有2017替换成6666
    
    sed 's/\/bin\/bash/\/sbin\/sh/' user 将user文档的 /bin/bash 改成 /sbin/sh(了解)
    sed 's#/bin/bash#/sbin/sh#' user 修改替换符为# 
    
    a指令
    sed 'a 666' user 在每行下面添加666
    sed '3a 666' user 在第三行下面添加666
    
    i指令
    sed '3i 666' user 在第三行上面廷加 
    
    面试题
    echo 1794917239 | sed 's91791239g' == sed 's/17/123/g'  三个9为替换符

脚本搭建httpd服务,用82端口开启服务
sed '/Listen 80/s/0/2/g' /etc/httpd/conf/httpd.conf

编写脚本,找到系统使用bash的账户名,然后按照“账户名–>密码” 的格式存储在一个文件中
grep "bash$" /etc/passwd | sed 's/:.*//'
在passwd文件筛选bash结尾的行
管道给sed ,替换:以后所有的内容为空

sed '/bash$/s/:.*//' /etc/passwd 此方法效果和上面相同,但是默认会把修改后和原本没有动的所有内容输出

sed -n '/bash$/s/:.*//p' /etc/passwd -n屏蔽输出,在后面加一个p,只会显示执行结果


#!/bin/bash
a=$(sed -n '/bash$/s/:.*//p' /etc/passwd)
for i in $a
do
b=$(grep ^$i: /etc/shadow)  名字以i开头,后面为:
    b=${b#*:}
    b=${b%%:*}
    echo "$i --> $b"
done

匹配0-199
0~199
1?[0-9]?[0-9 ]

awk
前置指令 | awk 选项 条件 指令
awk 选项 条件 指令 被处理文档
 选项
     -F 定义分隔符
 条件
     /字符串/ 字符串可以使用正则 ~包含 !~不包含
     == != >= <= > <
     &&并且 ||或者
     运算 + - * / %
     
     内置变量 $1 第一列
            $2  第二列
            $0  所有列
            NR  行号
            NF  列号
 指令
     print 
     

hello the world
welcome to beijing

awk '{print}' user 输出文档
awk '/the/{print}' user 输出有the的行
awk '/the/{print $1}' user 查询有the的行,只输出第一列
awk '/the/{print $1,$3,$0}' user 查询有the的行,输出所有列
awk '/the/{print NR}' user 查询行号
awk '{print NR,$0}' user 输出行号和所有列内容
awk '/^bin/{print NR,$0}' 输出以bin开头的行号,和所有列
awk -F: '{print $1,$3}' 以:为分隔符,查看第一列和第三列
awk -F: '{print "abc"}' 相当于echo 常量
awk -F: '{print $1"的解释器是"$7}' user  以:为分隔符,输出

~包含 !~不包含
awk -F: '$5~/root/{print}' user 以:分割,在第五列找包含root
awk -F: '$5!~/root/{print}' user 以:分割,在第五行找不包含root

== != >= <= > <
awk 'NR==2{print}' user  查看第二行
awk -F: '$3>2{print}' user 以:分割,找第三列数字大于2的行
awk -F: '$5=="root"{print}' user 以:分割,在第五行是root
awk 'NR>2{print}' user 输出行号大于2的行

&&并且 ||或者
awk 'NR>=2&&NR<=4{print}' user 查询user2-4行

运算 + - * / %
awk 'NR%2==0{print}' user
awk 'NR%2==0{print NR,$0}' user  显示偶数行的行号和内容

awk处理时机
变量不用"" 常量需要""
BEGIN任务 执行1次,读取文档之前执行
逐行任务  执行n次,读取文档时执行
END任务   执行1次,读取文档之后执行
awk 'BEGIN{pirnt "abc"}{print "opq"}END{print "xyz"}' user

awk 'BEGIN{print "user\tUDI\tHome"}'
awk -F: '{print $1"\t"$3"\t"$6}' user
awk 'END{print "总计"NR"行"}' user
上面三条命令合计如下**************************
awk -F: 'BEGIN{print "user\tUDI\tHome"}{print $1"\t"$3"\t"$6}END{print "总计"NR"行"}' user 
输出如下**********************************
user    UDI     Home
root    0       /root
bin     1       /bin
daemon  2       /sbin
adm     3       /var/adm
lp      4       /var/spool/lpd
总计5行

日志文件
la /var/log/httpd/access_log
格式为:192.168.88.240 - - [07/Mar/2024:17:29:17 +0800] .....
统计日志文件ip出现的次数
awk 'BGEIN{}{a[$1]++}END{for(i in a){print i"出现了"a[i]"次"}}' /var/log/httpd/access_log
查询      定义数组a,下标为每行第一列ip,下标(ip)相同,数字加一 ,结尾for循环,i为下标a[i]为统计的次数   
sort排序
awk 'BGEIN{}{a[$1]++}END{for(i in a){print i"出现了"a[i]"次"}}' /var/log/httpd/access_log | sort -n -k2 以数字和第二列排列,默认升序   在n后面跟着r降序

数组
名字[下标]=值
下标为非数字需要加""

192.168.88.240 - - [07/Mar/2024:17:29:17 +0800] 


yum案例
#!/bin/bash
sed -i '/\/dev\/sr0/d' /etc/fstab
umount /mydvd
rm -rf /etc/yum.repos.d/*
echo "[haha]" >> /etc/yum.repos.d/haha.repo
echo "name=haha" >> /etc/yum.repos.d/haha.repo
echo "baseurl=file:///mydvd" >> /etc/yum.repos.d/haha.repo
echo "gpgcheck=0" >> /etc/yum.repos.d/haha.repo
echo "/dev/sr0 /mydvd iso9660 defaults 0 0" >> /etc/fstab
mount -a

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到