linux——shell笔记

目录

第1 章 Shell 概述

1.1 什么是Shell  

1.2 Shell脚本意义

第2章 Shell 脚本入门

2.1 脚本格式

2.2 第一个Shell 脚本

2.3 脚本的常用执行方式

第3章 变量

3.1 系统预定义变量

3.1.1 常用系统变量

3.1.2 案例实操

3.2 自定义变量

3.2.1 基本语法

3.2.2 变量定义规则

3.2.3 将命令返回值赋给变量

3.2.4 案例实操

3.3 设置环境变量

3.3.1 基本语法

3.3.2 案例实操

3.4 特殊变量(位置参数变量)

3.4.1 基本语法

3.4.2 案例实操

3.5 预定义变量

3.5.1 基本介绍

3.5.2 基本语法

3.5.3 案例实操

第4 章 运算符

4.1 基本语法

4.2 案例实操

第5章 条件判断

5.1 基本语法

5.2 常用判断条件

5.3 案例实操

5.4 多条件判断

第6章 流程控制(重点)

6.1 if 判断

6.1.1 基本语法

6.1.2 案例实操

6.2 case 语句

6.2.1 基本语法

6.2.2 案例实操

6.3 for 循环

6.3.1 基本语法1

6.3.2 案例实操

6.3.3 比较$*和$@区别

6.3.4 基本语法2

6.3.5 案例实操

6.4 while 循环

6.4.1 基本语法

6.4.2 案例实操

第7章 read 读取控制台输入

7.1 基本语法

7.2 案例实操

第8章 函数

8.1 系统函数

8.1.1 basename

8.1.2 dirname

8.2 自定义函数

8.2.1基本语法

8.2.2经验技巧

8.2.3案例实操

第9章 正则表达式入门

9.1 常规匹配

9.2 常用特殊字符

9.2.1 特殊字符:^

9.2.2 特殊字符:$

9.2.3 特殊字符:.

9.2.4 特殊字符:*

9.2.5 字符区间(中括号):[ ]

9.2.6 特殊字符:\

第10章 文本处理工具

10.1 cut

10.1.1 基本用法

10.1.2 选项参数说明

10.1.3 案例实操

10.2 awk

10.2.1 基本用法

10.2.2 选项参数说明

10.2.3 案例实操

10.2.4 awk 的内置变量

10.2.5 案例实操

第11 章综合应用案例

11.1 归档文件

11.1.1 建立脚本实现归档操作

11.1.2 加入定时任务实现每日自动归档

11.2 发送消息

11.2.1 非脚本实现

11.2.2 脚本实现


第1 章 Shell 概述

1.1 什么是Shell  

shell是一个脚本中命令的解释器,它用于接收应用程序/用户命令,然后调用操作系统内核
Centos 默认的解析器是bash

1.2 Shell脚本意义

1.记录命令执行的过程和执行逻辑,以便以后重复执行
2.脚本可以批量处理主机
3.脚本可以定时处理主机

 

第2章 Shell 脚本入门

2.1 脚本格式

脚本以#!/bin/bash 开头(指定解析器)

2.2 第一个Shell 脚本

(1)需求:创建一个Shell 脚本,输出helloworld
(2)案例实操:


[root@node-15 ~]# vim helloworld.sh
[root@node-15 ~]# cat helloworld.sh
#!/bin/bash
echo "helloworld"

2.3 脚本的常用执行方式

第一种:采用bash 或sh+脚本的相对路径或绝对路径(不用赋予脚本+x 权限)

[root@node-15 ~]# bash ./helloworld.sh
helloworld
[root@node-15 ~]# sh ./helloworld.sh
helloworld
[root@node-15 ~]# bash /root/helloworld.sh
helloworld
[root@node-15 ~]# sh /root/helloworld.sh
helloworld
[root@node-15 ~]#

第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)

[root@node-15 ~]# ./helloworld.sh
-bash: ./helloworld.sh: 权限不够
[root@node-15 ~]# chmod +x helloworld.sh
[root@node-15 ~]# ./helloworld.sh
helloworld
[root@node-15 ~]# /root/helloworld.sh
helloworld
[root@node-15 ~]#

第一种执行方法,本质是bash 解析器执行脚本,所以脚本本身不需要执行权限。
第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。

 

第3章 变量

3.1 系统预定义变量

3.1.1 常用系统变量

$HOME、$PWD、$SHELL、$USER 等

3.1.2 案例实操

(1)查看系统变量的值

[root@node-15 ~]# echo $SHELL
/bin/bash

(2)显示当前Shell 中所有变量:set

[root@node-15 ~]# set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release'
COLUMNS=80

3.2 自定义变量

3.2.1 基本语法

(1)定义变量:变量名=变量值,注意,=号前后不能有空格
(2)撤销变量:unset 变量名
(3)声明静态变量:readonly 变量,注意:不能unset

3.2.2 变量定义规则

(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建
议大写。
(2)等号两侧不能有空格
(3)在bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。
(4)变量的值如果有空格,需要使用双引号或单引号括起来。

3.2.3 将命令返回值赋给变量

(1)A=`ls –l /root`反引号,运行里面的命令,并把结果返回给变量A

(2)A=$(ls –l /root)等价于反引号

[root@node-15 ~]# MY_DATE=$(date)
[root@node-15 ~]# echo "date=$MY_DATE"
date=2022年 08月 16日 星期二 17:42:39 CST
[root@node-15 ~]# RESULT=`ls -l /root`
[root@node-15 ~]# echo $RESULT
总用量 12 -rw-------. 1 root root 1728 5月 9 11:05 anaconda-ks.cfg -rwxr-xr-x 1 root root 30 8月 15 17:0   1 helloworld.sh -rwxr--r-- 1 root root 429 8月 16 16:13 shell.sh
[root@node-15 ~]#

3.2.4 案例实操

(1)定义变量A

[root@node-15 ~]# A=5
[root@node-15 ~]# echo $A
5

(2)给变量A 重新赋值

[root@node-15 ~]# A=8
[root@node-15 ~]# echo $A
8

(3)撤销变量A

[root@node-15 ~]# unset A
[root@node-15 ~]# echo $A

(4)声明静态的变量B=2,不能unset

[root@node-15 ~]# readonly B=2
[root@node-15 ~]# echo $B
2
[root@node-15 ~]# B=9
-bash: B: 只读变量
[root@node-15 ~]# unset B
-bash: unset: B: 无法反设定: 只读 variable

(5)在bash 中,变量默认类型都是字符串类型,无法直接进行数值运算

[root@node-15 ~]# C=1+2
[root@node-15 ~]# echo $C
1+2

(6)变量的值如果有空格,需要使用双引号或单引号括起来

[root@node-15 ~]# D=Hello World
-bash: World: 未找到命令
[root@node-15 ~]# D="Hello World"
[root@node-15 ~]# echo $D
Hello World

3.3 设置环境变量

3.3.1 基本语法

export 变量名=变量值 (功能描述:将shell变量输出为全局环境变量,可供其他shell程序使用)
source 配置文件  (功能描述:让修改后的配置信息立即生效)
echo $变量名  (功能描述:查询环境变量的值)

3.3.2 案例实操

1.在/etc/profile文件中定义TOMCAT_HOME环境变量

vim /etc/profile并在最下面写入以下内容

#定义一个自己的环境变量
TOMCAT_HOME=/opt/tomcat
export TOMCAT_HOME

2.查看环境变量的值

[root@node-15 ~]# vim /etc/profile
[root@node-15 ~]# echo $TOMCAT_HOME

[root@node-15 ~]# source /etc/profile
[root@node-15 ~]# echo $TOMCAT_HOME
/opt/tomcat
[root@node-15 ~]#

注意:为了使/etc/profile的环境变量生效,需要使用source /etc/profile重启系统或者注销 

3.在另一个shell程序中使用TOMCAT_HOME

[root@node-15 ~]# vim helloworld.sh
[root@node-15 ~]# cat helloworld.sh
#!/bin/bash
#echo "helloworld"

#使用自定义的环境变量
echo "tomcathome=$TOMCAT_HOME"
[root@node-15 ~]# sh ./helloworld.sh
tomcathome=/opt/tomcat
[root@node-15 ~]#
[root@node-15 ~]# vim shell.sh
[root@node-15 ~]# cat -n shell.sh
     1  #!/bin/bash
     2  echo "helloword"
     3
     4  #输出环境变量
     5  echo "PATH=$PATH"
     6  echo "user=$USER"
     7
     8  #自定义变量
     9  A=100
    10  echo "A=$A"
    11  #撤销一个变量
    12  unset A
    13  echo "A=$A"
    14
    15  #定义和使用静态变量
    16  readonly B=99
    17  echo "B=$B"
    18  #注意:静态变量不能unset
    19  unset B
    20  echo "B=$B"
    21
    22  A=19
    23  MYNUM=89
    24  echo "$A $MYNUM"
    25
    26  #两种将命令返回赋给变量的方法
    27  RESULT=`ls -l /root`
    28  echo $RESULT
    29  echo ""
    30  MY_DATE=$(date)
    31  echo "date=$MY_DATE"
    32
[root@node-15 ~]# sh shell.sh
helloword
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
user=root
A=100
A=
B=99
shell.sh: 第 19 行:unset: B: 无法反设定: 只读 variable
B=99
19 89
总用量 12 -rw-------. 1 root root 1728 5月 9 11:05 anaconda-ks.cfg -rwxr-xr-x 1                                                                     root root 30 8月 15 17:01 helloworld.sh -rwxr--r-- 1 root root 429 8月 16 16:13                                                                     shell.sh

date=2022年 08月 16日 星期二 16:14:17 CST
[root@node-15 ~]#

3.4 特殊变量(位置参数变量)

3.4.1 基本语法

$n (功能描述:n 为数字,$0 代表该脚本名称,$1-$9 代表第一到第九个参数,十以
上的参数,十以上的参数需要用大括号包含,如${10})

$# (功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及
加强脚本的健壮性)。

$* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
$@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)

3.4.2 案例实操

[root@node-15 ~]# vim parameter.sh
[root@node-15 ~]# cat parameter.sh
#!/bin/bash
echo '==========$n=========='
echo $0
echo $1
echo $2
echo '==========$#=========='
echo $#
echo '==========$*=========='
echo $*
echo '==========$@=========='
echo $@
[root@node-15 ~]# chmod 544 parameter.sh
[root@node-15 ~]# ./parameter.sh a b c d e f g
==========$n==========
./parameter.sh
a
b
==========$#==========
7
==========$*==========
a b c d e f g
==========$@==========
a b c d e f g

3.5 预定义变量

3.5.1 基本介绍

预定义变量是shell设计者事先已经定义好的变量,可以直接在shell脚本中使用

3.5.2 基本语法

$$  (功能描述:当前进程的进程号(PID))
$!   (功能描述:后台运行的最后一个进程的进程号)
$? (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一
个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明
上一个命令执行不正确了。)

3.5.3 案例实操

[root@node-15 ~]# vim preVar.sh
[root@node-15 ~]# cat preVar.sh
#!/bin/bash
echo "当前的进程号=$$"
#后台的方式运行helloworld.sh
./helloworld.sh &
echo "最后的进程号=$!"
echo "执行的值=$?"

[root@node-15 ~]# chmod 744 preVar.sh
[root@node-15 ~]# ./preVar.sh
当前的进程号=15949
最后的进程号=15950
执行的值=0
[root@node-15 ~]# tomcathome=/opt/tomcat
^C

 

第4 章 运算符

4.1 基本语法

“$((运算式))” 或“$[运算式]”
expr m + n 注意expr运算符间要有空格
expr m – n
expr \*,/,% 乘,除,取余

4.2 案例实操

案例一:计算(2+3)* 4 的值
案例二:求出命令行的两个参数[整数]的和

[root@node-15 ~]# cat demo.sh
#!/bin/bash

#案例一
#第一种方式$()
RESULT1=$(((2+3)*4))
echo "result1=$RESULT1"

#第二种方式$[]
RESULT2=$[(2+3)*4]
echo "result2=$RESULT2"

#第三种方式expr
TEMP=`expr 2 + 3`
RESULT3=`expr $TEMP \* 4`
echo "result3=$RESULT3"


#案例二:求出两个参数的和
SUM=$[$1+$2]
echo "SUM=$SUM"


[root@node-15 ~]# chmod 744 demo.sh
[root@node-15 ~]# ./demo.sh 10 8
result1=20
result2=20
result3=20
SUM=18

 

第5章 条件判断

5.1 基本语法

(1)test condition
(2)[ condition ](注意condition 前后要有空格)
注意:条件非空即为true,[ condition ]返回true,[ ] 返回false。

5.2 常用判断条件

(1)两个整数之间比较
-eq 等于(equal) -ne 不等于(not equal)
-lt 小于(less than) -le 小于等于(less equal)
-gt 大于(greater than) -ge 大于等于(greater equal)
注:如果是字符串之间的比较,用等号“=”判断相等;用“!=”判断不等。
(2)按照文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
(3)按照文件类型进行判断
-e 文件存在(existence)
-f 文件存在并且是一个常规的文件(file)
-d 文件存在并且是一个目录(directory)

5.3 案例实操

(1)ok是否等于ok
(2)23 是否大于等于22
(3)helloworld.sh 是否具有写权限
(4)/root/aaa.txt 目录中的文件是否存在

[root@node-15 ~]# vim judge.sh
[root@node-15 ~]# cat judge.sh
#!/bin/bash

#案例1:“OK”是否等于“OK”
if [ "ok" = "ok" ]
then
        echo "equal"
fi

#案例2:23 是否大于等于22
if [ 23 -ge 22 ]
then
        echo "大于等于"
fi

#案例3:helloworld.sh 是否具有写权限
if [ -w helloworld.sh ]
then
        echo "有"
fi

#案例4:/root/aaa.txt 目录文件是否存在
if [ -e /root/aaa.txt ]
then
        echo "存在"
fi

[root@node-15 ~]# touch aaa.txt
[root@node-15 ~]# chmod 744 judge.sh
[root@node-15 ~]# ./judge.sh
equal
大于等于
有
存在
[root@node-15 ~]#

5.4 多条件判断

(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)

[root@node-15 ~]# [ 2 -lt 5 ] && echo OK || echo notOK
OK
[root@node-15 ~]# [  ] && echo OK || echo notOK
notOK

 

第6章 流程控制(重点)

6.1 if 判断

6.1.1 基本语法

(1)单分支

if [ 条件判断式];then
        程序

fi

或者

if [ 条件判断式]
then
        程序

fi

(2)多分支

if [ 条件判断式]
then
        程序

elif [ 条件判断式]
then
        程序

else        程序
fi

注意事项:
①[ 条件判断式],中括号和条件判断式之间必须有空格
②if 后要有空格

6.1.2 案例实操

编写shell程序,如果输入的参数,大于等于60,则输出“及格”,如果小于60,则输出“不及格”

[root@node-15 ~]# vim testIf.sh
[root@node-15 ~]# cat testIf.sh
#!/bin/bash

#编写shell程序,如果输入的参数,大于等于60,则输出“及格”,如果小于60,则输出“不及格”

if [ $1 -ge 60 ]
then
        echo "及格"
elif [ $1 -lt 60 ]
then
        echo "不及格"
fi

[root@node-15 ~]# chmod 744 testIf.sh
[root@node-15 ~]# ./testIf.sh 60
及格
[root@node-15 ~]# ./testIf.sh 59
不及格

6.2 case 语句

6.2.1 基本语法

case $变量名 in
"值1")
        如果变量的值等于值1,则执行程序1
;;
"值2")
        如果变量的值等于值2,则执行程序2
;;
        …省略其他分支…
*)
        如果变量的值都不是以上的值,则执行此程序
;;

esac

注意事项:
(1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
(2)双分号“;;”表示命令序列结束,相当于java 中的break。
(3)最后的“*)”表示默认模式,相当于java 中的default。

6.2.2 案例实操

编写shell程序,当命令行参数是1时,输出“周一”,是2时,输出“周二”,其他情况输出”other”

[root@node-15 ~]# vim testCase.sh
[root@node-15 ~]# cat testCase.sh
#!/bin/bash

#编写shell程序,当命令行参数是1时,输出“周一”,是2时,输出“周二”,其他情况输出”other”
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "other"
;;
esac
[root@node-15 ~]# chmod 744 testCase.sh
[root@node-15 ~]# ./testCase.sh 1
周一
[root@node-15 ~]# ./testCase.sh 2
周二
[root@node-15 ~]# ./testCase.sh 3
other

6.3 for 循环

6.3.1 基本语法1

for 变量in 值1 值2 值3…
do
        程序
done

6.3.2 案例实操

打印所有输入参数(这里可以看出$*和$@的区别)

[root@node-15 ~]# vim testFor1.sh
[root@node-15 ~]# cat testFor1.sh
#!/bin/bash

#打印命令行输入的参数
echo '====================被双引号包含======================='
echo '==========="$*"============='
#使用$*
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个for 循环只会循环一次
do
        echo "The num is $i"
done

echo '==========="$@"============='
#使用$@
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
        echo "The num is $j"
done



echo '====================不被双引号包含======================='
echo '===========$*============='
#使用$*
for i in $*
do
        echo "The num is $i"
done

echo '===========$@============='
#使用$@
for j in $@
do
        echo "The num is $j"
done
[root@node-15 ~]# chmod 744 testFor1.sh
[root@node-15 ~]# ./testFor1.sh 10 20 30
====================被双引号包含=======================
==========="$*"=============
The num is 10 20 30
==========="$@"=============
The num is 10
The num is 20
The num is 30
====================不被双引号包含=======================
===========$*=============
The num is 10
The num is 20
The num is 30
===========$@=============
The num is 10
The num is 20
The num is 30
[root@node-15 ~]#

6.3.3 比较$*和$@区别

$*和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n的形式输出所有参数。

当它们被双引号“”包含时,$*会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输出所有参数;$@会将各个参数分开,以“$1” “$2”…“$n”的形式输出所有参数。 

6.3.4 基本语法2

for (( 初始值;循环控制条件;变量变化))
do
        程序
done 

6.3.5 案例实操

从1 加到100的值输出显示

[root@node-15 ~]# vim testFor2.sh
[root@node-15 ~]# cat testFor2.sh
#!/bin/bash

#从1 加到100的值输出显示
SUM=0
for((i=0;i<=100;i++))
do
SUM=$[$SUM+$i]
done
echo "sum=$SUM"


[root@node-15 ~]# chmod 744 testFor2.sh
[root@node-15 ~]# ./testFor2.sh
sum=5050

6.4 while 循环

6.4.1 基本语法

while [ 条件判断式]
do
        程序
done

6.4.2 案例实操

案例一:从1 加到100的值输出显示

[root@node-15 ~]# vim testWhile1.sh
[root@node-15 ~]# cat testWhile1.sh
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
    sum=$[$sum+$i]
    i=$[$i+1]
done
echo $sum


[root@node-15 ~]# chmod 744 testWhile1.sh
[root@node-15 ~]# ./testWhile1.sh
5050

 

案例二:从命令行输入一个数n,统计从1+...+n的值

[root@node-15 ~]# vim testWhile2.sh
[root@node-15 ~]# cat testWhile2.sh
#!/bin/bash

#案例二:从命令行输入一个数n,统计从1+...+n的值
SUM=0
i=0
while [ $i -le $1 ]
do
        SUM=$[$SUM+$i]
        i=$[$i+1]
done
echo "sum=$SUM"

[root@node-15 ~]# chmod 744 testWhile2.sh
[root@node-15 ~]# ./testWhile2.sh 10
sum=55

 

第7章 read 读取控制台输入

7.1 基本语法

read (选项) (参数)
①选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒),如果没有在指定的时间内输入,就不再等待了,如果-t 不加表示一直等待
②参数
变量:指定读取值的变量名

7.2 案例实操

案例一:读取控制台输入一个num值
案例二:读取控制台输入一个num值,在10秒内输入

[root@node-15 ~]# vim testRead.sh
[root@node-15 ~]# cat testRead.sh
#!/bin/bash

#案例一:读取控制台输入一个num值

read -p "请输入一个数num1=" NUM1
echo "你输入的值是num1=$NUM1"

#案例二:读取控制台输入一个num值,在10秒内输入

read -t 10 -p "请10秒内输入一个数num2=" NUM2
echo "你输入的值是num2=$NUM2"
[root@node-15 ~]# chmod 744 testRead.sh
[root@node-15 ~]# ./testRead.sh
请输入一个数num1=123
你输入的值是num1=123
请10秒内输入一个数num2=456
你输入的值是num2=456

 

第8章 函数

8.1 系统函数

8.1.1 basename

1)基本语法

basename [string / pathname] [suffix] (功能描述:basename 命令会删掉所有的前
缀包括最后一个(‘/’)字符,然后将字符串显示出来。
basename 可以理解为取路径里的文件名称
选项:
suffix 为后缀,如果suffix 被指定了,basename 会将pathname 或string 中的suffix 去掉。

功能:返回完整路径最后/的部分,常用于获取文件名
2)案例实操

截取该/home/aaa/test.txt 路径的文件名称。

[root@node-15 ~]# basename /home/aaa/test.txt
test.txt
[root@node-15 ~]# basename /home/aaa/test.txt .txt
test

8.1.2 dirname

1)基本语法
dirname 文件绝对路径(功能描述:从给定的包含绝对路径的文件名中去除文件名
(非目录的部分),然后返回剩下的路径(目录的部分))
dirname 可以理解为取文件路径的绝对路径名称

功能:返回完整路径最后/的前面部分,常用于返回路径部分
2)案例实操
获取/home/aaa/test.txt 文件的路径。

[root@node-15 ~]# dirname /home/aaa/test.txt
/home/aaa

8.2 自定义函数

8.2.1基本语法

[ function ] funname[()]
{
        Action;
        [return int;]
}


调用直接写函数名:funname

8.2.2经验技巧

(1)必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其它语言一
样先编译。
(2)函数返回值,只能通过$?系统变量获得,可以显示加:return 返回,如果不加,将
以最后一条命令运行结果,作为返回值。return 后跟数值n(0-255)

8.2.3案例实操

计算两个输入参数的和

[root@node-15 ~]# vim testFun.sh
[root@node-15 ~]# cat testFun.sh
#!/bin/bash

#计算两个输入参数的和

function getSum()
{
        SUM=$[$n1+$n2]
        echo "和是$SUM"
}
read -p "请输入第一个数n1=: " n1
read -p "请输入第二个数n2=: " n2

#调用getSum
getSum $n1 $n2
[root@node-15 ~]# chmod 744 testFun.sh
[root@node-15 ~]# ./testFun.sh
请输入第一个数n1=: 80
请输入第二个数n2=: 20
和是100

 

第9章 正则表达式入门

正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。在 Linux 中,grep,sed,awk 等文本处理工具都支持通过正则表达式进行模式匹配。

9.1 常规匹配

一串不包含特殊字符的正则表达式匹配它自己,例如:

[root@node-15 ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@node-15 ~]#

 就会匹配所有包含 root 的行。

9.2 常用特殊字符

9.2.1 特殊字符:^

^ 匹配一行的开头,例如:

[root@node-15 ~]# cat /etc/passwd | grep ^a
adm:x:3:4:adm:/var/adm:/sbin/nologin
admin:x:1000:1000:admin:/home/admin:/bin/bash
[root@node-15 ~]#

会匹配出所有以 a 开头的行

9.2.2 特殊字符:$


$ 匹配一行的结束,例如

[root@node-15 ~]# cat /etc/passwd | grep t$
halt:x:7:0:halt:/sbin:/sbin/halt
[root@node-15 ~]#

会匹配出所有以 t 结尾的行

注意:^$ 匹配空行

[root@node-15 ~]# cat daily_archive.sh | grep -n ^$
2:
9:
18:
21:
24:
28:
32:
34:
46:
[root@node-15 ~]#


9.2.3 特殊字符:.

. 匹配一个任意的字符,例如

[root@node-15 ~]# cat /etc/passwd | grep r..t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@node-15 ~]#

会匹配包含 rabt,rbbt,rxdt,root 等的所有行

9.2.4 特殊字符:*

* 不单独使用,他和上一个字符连用,表示匹配上一个字符 0 次或多次,例如

[root@node-15 ~]# cat /etc/passwd | grep ro*t
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@node-15 ~]#

会匹配 rt, rot, root, rooot, roooot 等所有行
注意:.* 匹配任意字符出现任意多次,或什么都不出现

9.2.5 字符区间(中括号):[ ]

[ ] 表示匹配某个范围内的一个字符,例如
[6,8]------匹配 6 或者 8
[0-9]------匹配一个 0-9 的数字
[0-9]*------匹配任意长度的数字字符串
[a-z]------匹配一个 a-z 之间的字符
[a-z]* ------匹配任意长度的字母字符串
[a-c, e-f]-匹配 a-c 或者 e-f 之间的任意字符

[root@node-15 ~]# cat /etc/passwd | grep r[a,b,c]*t
operator:x:11:0:operator:/root:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
[root@node-15 ~]#

会匹配 rt,rat, rbt, rabt, rbact,rabccbaaacbt 等等所有行

9.2.6 特殊字符:\

\ 表示转义,并不会单独使用。由于所有特殊字符都有其特定匹配模式,当我们想匹配
某一特殊字符本身时(例如,我想找出所有包含 '$' 的行),就会碰到困难。此时我们就要
将转义字符和特殊字符连用,来表示特殊字符本身,例如

[root@node-15 ~]# cat /etc/passwd | grep ‘a\$b’

就会匹配所有包含 a$b 的行,注意需要使用单引号将表达式引起来。

 

第10章 文本处理工具

10.1 cut

cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut 命令从文件的每
一行剪切字节、字符和字段并将这些字节、字符和字段输出。

10.1.1 基本用法

cut [选项参数] filename
说明:默认分隔符是制表符

10.1.2 选项参数说明

-f       列号,提取第几列
-d      分隔符,按照指定分隔符分割列,默认是制表符“\t”
-c      按字符进行切割 后加加 n 表示取第几列 比如 -c 1

10.1.3 案例实操

(1)数据准备

[root@node-15 ~]# vim cut.txt
[root@node-15 ~]# cat cut.txt
dong shen
guan zhen
wo wo
lai lai
le le

(2)切割 cut.txt 第一列
 

[root@node-15 ~]# cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
[root@node-15 ~]#

(3)切割 cut.txt 第二、三列

[root@node-15 ~]# cut -d " " -f 2,3 cut.txt
shen
zhen
wo
lai
le

(4)在 cut.txt 文件中切割出 guan

[root@node-15 ~]# cat cut.txt |grep guan | cut -d " " -f 1
guan
[root@node-15 ~]#

(5)选取系统 PATH 变量值,第 2 个“:”开始后的所有路径:

[root@node-15 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@node-15 ~]# echo $PATH | cut -d ":" -f 3-
/usr/sbin:/usr/bin:/root/bin
[root@node-15 ~]#

(6)切割 ifconfig 后打印的 IP 地址

[root@node-15 ~]# ifconfig ens33 | grep netmask | cut -d " " -f 10
192.168.111.101


10.2 awk

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开
的部分再进行分析处理。

10.2.1 基本用法

awk [选项参数] ‘/pattern1/{action1} /pattern2/{action2}...’ filename
pattern:表示 awk 在数据中查找的内容,就是匹配模式
action:在找到匹配内容时所执行的一系列命令

10.2.2 选项参数说明

-F       指定输入文件分隔符
-v        赋值一个用户定义变量

10.2.3 案例实操

(1)数据准备

[root@node-15 ~]# cp /etc/passwd ./passwd

passwd 数据的含义
用户名:密码(加密过后的):用户 id:组 id:注释:用户家目录:shell 解析器
(2)搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第 7 列。

[root@node-15 ~]# awk -F : '/^root/{print $7}' passwd
/bin/bash

(3)搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第 1 列和第 7 列,
中间以“,”号分割。

[root@node-15 ~]# awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash
[root@node-15 ~]#

注意:只有匹配了 pattern 的行才会执行 action。


(4)只显示/etc/passwd 的第一列和第七列,以逗号分割,且在所有行前面添加列名 user,
shell 在最后一行添加"dahaige,/bin/zuishuai"。

[root@node-15 ~]# awk -F : 'BEGIN{print "user, shell"} {print $1","$7} END{print "dahaige,/bin/zuishuai"}' passwd
user, shell
root,/bin/bash
bin,/sbin/nologin
daemon,/sbin/nologin
adm,/sbin/nologin
lp,/sbin/nologin
sync,/bin/sync
shutdown,/sbin/shutdown
halt,/sbin/halt
mail,/sbin/nologin
operator,/sbin/nologin
games,/sbin/nologin
ftp,/sbin/nologin
nobody,/sbin/nologin
systemd-network,/sbin/nologin
dbus,/sbin/nologin
polkitd,/sbin/nologin
sshd,/sbin/nologin
postfix,/sbin/nologin
chrony,/sbin/nologin
admin,/bin/bash
dahaige,/bin/zuishuai
[root@node-15 ~]#

注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。


(5)将 passwd 文件中的用户 id 增加数值 1 并输出

[root@node-15 ~]# awk -v i=1 -F : '{print $3+i}' passwd
1
2
3
4
5
12
13
15
82
1000
75
90
999
1001
[root@node-15 ~]#

10.2.4 awk 的内置变量

FILENAME       文件名
NR                    已读的记录数(行号)
NF                     浏览记录的域的个数(切割后,列的个数)

10.2.5 案例实操

(1)统计 passwd 文件名,每行的行号,每行的列数

[root@node-15 ~]# awk -F : '{print "filename:" FILENAME ",linenum:"NR ",col:"NF}' passwd
filename:passwd,linenum:1,col:7
filename:passwd,linenum:2,col:7
filename:passwd,linenum:3,col:7
filename:passwd,linenum:4,col:7
filename:passwd,linenum:5,col:7
filename:passwd,linenum:6,col:7
filename:passwd,linenum:7,col:7
filename:passwd,linenum:8,col:7
filename:passwd,linenum:9,col:7
filename:passwd,linenum:10,col:7
filename:passwd,linenum:11,col:7
filename:passwd,linenum:12,col:7
filename:passwd,linenum:13,col:7
filename:passwd,linenum:14,col:7
filename:passwd,linenum:15,col:7
filename:passwd,linenum:16,col:7
filename:passwd,linenum:17,col:7
filename:passwd,linenum:18,col:7
filename:passwd,linenum:19,col:7
filename:passwd,linenum:20,col:7
[root@node-15 ~]#

(2)查询 ifconfig 命令输出结果中的空行所在的行号

[root@node-15 ~]# ifconfig | awk '/^$/{print NR}'
9
18
26

(3)切割 IP

[root@node-15 ~]# ifconfig ens33 | awk '/netmask/ {print $2}'
192.168.6.101

 

第11 章综合应用案例

11.1 归档文件

实际生产应用中,往往需要对重要数据进行归档备份。
需求:实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/),
将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/root/archive 下。
这里用到了归档命令:tar
后面可以加上-c 选项表示归档,加上-z 选项表示同时进行压缩,得到的文件后缀名
为.tar.gz。

11.1.1 建立脚本实现归档操作

[root@node-15 ~]# vim daily_archive.sh
[root@node-15 ~]# cat daily_archive.sh
#!/bin/bash

# 首先判断输入参数个数是否为1
if [ $# -ne 1 ]
then
        echo "参数个数错误!应该输入一个参数,作为归档目录名"
        exit
fi

# 从参数中获取目录名称
if [ -d $1 ]
then
        echo
else
        echo "目录不存在!"
        exit
fi

DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)

# 获取当前日期
DATE=$(date +%y%m%d)

# 定义生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE

# 开始归档目录文件
echo "开始归档..."
echo

tar -czf $DEST $DIR_PATH/$DIR_NAME

if [ $? -eq 0 ]
then
        echo
        echo "归档成功!"
        echo "归档文件为:$DEST"
        echo
else
        echo "归档出现问题!"
        echo
fi
exit


[root@node-15 ~]# mkdir /root/archive
[root@node-15 ~]# chmod u+x daily_archive.sh
[root@node-15 ~]# ./daily_archive.sh /root/archive

开始归档...

tar: 从成员名中删除开头的“/”

归档成功!
归档文件为:/root/archive/archive_archive_220818.tar.gz

11.1.2 加入定时任务实现每日自动归档

 设置每日凌晨两点自动归档

[root@node-15 ~]# crontab -l
no crontab for root
[root@node-15 ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@node-15 ~]# crontab -l
0 2 * * * /root/daily_archive.sh /root/scripts
[root@node-15 ~]#

11.2 发送消息

利用Linux 自带的mesg 和write 工具,向其它用户发送消息。
需求:实现一个向某个用户快速发送消息的脚本,输入用户名作为第一个参数,后面直
接跟要发送的消息。脚本需要检测用户是否登录在系统中、是否打开消息功能,以及当前发
送消息是否为空。

11.2.1 非脚本实现

显示当前在线者并查看是否开启消息功能(这里登录了两个用户,分别是root与admin)

root端

[root@node-15 ~]# mesg
is y
[root@node-15 ~]# who -T
root     + pts/0        2022-08-16 08:21 (10.199.28.219)
[root@node-15 ~]# who -T
root     + pts/0        2022-08-16 08:21 (10.199.28.219)
admin    + pts/1        2022-08-18 08:54 (10.199.28.219)
[root@node-15 ~]# write admin pts/1
hi,admin,i am root
How are you
^C[root@node-15 ~]#

admin端


Last login: Fri Jul 29 13:44:02 2022 from 10.199.28.219
[admin@node-15 ~]$ who
root     pts/0        2022-08-16 08:21 (10.199.28.219)
admin    pts/1        2022-08-18 08:54 (10.199.28.219)
[admin@node-15 ~]$
Message from root@node-15 on pts/0 at 08:57 ...
hi,admin,i am root
How are you
EOF
^C
[admin@node-15 ~]$ who am i
admin    pts/1        2022-08-18 08:54 (10.199.28.219)
[admin@node-15 ~]$

11.2.2 脚本实现

1.建立脚本实现发送消息操作

^C[root@node-15 ~]# vim send_mesg.sh
[root@node-15 ~]# cat send_mesg.sh
#!/bin/bash

#查看用户是否登录  -i忽略大小写 -m匹配前几行
login_user=$(who | grep -i -m 1 $1 | awk '{print $1}')

if [ -z $login_user ]
then
        echo "$1 不在线!"
        echo "脚本退出.."
        exit
fi

#查看用户是否开启消息功能
is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}')

if [ $is_allowed != "+" ]
then
        echo "$1 没有开启消息功能"
        echo "脚本退出.."
        exit
fi

#确认是否有消息发送
if [ -z $2 ]
then
        echo "没有消息发出"
        echo "脚本退出.."
        exit
fi

#从消息中获取要发送的消息
whole_msg=$(echo $* | cut -d " " -f 2- )

#获取用户登录的终端
user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')

#写入要发送的消息
echo $whole_msg | write $login_user $user_terminal

#判断是否发送成功
if [ $? != 0 ]
then
        echo "发送失败!"
else
        echo "发送成功!"
fi

exit


2.检验脚本功能实现

root端

[root@node-15 ~]# chmod u+x send_mesg.sh
[root@node-15 ~]# ./send_mesg.sh
用法: grep [选项]... PATTERN [FILE]...
试用‘grep --help’来获得更多信息。
 不在线!
脚本退出..
[root@node-15 ~]# ./send_mesg.sh xiaoming
xiaoming 不在线!
脚本退出..
[root@node-15 ~]# ./send_mesg.sh admin
没有消息发出
脚本退出..
[root@node-15 ~]# ./send_mesg.sh admin hi,admin
发送成功!
[root@node-15 ~]# ./send_mesg.sh admin boss is coming
发送成功!

admin端

[admin@node-15 ~]$ who am i
admin    pts/1        2022-08-18 08:54 (10.199.28.219)
[admin@node-15 ~]$
Message from root@node-15 on pts/0 at 09:31 ...
hi,admin
EOF

Message from root@node-15 on pts/0 at 09:32 ...
boss is coming
EOF
^C
[admin@node-15 ~]$

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值