处理字符串的表示方式,它以行为单位来进行字符串的处理操作,正则表达式通过一些特殊符号的辅助,可以让用户轻易地完成【查找、删除、替换】某特定字符串的处理过程。
正则表达式的字符串表达方式依照不同严谨度分为:
实验素材 regular_express.txt
"Open Source" is a good mechanism to develop programs.
2 apple is my favorite food.
3 Football game is not use feet only.
4 this dress doesn't fit me.
5 However, this dress is about $ 3183 dollars.
6 GNU is free air not free beer.
7 Her hair is very beauty.
8 I can't finish the test.
9 Oh! The soup taste good.
10 motorcycle is cheap than car.
11 This window is clear.
12 the symbol '*' is represented as start.
13 Oh! My god!
14 The gd software is a library for drafting programs.
15 You are the best is mean you are the no. 1.
16 The world
17 I like dog.
18 google is the best tools for search keyword.
19 goooooogle yes!
20 go! go! Let's go.
21 # I am VBird
22
语系对正则表达式的影响—— 不同语系的编码数据不同,会造成数据选取结果的差异
基础正则表达式字符集合(characters)
grep -n '^#' regular_express.txt # 查找行首为 # 开始的那一行,并列出行号
grep -n '!$' regular_express.txt # 将行尾为 ! 的那一行打印出来,并列出行号
grep -n 'e.e' regular_express.txt # 查找的字符串可以是(eve)、(eee)、(e e)等,但不能仅有(ee),即 e 与 e 中 间【一定】仅有一个字符,而空格也是字符
grep -n \' regular_express.txt # 查找含有单引号 ' 的那一行
grep -n 'ess*' regular_express.txt # 找出含有(es)、(ess)、(essss)等的字符串,注意 * 可以是 0 个,(es)也符合。另外因为 * 为重复【前一个 RE 字符】的符号,在 * 之前必须紧跟着一个 RE 字符,如任意字符则为 【.*】
grep -n 'g[ld]' regular_express.txt # 查找含有 (gl)或(gd)的那一行。注意 在 [ ] 当中【谨代表一个待查找的字符】,如[afl] 代表 a 或 f 或 l 的意思
grep -n '[A-Z]' regular_express.txt # 查找含有 左右大写字符的那一行
grep -n 'oo[^t]' regular_express.txt # 查找的字符串可以是(oog)、(ood)但不能是(oot),^ 在 [] 内代表【反向选择】
grep -n 'go[2,3\]g' regular_express.txt # 查找在 g 与 g 之间有2到3个 o 存在的字符串,亦即(goog)、(gooog)
grep [ -A ] [ -B ] [ --color=auto ] ' 查找字符 ' filename
备注:grep 在数据中查询一个字符串时,是以【整行】为单位来进行数据的选取。
例一:查找特定字符串 'the'
查找不含特定字符串 'the' 的行,并输出行号 —— 反向选择
例二:利用中括号 [] 来查找集合字符
^ 符号,在字符集合符号(括号[])之内与之外不同,在 [] 之内代表反向选择,[] 之外代表定位在行首 !!
注意 ;小数点具有其他意义,必须使用转义符(\)来解除小数点特殊意义
正则表达式 . *
注意:正则表达式不是通配符 ,通配符 * 可以代表任意(0个或 多个)字符
例五:限定连续 RE 字符的范围 {}
注意 —— { 与 } 的符号在 shell 中有特殊意义,使用 RE (正则)表示时,必须使用 转义符 \ 来让它失去特殊意义
sed [ -nefr ] [操作]
n1 ,n2 不一定存在,一般代表【选择进行操作的行数】
function:
例一:以行为单位的新增/删除功能
nl /etc/passwd | head -n 4 | sed '2a drink tee... \ # 第 2 行后新增多行
> drink beer' # 新增多行时, 末尾 \
例二:以行为单位的替换与显示功能
例三:部分数据的查找并替换功能 —— sed 's/要被替换的字符/新的字符/g'
例:利用 sed 选取出 ifconfig ens160 的 IP
inet 172.25.254.10 netmask 255.255.255.0 broadcast 172.25.254.255
172.25.254.10 netmask 255.255.255.0 broadcast 172.25.254.255
ifconfig ens160 | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *netmask.*$//g' # sed 's/<空格>*netmask.*$//g' 删除 IP 后面部分
172.25.254.10
例四:直接修改文件内容(谨慎操作)
1 "Open Source" is a good mechanism to develop programs.
2 apple is my favorite food.
3 Football game is not use feet only.
4 this dress doesn't fit me.
5 However, this dress is about $ 3183 dollars.
1 "Open Source" is a good mechanism to develop programs!
2 apple is my favorite food!
3 Football game is not use feet only!
4 this dress doesn't fit me!
5 However, this dress is about $ 3183 dollars!
awk 适用于一行当中分成数个字段来处理数据,而默认的字段的间隔符为“空格键”或“[Tab]键”。
awk ' 条件类型 1 {操作1} 条件类型 2 {操作2} ... ' filename
awk 内置变量及意义
例:last -n 5
awk 逻辑运算符
例:查看 /etc/passwd ,并显示出账户,及UID,且UID 小于10
awk 的使用重要事项
利用 shell 的功能所写的一个【程序 program】,这个程序使用纯文本文件,将一些 shell 的语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据重定向等功能,已达到我们想要的目的。
Shell 脚本的编写注意事项:
#!/bin/bash # 第一行 #!/bin/bash 声明这个脚本使用的 shell 名称!!
echo "this is my first shell script"
hostname
whoami
id
echo "OK!"
this is my first shell script
client.westos.com
root
uid=0(root) gid=0(root) groups=0(root) # 简单的 shell 就是依次顺序 从上到下执行,直到结束
OK!
例:编写一个脚本,让用户输入:1. first name 2. last name ,最后在屏幕上显示:【Your full name is:】的内容
9 #!/bin/bash
10 read -p "please keyin your first name: " firstname # 输入 read -p " "
11 read -p "please keyin your last name: " lastname # 输入 read -p " "
12 echo -e "\nYour full name is: ${firstname} ${lastname}" # 输出 echo -e " \n " \n 换一行输出
please keyin your first name: Li # 输入 Li
please keyin your last name: Dong # 输入 Dong
Your full name is: Li Dong # 自动显示 full name
例:假设用户输入 filename ,而今天的【日期】 是 2020/07/10 ,我想以前天、昨天、今天的日期来建立这些文件,即filename_20200710、filename_20200709、filename_20200708,该怎么办?
#!/bin/bash
read -p "Please keyin your filename: " fileuser # 让输入者输入文件名称,并取得 'fileuser'
filename=${fileuser:-"filename"} # 避免使用者随意按 Enter ,利用变量功能分析有么有配置文件名
date1=$(date --date='2 days ago' +%Y%m%d) # 利用 date 命令取得文件名 ,前两天日期
date2=$(date --date='1 days ago' +%Y%m%d) # 前一天日期
date3=$(date +%Y%m%d) # 当天日期
file1=${filename}${date1} # 配置文件名
file2=${filename}${date2}
file3=${filename}${date3}
touch "${file1}" # 建立文件
touch "${file2}"
touch "${file3}"
Please keyin your filename: dodo
-rw-r--r-- 1 root root 0 Jul 10 19:11 dodo20200708
-rw-r--r-- 1 root root 0 Jul 10 19:11 dodo20200709
-rw-r--r-- 1 root root 0 Jul 10 19:11 dodo20200710
1)利用 test 命令的测试功能
test 命令
test = [ ] # [ ] 相当于 test 命令
例: " test $a =$b " = [ "$a" = "$b" ]
test 数字对比
= / !=
test 的条件关系
test 对空的判定(判定字符串的数据)
test 对文件的判定
例:让用户输入一个文件名,来判断:
#!/bin/bash
echo -e "Please input a filename,I will check the filename's type and permission. \n"
read -p "Please input a filename: " filename
test -z ${filename} && echo "You mast input a filename." && exit 0 # 判断使用者是否真的输入字符!!
test -d ${filename} && echo "The filename: '${filename}'dont exist!" && exit 0
test -f ${filename} && filetype="regulare file"
test -d ${filename} && filetype="directory"
test -r ${filename} && perm="readable"
test -w ${filename} && perm="${perm} writeable"
test -x ${filename} && perm="${perm} executable"
echo "The filename :${filename}" is a ${filetype}
echo "and the permissions for you is :${perm}"
Please input a filename,I will check the filename's type and permission.
Please input a filename: westos # 输入名为 weatos 会检测,如果存在,下面会显示检测数据,否则为空
The filename :westos is a regulare file
and the permissions for you is :readable
例 :编写脚本完成以下条件
file_check.sh 在执行时,①如果脚本未指定检测文件报错 “未指定检测文件,请指定” ,②如果脚本执行后指定文件不存在 ,报错“此文件不存在”,且当文件存在时请检测文件类型,并显示到输出中。
2)利用判断符号 [ ]
例:
#!/bin/bash
read -p "Please input Y or N : " yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK,continue" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "Oh,interrput" && exit 0
echo "I don't know what your choice is" && exit 0
Please input Y or N : n
Oh,interrput
应用练习
练 1:根据当前登录用户uid判断是否为超级用户?提示:uid=0代表超级用户,如果是超级用户输出”the user is root”,否则输出”the user is not root”。
#!/bin/bash
[ `id -u` -eq 0 ] && echo "the user is root" || echo "the user isn't root" # 通过 id -u 命令 查看 UID ,只有 UID=0 为 root用户!
练 2:用户输入云服务器相关信息(主机名),判断主机名输入是否合法?
#!/bin/bash
read -p "Please kiyin a hostname: " hostname
[ -z "$hostname" ] && echo " keyin is wrong,please keyin again!" || echo "keyin ok"
3)shell 脚本的默认变量($0、$1...)
例:用户输入两个变量,然后将两个变量的内容相乘,最后输出相乘结果,怎么办?
#!/bin/bash
echo -e "You should input 2 numbers,I will multiplying them!\n"
read -p "first number: " firnu
read -p "second number: " secnu
total=$((${firnu}*${secnu})) # 【$((计算式))】,注意 ‘=’ 左右不能有空格间隔!!
echo -e "The result of ${firnu}*${secnu} is ==> ${total}"
You should input 2 numbers,I will multiplying them!
first number: 4
second number: 7
The result of 4*7 is ==> 28
单层、简单条件判断式
当条件判断成立时,可以进行的命令工作内容;
备注: && 代表 AND ; || 代表 or ;
例:改写 ans_yn.sh 脚本 为if ... then 样式
#!/bin/bash
read -p "Please input Y or N : " yn # 当执行一个程序的时候,这个程序的时候,这个程序会让用户选择 Y 或 N
if [ "${yn}" == "Y" -o "${yn}" == "y" ]; then # 如果用户输入Y 或 y 时,就显示【OK,continue】;
echo "OK,continue"
exit 0
fi
if [ "${yn}" == "N" -o "${yn}" == "n" ]; then # 如果用户输入N 或 n 时,就显示【OK,interrupt】;
echo "Oh,interrput"
exit 0
fi
echo "I don't know what your choice is" && exit 0 # 如果不是 Y/y/N/n 之内的其他字符,就显示【I don't know what your choice is】
例:判断当前主机与远程主机的网络连接状态 (是否能 ping 通?)—— 主机连通性性判断
#!/bin/bash
read -p "Please keyin ipaddress: " IP
if [ `ping -c 1 "$IP" &>/dev/null;echo "$?" ` -eq 0 ]; then
echo "$IP is up"
else
echo "$IP is down"
fi
例:判断 Web 服务器当中 httpd 服务进程是否存在?—— 进程存在性判断
#!/bin/bash
ps=$*
if [ `pgrep $ps &>/dev/null; echo "$ps"` ]; then # 根据 pgrep 命令查找进程的返回值 ,判断是否存在进程
echo "$ps is exists in system"
else
echo "$ps isn't exists in system"
fi
拓展 pgrep 命令 —— 以名称为依据从运行进程队列中查找相关进程,并显示查找的进程id
例:输入一个用户,用脚本判断该用户是否存在?—— 用户存在性判断
#!/bin/bash
read -p "Please keyin a username: " name
if [ `grep -w "$name" /etc/passwd &>/dev/null;echo "$?"` -eq 0 ]; then
echo "The $name is extsis in system"
else
echo "The $name isn't extsis in system"
fi
备注:也可以用 id username 命令 查看用户是否存在 !
多重、复杂条件判断式
# 一个条件判断,分成功执行与失败执行(else)
当条件判断成立时,可执行命令;
else
当条件判断不成立时,可执行命令;
#多个条件判断 (if ... elif ... elif ... else)分多种不同情况执行
当条件判断式一成立时,可执行命令;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可执行命令;
else
当条件判断式一与二都不成立时,可执行命令;
例:想让用户输入 【hello】参数,在执行脚本命令时
#!/bin/bash
if [ "$1" == "hello" ]; then
echo "Hello,how are you?"
elif [ -z "$1" ]; then
echo "You mast keyin parameter after hello.sh!"
else
echo " parameter only keyin "hello"!! "
fi
应用练习
练 1:用脚本判断一个软件包是否安装,如果没有安装则进行安装(默认本地 yum源 已配置好)。
练 2:运用脚本判断当前内核版本号是否为2,且次版本号是否大于等于6,如果都满足则输出当前内核版本信息。
语法结构:
"第一个变量内容") # 每个变量建议 " " 双引号括起来,关键字为右侧圆括号 )
程序段(command1)
;; # 每个类别结尾使用 ';;' 来处理 !!
"第二个变量内容")
程序段(command2)
;;
*) # '*' 代表其他值
exit1
;;
例:有色字符串输出
1)while do done 、 until do done (不定循环)
2)for ...do ...done (固定循环)
例:如果实验室有100台主机,进行网络状态实际检测,检测的域名是主机所在的172.25.254.0~172.25.254.100网段,怎么办?
#!/bin/bash
network="172.25.254"
for setnu in {1..100}
do ping -c 1 ${network}.${setnu} >/dev/null && result=0 || result=1 # 获取 ping 的返回值是否正确!!
if [ $result == 0 ]; then
echo "${network}.${setnu} is UP"
else
echo "${network}.${setnu} is DOWN"
fi
done
例:让用输入某个目录文件名,然后找出目录内的文件名的权限
#!/bin/bash
read -p "Please keyin a directory: " dir
if [ "$dir" == "" -o ! -d "$dir" ]; then
echo "The directory "$dir" isn't exist in system"
exit 1
fi
filelist=$(ls ${dir}) # 列出该目录下所有文件名称
for filename in ${filelist} # 根据列出文件名称 定义 filename 循环变量参数
do
perm=""
test -r "${dir}/${filename}" && perm="${perm} readable"
test -w "${dir}/${filename}" && perm="${perm} writeable"
test -x "${dir}/${filename}" && perm="${perm} executable"
echo "The ${dir}/${filename} 's permission is ${perm}"
done
Please keyin a directory: /mnt
练习1:通过 for 循环计算 10!(10阶乘,即 10*9*8*...3*2*1)=?
9 #!/bin/bash
10 nu=1
11 for num in {2..10}
12 do
13 let nu=$nu*$num
14
15 done
16 total=$($nu*$num)
17 echo "$total"
练习2:通过 for 循环 批量新建5个新用户 stu1~stu5,要求这几个用户家目录都在 /rhome
#!/bin/bash
for var in {1..5}
do
if [ `id stu"$var">/var/null;echo "$?"` -eq 0 ];then
echo " stu$var is exist "
continue
else
useradd -d /rhome stu$var
fi
done
练习3:通过 for 循环,判断一个数是否为 质数——质数又叫做素数,是指只能被1或者自己整除的自然数 (???)
9 #!/bin/bash
10 read -p "Please keyin a number: " number
11 if [ -z "$number" -o "$number" -le 0 ];then
12 echo "You MAST KEYIN A NUMBER >0 !"
13 exit 1
14 elif [ "$number" -eq 1 -o "$number" -eq 2 ];then
15 echo "The "$number" is a perime number"
16 exit 0
17 elif [ "$number" -gt 2 ];then
18 max=$(($number-1))
19 mod=$(($number%p))
20 for p in {2..$max}
21 do
22 if [ "$mod" -ne 0 ];then
23 continue
24 echo "The "$number" is a perime number"
25 else
26 echo "The "$number" isn't a perime number"
27 exit 1
28 fi
29 done
30 fi
Z1.判断 /tmp/run 目录 存在与否,①不存在就建立 ②存在就删除目录下所有内容
Z2.输入一个路径判断路径是否存在,并输出目标文件类型(普通文件、链接、目录等)
Z3. 交互式输入一个主机IP,运用脚本判断此IP对应主机网络状态可否ping通,输出结果类似 Server “172.25.254.37 id Down”,并把结果邮件到本地管理员root@localhost mail01@localhost (发送邮件信息???)
Z4.写一个脚本/home/program ,当给脚本输入参数 hello ,返回值 world ,输入参数 world ,返回值 hello ,没有输入参数或参数错误,输出‘usage:/home/program hello or world ’
Z5.编写一个脚本 完成自动搭建 nfs 服务器
Z6.编写一个脚本,实现自动搭建 SAMABA 服务器
9 #!/bin/bash
10 #1.server's IP NETWORK STATUS
11 read -p "Please keyin server IP: " ip
12 if [ `ping -c1 "$ip" &> /dev/null;echo "$?"` -eq 0 ];then
13 echo "NETWORK STATUS is OK"
14 else
15 echo "NETWORK STATUS isn't OK"
16 exit 1
17 fi
18
19 #2.check Selinx & Firewalld
20 setenforce 0 &> /dev/null
21 systmctl stop firewalld &> /dev/null
22 echo "-----Kill Selinx & Firewalld-----"
23
24 #3.check samba package
25 rpm -q samba &> /dev/null
26 if [ `echo "$?"` -eq 0 ];then
27 echo "samba package has installed"
28 else
29 dnf install samba samba-common -y &> /dev/null && echo "samba instal l sucess" && echo "samba install failed"; exit 1
30 fi
31
32 #4.Edit SAMBA configure file
33 cd /etc/samba
34 [ -e /etc/samba/smb.conf -a -f /etc/samba/smb.conf ] && echo"/etc/samba/smb. conf is exists" || cp -p smb.conf.example smb.conf;echo "smb.conf create suc ess"
35
36 #5.create share dirctory [HAHA]
37 systemctl enable --now smb.service
38
39 cat >> /etc/samba/smb.conf << EOF
40 [HAHA]
41 comment = westos dir
42 path =/westos
43 EOF
44 systemctl restart smb.service
案例1:用户建立脚本
#!/bin/bash
[ `id-u` -eq 0 ] || echo "Error: This script must run as root!" ;exit 1
[ $# -eq 2 ] || echo "Error:Please input userlist and passlist" ;exit 1
[ -e $1 -a -f $1 ] || echo "Error:userlist not exists";exit 1
[ -e $2 -a -f $2 ] || echo "Error:passlist not exists";exit 1
user_line=`wc -l $1 | cut -d ' ' -f1`
pwds_line=`wc -l $2 | cut -d ' ' -f1`
[ $user_line != $pwds_line ] && echo "Error: userfile lines different of passfile"
max_line=`wc -l $1 | cut -d ' ' -f1`
for num in `seq 1 $max_line`
do
echo "----------------------------------"
username=`sed -n ${num}p %1`
password=`sed -n ${num}p %2`
useradd $username
if [ $? -eq 0 ]; then
echo "$username Create sucess"
echo $password | passwd --stdin $username
echo "$username set passwd success"
else
echo "$username Creat failed"
fi
done
案例2:自动登录
案例3:批量处理
案例4:数据备份
#!/usr/bin/bash
passwd=$1
dump_dir=/mnt/mysqldump
DB_CHOICE(){
db=$1
password=$2
echo "$db.sql is exists,choice: [S]kip [B]ackup [o]verwrite"
read -p "your choice: " choice
case $choice in
s|S) # skip 跳过
;;
b|B) # Backup 备份
mv /mnt/mysqldump/$db.sql /mnt/mysqldump/$db_backup.sql
echo "The backup successful ,/mnt/mysqldump/$db.sql"
;;
o|O) # overwrite 覆盖
mysqldump -uroot -p$password $db > /mnt/mysqldump/$db.sql
echo "The backup successful ,/mnt/mysqldump/$db.sql"
;;
*) # 输入正确选项
echo "Please enter the correct option!"
;;
esac
}
#1. chenage dir # 判断 /mnt/mysqldump 目录是否存在
echo "---------------------------------------------------"
if [ -e $dump_dir ];then
if [ ! -d $dump_dir ];then
rm -fr $dump_dir
mkdir $dump_dir
fi
else
mkdir $dump_dir
fi
#2. mysqldump # 获取数据库的所有数据库名称,并通过 for循环进行批量备份
echo "---------------------------------------------------"
dbs=`mysql -uroot -p$passwd -e "show databases;" | grep -E "Database|schema$" -v`
for db in $dbs
do
if [ -e /mnt/mysqldump/$db.sql ];then # 判断备份文件是否存在,如果已存在,询问用户需求(s/b/o)
DB_CHOICE $db $passwd
else
mysql -uroot -p$passwd $db > /mnt/mysqldump/$db.sql
fi
done
案例5:lamp服务 自动部署
lamp 服务构架 (linux + apache + mysql +python/php)
案例6:Shell 脚本 + dhcpd 、httpd、kickstart 实现自动安装 虚拟机系统
安装环境需求
步骤一 添加硬盘(安装虚拟机的硬件存储)
步骤二 虚拟机安装环境设置
步骤三 网络软件仓库搭建
步骤四 网卡配置
双网卡主机配置 :添加设备——网络配适器2 (桥接模式)
步骤五 DHCP 服务器搭建
步骤六 kickstart自动安装脚本的制作
步骤七 测试手动设置安装虚拟机
步骤七 编辑Shell 脚本 实现自动设置安装选项
#!/bin/bash
virt-install \
--location http://172.25.254.10/rhel8 \
--extra-args "ks=http://172.25.254.10/ks.cfg" \
--os-variant rhel8.0 \
--memory 2000 \
--vcpus 1 \
--disk path=/var/lib/libvirt/images/westos.qcow2,bus=virtio,size=10 \
--name westos \
--network type=bridge,source=br0,source_mode=virtio &> /dev/null &