20单元——学习正解表达式及学习实践 Shell script

正则表达式:

处理字符串的表示方式,它以行为单位来进行字符串的处理操作,正则表达式通过一些特殊符号的辅助,可以让用户轻易地完成【查找、删除、替换】某特定字符串的处理过程。

正则表达式的字符串表达方式依照不同严谨度分为:

  • 基础正则表达式
  • 扩展正则表达式

实验素材 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 <Happy> is the same with "glad".
 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)

  • ^word :待查找的字符串(word)在首行

grep -n '^#' regular_express.txt                          # 查找行首为 # 开始的那一行,并列出行号

  • word$:待查找的字符串(word)在行尾

grep -n '!$' regular_express.txt                         # 将行尾为 ! 的那一行打印出来,并列出行号

  • . :代表【一定有一个任意字符】的字符

grep -n 'e.e' regular_express.txt                         # 查找的字符串可以是(eve)、(eee)、(e e)等,但不能仅有(ee),即 e 与 e 中  间【一定】仅有一个字符,而空格也是字符

  • \:转义符,将特殊符号的特殊意义去除

grep -n \' regular_express.txt                             # 查找含有单引号 ' 的那一行

  • *:重复零到无穷多个的前一个 RE 字符

grep -n 'ess*' regular_express.txt                      #  找出含有(es)、(ess)、(essss)等的字符串,注意 * 可以是 0 个,(es)也符合。另外因为 * 为重复【前一个 RE 字符】的符号,在 * 之前必须紧跟着一个 RE 字符,如任意字符则为 【.*】

  • [list]:字符集合的 RE 字符,里面列出想要选取的的字符

grep -n 'g[ld]' regular_express.txt                      # 查找含有 (gl)或(gd)的那一行。注意 在 [ ] 当中【谨代表一个待查找的字符】,如[afl] 代表  a 或 f 或 l 的意思

  • [n1-n2]:字符集合的 RE 字符,里面列出想要选取的的字符范围

grep -n '[A-Z]' regular_express.txt                    #  查找含有 左右大写字符的那一行

  • [^list]:字符集合的 RE 字符,里面列出想不要的字符串或范围

grep -n 'oo[^t]' regular_express.txt                  #  查找的字符串可以是(oog)、(ood)但不能是(oot),^ 在 [] 内代表【反向选择】

  • \{n,m\}:意义①:连续 n 到 m 个的【前一个 RE 字符】;意义②:若为\{n\},则为连续 n个前一个 RE 字符;意义③:若为\{n,\},则为连续 n 个以上的前一个 RE 字符;

grep -n 'go[2,3\]g' regular_express.txt            #  查找在 g 与 g 之间有2到3个 o 存在的字符串,亦即(goog)、(gooog)

扩展正则表达式

  • +:重复【一个或一个以上】的前一个 RE 字符
  • ?:【零个或一个】的前一个 RE 字符
  • |:用或(or)的方式找出数个字符串
  • ():找出【群组】字符串
  • ()+:多个重复群组的判别 

1)grep 的高级选项应用

grep [ -A ]  [ -B ] [ --color=auto ]  ' 查找字符 '  filename

  • [ -A ] :后面可加数字,为 after 的意思,除了列出改行外,后续的 n 行业列出来
  • [ -B ]:后面可加数字,为 befer 的意思,除了列出改行外,前面的 n 行业列出来
  • [ --color=auto ]:可将正确的那个选取数据列出颜色

备注:grep 在数据中查询一个字符串时,是以【整行】为单位来进行数据的选取。

例一:查找特定字符串 'the'

  • grep -n 'the' regular_express.txt                       # 查找特殊字符串 'the' ,并输出行号

          查找不含特定字符串 'the' 的行,并输出行号  —— 反向选择

  • grep -vn 'the' regular_express.txt                     # -v 反向选择

例二:利用中括号 [] 来查找集合字符

  • grep -n 't[ae]st' regular_express.txt                #  查找 字符串【tast】或【test】的行, [] 里面不论几个字符,都仅代表【一个】字符
  • grep -n '[0-9]' regular_express.txt                  #  查找 【数字】的行

  • grep -n 'oo' regular_express.txt                   # 查找 有特殊字符 'oo'的行,并输出行号
  • grep -n '[^g]oo' regular_express.txt             # 查找 有特殊字符 'oo'的行,且 oo 前面不含 【g 】,利用集合字符的反向选择 [^]完成
  • grep -n '[^a-z]oo' regular_express.txt          # 查找 有特殊字符 'oo'的行,且 oo 前面不含 【小写字符】
  • grep -n '[^[:lower:]]oo' regular_express.txt  #  [:lower:] 代表 a-z (小写字符)的意思

例三: 行首与行尾字符 ^ $

^ 符号,在字符集合符号(括号[])之内与之外不同,在 [] 之内代表反向选择,[] 之外代表定位在行首 !!

  • grep -n '^[a-z]oo' regular_express.txt              # ^[] 定位在行首
  • grep -n '^[a-z]' regular_express.txt                  # 查找开头不是英文字母的行,并输出行号
  • grep -n '^[^a-zA-Z]' regular_express.txt           #  a-zA-Z 等于 [:alpha:]

  • grep -n '[^\.]$' regular_express.txt             # 查找不是以 【.】 小数点 结尾的行,并输出行号。 

注意 ;小数点具有其他意义,必须使用转义符(\)来解除小数点特殊意义

  • grep -n '^$' regular_express.txt                # '^$'  只有行首与行尾 ,代表 【空白行】
  • grep -v '^$' /etc/rsyslog.conf | grep -v '^#'      # -v '^$' 代表 【不要空白行】  -v '^#'   代表 【不要 # 开头的注释行】

例四:任意一个字符 . 与重复字符 *

正则表达式  .   * 

  • [ . (小数点) ]:代表【一定有一个任意字符】的意思
  • [ *(星号)]:代表【重复前一个字符,0到无穷多次】的意思,为组合形态  

注意:正则表达式不是通配符 ,通配符 * 可以代表任意(0个或 多个)字符

  • grep -n 'g..d' regular_express.txt         #  查找 含有 'g??d' 的字符串 的行,强调 g 与 d 之间一定存在两个字符
  • grep -n 'ooo*' regular_express.txt       #  查找至少有两个 o 以上的字符串所在行
  • grep -n 'goo*g' regular_express.txt     #  查找 g 与 d 之间至少有一个 o 的字符串所在行
  • grep -n 'g.*g' regular_express.txt        # 找出 g 开头 与 g 结尾的字符串,当中字符串可有可无。 【.*】代表零个或多个任意字符
  •  grep -n '[0-9][0-9]*' regular_express.txt    #  找出含有任意数字的字符串的行。RE表示法  '[0-9][0-9]*'  等于  '[0-9]'

例五:限定连续 RE 字符的范围 {}

注意 —— { 与 } 的符号在 shell 中有特殊意义,使用 RE (正则)表示时,必须使用 转义符 \ 来让它失去特殊意义

  • grep -n 'o\{2\}' regular_express.txt              # 查找两个 o 的字符串所在行,并显示行号
  • grep -n 'go\{2,5\}' regular_express.txt         # 查找 g 后面接 2 到 5 个o 的字符串所在行,并显示行号
  • grep -n 'go\{2,\}' regular_express.txt           # 查找 g 后面接 2 个或 2个以上 o 的字符串所在行,并显示行号

2)sed :数据处理工具

sed [ -nefr ]  [操作]

  • -n:使用安静模式(silent),只有经过 sed 处理的那一行(或操作)才会被列出
  • -e:直接在命令模式上进行 sed 的操作编辑
  • -r:sed 的操作使用扩展型正则表达式语法。(默认是基础正则表达式语法)
  • -i:直接修改读取的文件内容,而不是由屏幕输出
  • [操作]:[n1[,n2]]  function

n1 ,n2 不一定存在,一般代表【选择进行操作的行数】

function:

  • a:新增,后可接 字符,而这些字符会在新的一行出现(目前行的下一行)
  • c:替换,后可接字符,这些字符可以替换 n1,n2 之间的行
  • d:删除,后面通常不接任何东西
  • i:插入,后可接字符,而这些字符会在新的一行出现(目前行的上一行)
  • p:打印,将某个数据打印出来,通常 p 会与参数 sed -n 一起运行
  • s:替换,可以直接进行替换的工作,s操作 通常可以搭配正则表达式

例一:以行为单位的新增/删除功能

  • nl /etc/passwd | sed '3,$d'             # 以行为单位,删除 第3到最后一行
  • cat -n /etc/passwd | sed '2,5d'       # 以行为单位,删除 第 2 ~ 5 行

  • nl /etc/passwd | head -n 4 | sed '2a drink tee...'             # sed ' 2a ...' 第 2 行后新增
  • nl /etc/passwd | head -n 4 | sed '2a drink tee... \           #  第 2 行后新增多行
    > drink beer'                                                                  #  新增多行时, 末尾  \<Enter> 进行换行输入!!

  • nl /etc/passwd | head -n 4 | sed '2i drink tee...'              # sed ' 2i ...'   第 2 行前新增

例二:以行为单位的替换与显示功能

  • nl /etc/passwd | head -n 6 | sed '2,5c NO 2-5 number'       #  将 第2-5行,内容替换成【NO 2-5 number】
  • nl /etc/passwd | sed -n '5,7p'                                              # 选取 第5-7行 打印出来  sed -n 'n1,n2p' 选取行更方便
  • nl /etc/passwd | head -n 7 | tail -n 3                                   # 选取 第5-7行 显示出来

例三:部分数据的查找并替换功能   ——  sed 's/要被替换的字符/新的字符/g'

例:利用 sed 选取出 ifconfig ens160 的 IP

  • ifconfig ens160
  • ifconfig ens160 | grep 'inet '                                      # grep  'inter<空格>' 选取关键数据(IP)所在行

        inet 172.25.254.10  netmask 255.255.255.0  broadcast 172.25.254.255

  • ifconfig ens160 | grep 'inet ' | sed 's/^.*inet //g'        # sed 's/^.*inet //g'    删除 IP 前面部分数据

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 

例四:直接修改文件内容(谨慎操作)

  • cat -n catfile | head -n 5

     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.

  • sed -i 's/\.$/\!/g'  catfile                            # sed 【-i】直接修改文件内容,不显示
  • cat -n catfile | head -n 5

     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!

3)awk:数据处理工具

awk 适用于一行当中分成数个字段来处理数据,而默认的字段的间隔符为“空格键”或“[Tab]键”。

awk ' 条件类型 1 {操作1}  条件类型 2 {操作2} ... '  filename

awk 内置变量及意义

  • NF:每一行($0)拥有的字段总数
  • NR:目前 awk 所处理的是第几行数据
  • FS:目前的分隔字符,默认是空格键

例:last -n 5

  • last -n 5 | awk '{print $1 "\t" $3}'                                          # "\t"  代表以 【Tab】按键隔开
  • last -n 5 | awk '{print $1 "\t lines: "NR"\t columns: "NF}'     # awk 内 NR 变量  (处理第几行数据) NF 变量(拥有字段总数)

awk 逻辑运算符

  • >=:大于等于
  • <=:小于等于
  • ==:等于
  • !=:不等于

 例:查看 /etc/passwd  ,并显示出账户,及UID,且UID 小于10

  • cat /etc/passwd |head -n4 | awk '{FS=":"} $3<10 {print $1 "\t" $3}'                # 第一栏 (账户) 第三栏 (UID)
  • cat /etc/passwd |head -n4 | awk 'BEGIN{FS=":"} $3<10 {print $1 "\t" $3}'     # BEGIN 预先设置 awk 的变量

awk 的使用重要事项

  • awk 的命令间隔:所有 awk 的操作 ,亦即在 {} 内的操作,如需要多个命令辅助时,可以用分号【;】间隔,或直接以 【Enter】按键来隔开每个命令。
  • 逻辑运算中,如果是等于的情况,务必使用【==】表示
  • 格式化输出时,在 printf 的格式设置中,务必加上 \n,才能进行分行
  • 与 bash shell 不同,awk 当中,变量可以直接引用,不需加上 $ 符号

Shell script (程序化脚本)的意义:

利用 shell 的功能所写的一个【程序 program】,这个程序使用纯文本文件,将一些 shell 的语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据重定向等功能,已达到我们想要的目的。

Shell 脚本的编写注意事项:

  • 命令是从上而下,从左而右地分析与执行;
  • 命令、选项、与参数间的多个空格都会被忽略;
  • 空白行也将被忽略掉,并且 [Tab]按键所产生的空白同样视为空格键;
  • 如果读取到一个 Enter 符号 (CR),就尝试开始执行该行(或该串)命令;
  • 如果一行内容太多,可以使用【\Enter】来扩展至下一行;
  • 【#】可以作为注释

用几行行命令 做出一个简单的 shell 脚本

  • touch myfirt_shell.sh                          # 创建脚本 myfirt_shell.sh 文件
  • vim myfirt_shell.sh                             # 编辑 脚本文件
  • cat myfirt_shell.sh

#!/bin/bash                                               # 第一行 #!/bin/bash 声明这个脚本使用的 shell 名称!!
echo "this is my first shell script"
hostname
whoami
id
echo "OK!"

  • chmod +x myfirt_shell.sh                   # 给脚本文件添加 执行权限 x
  • ls -l myfirt_shell.sh                         
  • sh myfirt_shell.sh                               # 运行脚本    sh + 脚本文件名

this is my first shell script
client.westos.com
root
uid=0(root) gid=0(root) groups=0(root)    # 简单的 shell 就是依次顺序  从上到下执行,直到结束
OK!

shell 脚本练习

  • 交互式脚本:变量内容由用户决定

例:编写一个脚本,让用户输入:1. first name 2. last name ,最后在屏幕上显示:【Your full name is:】的内容

  • vim showname.sh

  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 换一行输出

  • sh showname.sh

please keyin your first name: Li                  # 输入 Li
please keyin your last name: Dong            # 输入 Dong

Your full name is: Li Dong                          # 自动显示 full name

  • 随日期变化脚本:利用 date 建立文件 —— 服务器内数据库备份,解决每日不同数据文件命名

例:假设用户输入 filename ,而今天的【日期】 是 2020/07/10 ,我想以前天、昨天、今天的日期来建立这些文件,即filename_20200710、filename_20200709、filename_20200708,该怎么办?

  • vim create_filename.sh

#!/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}"

  • sh create_filename.sh                                                 # 测试

Please keyin your filename: dodo

  • ls -l

-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

  • 数值运算:简单的加减乘除

脚本执行方式的差异(source 、sh script 、./script)

  • 利用直接执行的方式来执行脚本
  • 利用 source 来执行脚本:在父进程中执行

 善用判断式

1)利用 test 命令的测试功能

test 命令 

test = [ ]                    # [ ] 相当于 test 命令

例: " test $a =$b " = [ "$a" = "$b" ]

test 数字对比

= / !=

  • -eq:  等于
  • -ne:不等于
  • -le:小于等于
  • -lt:小于
  • -ge:大于等于
  • -gt:大于

test 的条件关系

  • -a:并且 (and)
  • -o:或者 (or)

test 对空的判定(判定字符串的数据)

  • -n:  nozero  判定内容不为空
  • -z:  zero      判定内容为空

test 对文件的判定

  • -ef:文件节点号是否一致
  • -nt:文件1 是不是比文件 2 新
  • -ot:文件1 是不是比文件 2 旧
  • -S:套字节
  • -L:软连接
  • -e:【文件名】是否存在
  • -f:【文件名】是否存在,且为文件(file)
  • -d:【文件名】是否存在,且为目录(directory)
  • -b:快设备
  • -c:字符设备

例:让用户输入一个文件名,来判断:

  1. 此文件是否存在,如不存在则给予一个【Filename does not exist】的信息,并中断程序;
  2. 若文件存在,则判断它是一个文件或目录,结果输出【Filename is regular file】或 【Filename is directory】;
  3. 判断一下执行者的身份对这个文件或目录拥有的权限,并输出权限数据;
  • vim file_test.sh

#!/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}"

  • sh file_test.sh                                                  # 测试

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)利用判断符号 [ ]

  • 在 [] 内的每个组件,都需要有空格来分隔
  • 在 [] 内的变量,最好都以双引号括号起来
  • 在 [] 内的常数,最好都以单引号括号起来

例:

  1. 当执行一个程序的时候,这个程序的时候,这个程序会让用户选择 Y 或 N
  2. 如果用户输入Y 或 y 时,就显示【OK,continue】;
  3. 如果用户输入N 或 n 时,就显示【OK,interrupt】;
  4. 如果不是 Y/y/N/n 之内的其他字符,就显示【I don't know what your choice is】。
  • vim ans_yn.sh

#!/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

  • sh ans_yn.sh

Please input Y or N : n
Oh,interrput

应用练习

练 1:根据当前登录用户uid判断是否为超级用户?提示:uid=0代表超级用户,如果是超级用户输出”the user is root”,否则输出”the user is not root”。

  • vim L1_root.sh

#!/bin/bash
[ `id -u` -eq 0 ] && echo "the user is root" || echo "the user isn't root"         #  通过 id -u 命令 查看 UID ,只有 UID=0 为 root用户!

练 2:用户输入云服务器相关信息(主机名),判断主机名输入是否合法?

  • vim L2_hostname.sh

#!/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...)

例:用户输入两个变量,然后将两个变量的内容相乘,最后输出相乘结果,怎么办?

 

  • vim operation.sh
  • #!/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

条件判断式

利用 if...then

单层、简单条件判断式

  • if [ 条件判断式 ];  then

                   当条件判断成立时,可以进行的命令工作内容;

  • fi  (if 反过来写) ,结束 if 的意思

备注: &&  代表 AND   ; || 代表 or ;

例:改写 ans_yn.sh 脚本 为if ... then 样式

  • vim ans_yn.sh

#!/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 通?)—— 主机连通性性判断

  • vim L3_ping.sh

#!/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 服务进程是否存在?—— 进程存在性判断

  • vim L4_pgrep.sh

#!/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

  • -o:仅显示找到的最小(启示号)进程号
  • -n:仅显示找到的最大(结束号)进程号
  • -l:仅显示进程号
  • -P:指定父进程号, pgrep -P 4765 查看父进程(4765)下的子进程号
  • -t:指定开启进程的终端

例:输入一个用户,用脚本判断该用户是否存在?—— 用户存在性判断

  • vim L5_name.sh

#!/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)

  • if [ 条件判断式 ];  then

                   当条件判断成立时,可执行命令;

else

                   当条件判断不成立时,可执行命令;

  • fi  (if 反过来写) ,结束 if 的意思

#多个条件判断 (if ... elif ... elif ... else)分多种不同情况执行

  • if [ 条件判断式一 ];  then

                   当条件判断式一成立时,可执行命令;

elif  [ 条件判断式二 ];  then 

                    当条件判断式二成立时,可执行命令;        

else

                   当条件判断式一与二都不成立时,可执行命令;

  • fi  (if 反过来写) ,结束 if 的意思

例:想让用户输入 【hello】参数,在执行脚本命令时

  1. 判断 $1 是否为 hello,如果是的话,就显示 “Hello,how are you”
  2. 如果没有加任何参数,就提示用户必须要使用的参数执行法
  3. 而如果加入的参数不是 hello,就提醒用户仅能使用 hello 为参数
  • vim hello.sh

#!/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,如果都满足则输出当前内核版本信息。

利用 case...esac 判断

语法结构:

  • case $变量名称 in

                "第一个变量内容")                          # 每个变量建议 " " 双引号括起来,关键字为右侧圆括号 )

                             程序段(command1)

                             ;;                                            # 每个类别结尾使用 ';;' 来处理 !!

                "第二个变量内容")

                             程序段(command2)

                             ;;

                *)                                                        # '*' 代表其他值

                            exit1

                            ;;

  • esac        

例:有色字符串输出 

  • vim case_color.sh  

循环(loop)

1)while do done 、 until do done (不定循环)

2)for ...do ...done (固定循环)

例:如果实验室有100台主机,进行网络状态实际检测,检测的域名是主机所在的172.25.254.0~172.25.254.100网段,怎么办?

  • vim pingip.sh

#!/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

例:让用输入某个目录文件名,然后找出目录内的文件名的权限

  • vim dir_perm.sh

#!/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      

  • sh dir_perm.sh

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或者自己整除的自然数  (???)

  • vim L8_prime.sh

  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 目录 存在与否,不存在就建立 ②存在就删除目录下所有内容

  • vim Z1_dir.sh

Z2.输入一个路径判断路径是否存在,并输出目标文件类型(普通文件、链接、目录等)

  • vim Z2_PATH.sh                             (有效 & 无效 链接 的判断 ???)

Z3. 交互式输入一个主机IP,运用脚本判断此IP对应主机网络状态可否ping通,输出结果类似 Server “172.25.254.37 id Down”,并把结果邮件到本地管理员root@localhost    mail01@localhost          (发送邮件信息???)

  • vim Z3_ip.sh

 

Z4.写一个脚本/home/program ,当给脚本输入参数 hello ,返回值 world ,输入参数 world ,返回值 hello ,没有输入参数或参数错误,输出‘usage:/home/program hello or world ’

  • vim Z4_parameter.sh

Z5.编写一个脚本 完成自动搭建 nfs 服务器

  • vim Z5_NFSserver.sh

Z6.编写一个脚本,实现自动搭建 SAMABA 服务器

  • vim Z6_samaba.sh

  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:用户建立脚本

  • 执行 user_creat.sh  userlist  passlist
  • 建立 userlist 列表中的用户
  • 设定 userlist 列表中的密码为 passlist 列表中的密码
  • 当脚本后跟的文件个数 不足两个时 ,报错!
  • 当文件行数不存在时,报错!
  • 当用户已存在时,报错!

#!/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:自动登录

  • vim auto.sh

案例3:批量处理

案例4:数据备份

  • vim

#!/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 实现自动安装 虚拟机系统

安装环境需求

  • HTTP服务(FTP/NIS),提供yum安装源
  • DHCP服务:分配IP地址,定位引导程序
  • kickstart自动安装脚本的制作

步骤一  添加硬盘(安装虚拟机的硬件存储)

  • 添加设备 —— 硬盘 (SATA)50G

  • fdisk -l                              # 查看设备
  • fdisk /dev/sdb                  # 对添加的硬盘进行磁盘分区
  • udevadm settle                # 不重启 添加硬盘
  • mkfs.xfs  -K  /dev/sdb1    #格式化设置 磁盘文件系统为 .xfs格式

步骤二  虚拟机安装环境设置

  • dnf group list --hidden
  • dnf group install "Virtualization Client"  "Virtualization Hypervisor"  "Virtualization Tools"  -y    #  安装 虚拟机安装环境插件
  • mount /dev/sdb1   /var/lib/libvirt/images/                          # 将添加的硬盘设备挂载到虚拟机安装指定目录
  • blkid                                                                                  # 查看 sdb1 设备 的 UUID
  • vim /etc/fstab                                                                    # 编辑设置开机启动自动挂载
  • mount -a

步骤三  网络软件仓库搭建

  • dnf install httpd -y                                   # 安装 共享软件 Apache (阿帕奇 网页服务软件 Apache HTTP Server  )
  • systemctl enable --now httpd                 # 开启启动,并立即启用  httpd

  • mkdir /var/www/html/rhel8                       # 创建 共享目录 rhel8
  • mount  /run/media/root/RHEL-8-0-0-BaseOS-x86_64   /var/www/html/rhel8/  --bind    # 系统镜像 挂载 共享目录 --bind

步骤四  网卡配置

双网卡主机配置 :添加设备——网络配适器2 (桥接模式)

  • cd /etc/sysconfig/network-scripts/
  • ls
  • cp ifcfg-ens160  ifcfg-br0
  • vim ifcfg-ens160
  • vim ifcfg-br0
  • nmcli connection reload
  • nmcli connection down ens160
  • nmcli connection down br0
  • nmcli connection up ens160
  • nmcli connection up br0

步骤五  DHCP 服务器搭建

  • dnf install dhcp-server -y
  • cd /etc/dhcp/
  • ls
  • cp /usr/share/doc/dhcp-server/dhcpd.conf.example   dhcpd.conf         # 模板文件生成 dhcpd.conf
  • vim dhcpd.conf                                                                                      # 编辑 配置文件   172.25.254.10 为 dhcp 服务器
  • systemctl enable --now dhcpd                                                              # 启用 dhcpd 服务

 步骤六  kickstart自动安装脚本的制作

  • cp  -a /root/anaconda-ks.cfg /var/www/html/ks.cfg   #模板/root/anaconda-ks.cfg  ,重命名为ks.cfg 到网络共享目录下
  • chmod 755 /var/www/html/ks.cfg   # 赋予755文件权限
  • vim /var/www/html/ks.cfg                # 编辑启动脚本

步骤七  测试手动设置安装虚拟机

  • virt-manager

 

步骤七  编辑Shell 脚本 实现自动设置安装选项

  • touch virt.sh
  • vim virt.sh

#!/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 &

  • sh virt.sh                                  # 运行脚本 实现自动安装虚拟机系统配置

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值