Shell编程规范与变量三

Candy独角兽 / 2023-08-13 / 原文

目录
  • 1. 正则表达式
    • 1.1 元字符
    • 1.2 表示次数
    • 1.3 位置锚定
    • 1.4 分组或其他
    • 1.5 扩展正则表达式
    • 1.6 grep
  • 2. AWK
  • 3.常用脚本

1. 正则表达式

  • 通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符
[localhost ~]#man 7 regex
#可以使用man手册帮助

1.1 元字符

.   匹配任意单个字符,可以是一个汉字  
[]   匹配指定范围内的任意单个字符,示例:[zhou]   [0-9]   []   [a-z A-Z]   [:alpha:]
[^] 匹配指定范围外的任意单个字符,示例:[^zhou] [^a.z] [a.z]
[root@localhost ~]#ls /etc/|grep rc[.0-6]
#此处的点代表字符

[root@localhost ~]#ls /etc/ | grep 'rc\.'
#点值表示点需要转义

[root@localhost ~]# grep r..t /etc/passwd         
#r..t ..代表任意两个字符

[root@localhost ~]# echo abc |grep a.c              
#表示原来的点需要加\转义

[root@localhost ~]# echo abc |grep a\.c
#不加引号有时匹配会有出入

[root@localhost ~]# echo abc |grep 'a\.c'          
#标准格式需要加'' 或者""

[root@localhost ~]# ls |grep '[zhou].txt'    
#匹配[]中任意一个字符

[root@localhost ~]# ls [a-d].txt                
#通配符

[root@localhost ~]# ls |grep '[a-d].txt'             
#真正的小写在正则表达式中

[root@localhost ~]# ls |grep '[^a-z].txt'   
#显示非小写字母

[root@localhost ~]# ls |grep '[^a.z].txt'     
#[]里就是本意不需要转义

1.2 表示次数

*        #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.*       #任意长度的任意字符,不包括0次
\?       #匹配其前面的字符出现0次或1次,即:可有可无
\+       #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\}    #匹配前面的字符n次
\{m,n\}  #匹配前面的字符至少m次,至多n次
\{,n\}   #匹配前面的字符至多n次,<=n
\{n,\}   #匹配前面的字符至少n次
示例
[root@localhost ~]#echo 2452450982 | grep '[0-9]\{5,12\}'   #过滤QQ号
2452450982


[root@localhost ~]#ifconfig ens33 | grep netmask    #匹配子网掩码
        inet 192.168.8.100  netmask 255.255.255.0  broadcast 192.168.8.255
[root@localhost ~]#ifconfig ens33 | grep netmask | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+'    #匹配地址
192.168.8.100
255.255.255.0
192.168.8.255
[root@localhost ~]#ifconfig ens33 | grep netmask | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1   #匹配IP地址
192.168.8.100


[root@localhost ~]#ifconfig ens33 | grep netmask | tr -s ' ' | cut -d ' ' -f3  #匹配IP地址
192.168.8.100


[root@localhost ~]#cat /etc/fstab | grep -o '\b[[:alpha:]]\+\b' | wc -l  #匹配单词数
46


[root@localhost ~]#cat /etc/fstab | grep -v '^$' | grep '^[^#]'   #过滤不是以#开头的行
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=773916b1-ec4c-45ee-ac99-fa9a0cad9565 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

1.3 位置锚定

^    #行首锚定, 用于模式的最左侧
$    #行尾锚定,用于模式的最右侧
^PATTERN$  #用于模式匹配整行 (单独一行  只有root)
^$   #空行
^[[:space:]]*$  #空白行


\< 或 \b        #词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\> 或 \b        #词尾锚定,用于单词模式的右侧
\<PATTERN\>     #匹配整个单词

1.4 分组或其他

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+

后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名

方式为: \1, \2, \3, ...

\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

或者
或者:\|
[root@localhost ~]#echo abcabcabc | grep '\(abc\)\{3\}'  #匹配3次abc
abcabcabc

1.5 扩展正则表达式

grep -E

  • 表示次数
*     #匹配前面字符任意次
?     #0或1次
+     #1次或多次
{n}   #匹配n次
{m,n} #至少m,至多n次
{,n}  #匹配前面的字符至多n次,<=n,n可以为0
{n,}  #匹配前面的字符至少n次,<=n,n可以为0
  • 表示分组
() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者  
a|b        #a或b
C|cat      #C或cat
(C|c)at  #Cat或cat
示例
[root@localhost ~]#ifconfig ens33 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'  #匹配地址
192.168.8.100
255.255.255.0
192.168.8.255
[root@localhost ~]#ifconfig ens33 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1  #匹配IP地址
192.168.8.100

[root@localhost ~]#cat /dev/random | tr -dc [[:alnum:]] | head -c 12   #随机生成密码
[zDoFqM6r37N[root@localhost ~]#cat /dev/random | tr -dc [[:alnum:]] | head -c 12
rsb9xJiPyMkc[root@localhost ~]#cat /dev/random | tr -dc [[:alnum:]] | head -c 12
FUaeRUSdMv3Z[root@localhost ~]#cat /dev/random | tr -dc [[:alnum:]] | head -c 12
N9cdfOpAuL46[root@localhost ~]#
[root@localhost ~]#cat passwd | cut -d: -f1,4 /etc/passwd   #取文件第1和第4列,冒号分隔
[root@localhost ~]#cat log | cut -d ' ' -f1 | sort -rn | uniq -c | head
   4477 172.16.13.251
   4512 172.16.13.250
   4549 172.16.13.249
   4528 172.16.13.248
   4606 172.16.13.247
   4414 172.16.13.246
   4567 172.16.13.245
   4594 172.16.13.244
   4555 172.16.13.243
   4444 172.16.13.242

1.6 grep

grep [选项]… 查找条件 目标文件

选项
-i:查找时忽略大小写
-v:反向查找,输出与查找条件不相符的行
-n:显示匹配行的行号
-o:只显示匹配项
-f:对比两个文件的相同行
-c:打印匹配的行数
  • -E:扩展的正则表达式,相当于egrep(可以识别特殊正则符号)
  • -e:实现多个选项间的逻辑or关系,或者使用egrep

2. AWK

awk语言

  • 读取一行处理一行

  • 在 Linux/UNIX 系统中,awk 功能强大的编辑工具,逐行读取输入文本,

  • 默认以空格 /tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。

  • awk比较倾向于将一行分成多个字段然后进行处理。

  • AWK信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。

格式
awk 选项      模式        值         文件
awk option  'program'  var=value   file…

选项:
-F:指定分隔符
-v:自定义变量
-f:脚本
[root@localhost ~]#df | awk '{print $2,$1}'   #挑取指定列
1K-块 文件系统
31441920 /dev/mapper/centos-root
917604 devtmpfs
933524 tmpfs
933524 tmpfs
933524 tmpfs
5232640 /dev/sda1
186708 tmpfs
186708 tmpfs
           
                                   #提取感兴趣的行 #挑取感兴趣的列
[root@localhost ~]#ifconfig ens33 | awk '/netmask/{print $2}'
192.168.8.100
[root@localhost ~]#echo $PATH | awk -F: -v OFS="\n" '{print $1,$2}'
/usr/local/sbin
/usr/local/bin
#OFS表示输出时的分隔符

[root@localhost ~]#echo $PATH | awk -F: '{print $1,$2}'
/usr/local/sbin /usr/local/bin
[root@localhost ~]#echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]#echo $PATH | awk -F: '{print $(NF-1)}'
/usr/bin
[root@localhost ~]#ifconfig ens33 | awk 'NR%2==0'
        inet 192.168.8.100  netmask 255.255.255.0  broadcast 192.168.8.255
        ether 00:0c:29:76:f0:1a  txqueuelen 1000  (Ethernet)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@localhost ~]#ifconfig ens33 | awk 'NR==2{print$2}'
192.168.8.100


[root@localhost ~]#ifconfig ens33 | awk 'NR%2==0{print NR}'
2
4
6
8

[root@localhost ~]#cat /etc/passwd | awk -F: '$3>1000{print $1}'
nfsnobody
[root@localhost ~]#cat /etc/passwd | awk -F: '$3>1000{print}'
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
[root@localhost ~]#cat /etc/passwd | awk -F: '$3>=1000{print}'
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
lj:x:1000:1000:LJ:/home/lj:/bin/bash

[root@localhost ~]#awk '{print FNR}' /etc/issue /etc/os-release
1
2
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

[root@localhost ~]#awk '{print NR}' /etc/issue /etc/os-release
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

[root@localhost ~]#awk '{print FNR,$0}' /etc/issue /etc/os-release
1 \S
2 Kernel \r on an \m
3 
1 NAME="CentOS Linux"
2 VERSION="7 (Core)"
3 ID="centos"
4 ID_LIKE="rhel fedora"
5 VERSION_ID="7"
6 PRETTY_NAME="CentOS Linux 7 (Core)"
7 ANSI_COLOR="0;31"
8 CPE_NAME="cpe:/o:centos:centos:7"
9 HOME_URL="https://www.centos.org/"
10 BUG_REPORT_URL="https://bugs.centos.org/"
11 
12 CENTOS_MANTISBT_PROJECT="CentOS-7"
13 CENTOS_MANTISBT_PROJECT_VERSION="7"
14 REDHAT_SUPPORT_PRODUCT="centos"
15 REDHAT_SUPPORT_PRODUCT_VERSION="7"
16 


[root@localhost ~]#awk -F: '{print NR,$1}' /etc/passwd

[root@localhost ~]#awk -F: '{print NR,$1}' /etc/passwd | cat -A

3.常用脚本

#!/bin/bash

cat <<EOF
1.搭建本地yum仓库
2.关闭防火墙
3.关闭selinux
4.免密登录
5.修改主机名
6.查看系统信息(五大性能)
7.自动磁盘分区
EOF

read -p "请输入数字选择功能:(1-7)" number

case $number in
1)
read -p "先测试网络是否连接(点击回车自动测试)" ip
ping -c 3 114.114.114.114
if [ $? -eq 0 ]
then
      echo  "网络正常"

read -p "是否开始搭建本地yum仓库(yes/no)" key
key=`echo $key | tr 'A-Z' 'a-z'`
case $key in
y|yes)

       echo "请耐心等待安装......"

#关闭防火墙
systemctl stop firewalld.service
#临时关闭selinux
setenforce 0

#挂载提供安装包和元数据
mount /dev/sr0 /mnt

#切换到客户端的指定目录
cd /etc/yum.repos.d/

#建立文件夹存放网络yum仓库的配置文件
mkdir bak

#将网络源移走,减少干扰
mv *.repo bak/

#编写本地yum仓库
echo "
[lj]
name=lj
baseurl=file:///mnt
gpgcheck=0
">local.repo

#清理缓存
yum clean all

#重新构建元数据
yum makecache

;;

n|no)

echo "取消安装"

;;

*)

echo "输入有误!"

esac

else
        echo  "网络无连接"
fi
;;
2)
systemctl status firewalld | grep "is not running" &>/dev/null
if [ $? -eq 0 ]
then
   echo "防火墙处于关闭状态!"

else
   read -p "防火墙处于开启状态,是否需要关闭防火墙:(yes|no)" key
key=`echo $key | tr 'A-Z' 'a-z'`
case $key in
y|yes)
   #关闭防火墙
   systemctl stop firewalld.service
   echo "防火墙关闭成功!"

;;

n|no)

echo "防火墙未关闭!"

;;

*)

echo "输入有误!"

esac

fi
;;
3)
getenforce | grep Enforcing&>/dev/null
if [ $? -eq 0 ]
then
   echo "selinux正在运行中……"
   #临时关闭selinux
   setenforce 0

  getenforce | grep Enforcing&>/dev/null
  if [ $? -eq 0 ]
  then
   echo "selinux关闭失败,请重新关闭!"
  else
   echo "selinux临时关闭成功!"
  fi

else
   echo "selinux已经是关闭状态!"

fi
;;
4)
PASS=123123
#设置网段最后的地址,4-255之间,越小扫描越快
END=254

IP=`ip a s ens33 | awk -F'[ /]+' 'NR==3{print $3}'`
NET=${IP%.*}.

rm -f /root/.ssh/id_rsa
[ -e ./SCANIP.log ] && rm -f SCANIP.log
for((i=3;i<="$END";i++));do
ping -c 1 -w 1  ${NET}$i &> /dev/null  && echo "${NET}$i" >> SCANIP.log &
done
wait

ssh-keygen -P "" -f /root/.ssh/id_rsa
rpm -q sshpass || yum -y install sshpass
sshpass -p $PASS ssh-copy-id -o StrictHostKeyChecking=no $IP

AliveIP=(`cat SCANIP.log`)
for n in ${AliveIP[*]};do
sshpass -p $PASS scp -o StrictHostKeyChecking=no -r /root/.ssh root@${n}:
done
;;
5)
read -p "请输入要修改的名字:" name

hostnamectl set-hostname $name

bash
;;
6)
ip=$(ifconfig ens33|grep netmask|tr -s ' '|cut -d' ' -f3)
mem=`free -h | grep Mem | tr -s ' ' | cut -d ' ' -f2`
host=`hostname`
kernel=`uname -r`
disk=`lsblk |grep disk|tr -s ' '|cut -d ' ' -f4`
cputy=`lscpu |grep 型号名称|tr -s ' '|cut -d ' ' -f2-7`
cpuhs=`lscpu |grep 'CPU(s):'|tr -s ' '|cut -d ' ' -f2`

echo "该主机的ip地址为:$ip"
echo "该主机的总内存为:$mem"
echo "该主机的主机名为:$host"
echo "该主机的内核版本为:$kernel"
echo "该主机的disk大小为:$disk"
echo "该主机的CPU型号为:$cputy"
echo "该主机的CPU核数为:$cpuhs"
;;
7)
echo "- - -" >/sys/class/scsi_host/host0/scan
echo "- - -" >/sys/class/scsi_host/host1/scan
echo "- - -" >/sys/class/scsi_host/host2/scan
echo -e "n\n\n\n\n\nw" | fdisk /dev/sdb
;;

esac