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 后查看