# Shell 编程

# 正则表达式

# 正则表达式与通配符

  • 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed 等命令可以支持正则表达式。
  • 通配符用来匹配符合条件的文件名,通配符是完全匹配。ls、find、cp 这些命令不支持正则表达式,所以只能使用 shell 自己的通配符来进行匹配了。

# 基础正则表达式

image-20220903153944488

"*" 表示前一个字符匹配 0 次,或任意多次

[root@localhost ~]# grep "a*" test_rule.txt	# 匹配所有内容,包括空白行
[root@localhost ~]# grep "aa*" test_rule.txt    # 匹配最少包含有一个 a 的行
[root@localhost ~]# grep "aaa*" test_rule.txt    # 匹配最少包含两个连续 a 的字符串
[root@localhost ~]# grep "aaaaa*" test_rule.txt    # 则会匹配最少包含四个连续 a 的字符串

"." 匹配除了换行符外任意一个字符

[root@localhost ~]# grep "s..d" test_rule.txt    # 匹配在 s 和 d 这两个字母之间一定有两个字符的单词
[root@localhost ~]# grep "s.*d" test_rule.txt    # 匹配在 s 和 d 字母之间有任意字符
[root@localhost ~]# grep ".*" test_rule.txt    # 匹配所有内容

"^" 匹配行首,"$" 匹配行尾

[root@localhost ~]# grep "^M" test_rule.txt    # 匹配以大写 “M” 开头的行
[root@localhost ~]# grep "n$" test_rule.txt    # 匹配以小写 “n” 结尾的行
[root@localhost ~]# grep -n "^$" test_rule.txt    # 会匹配空白行

"[]" 匹配中括号中指定的任意一个字符,只匹配一个字符

[root@localhost ~]# grep "s [ao] id" test_rule.txt    # 匹配 s 和 i 字母中,要不是 a、要不是 o
[root@localhost ~]# grep "[0-9]" test_rule.txt    # 匹配任意一个数字
[root@localhost ~]# grep "^[a-z]" test_rule.txt    # 匹配用小写字母开头的行

"[^]" 匹配除中括号的字符以外的任意一个字符

[root@localhost ~]# grep "^[^a-z]" test_rule.txt    # 匹配不用小写字母开头的行
[root@localhost ~]# grep "^[^a-zA-Z]" test_rule.txt    # 匹配不用字母开头的行

"\" 转义符

[root@localhost ~]# grep "\.$" test_rule.txt    # 匹配使用 "." 结尾的行

# 字符截取命令

# cut 字段提取命令

[root@localhost ~]# cut [选项] 文件名

选项:

​ -f 列号: 提取第几列

​ -d 分隔符: 按照指定分隔符分隔列

默认以制表符作为分隔符。

# printf 命令

[root@localhost ~]# printf '输出类型输出格式' 输出内容

输出类型:

​ % ns: 输出字符串,n 是数字指代输出几个字符

​ % ni: 输出整数,n 是数字指代输出几个数字

​ %m.nf: 输出浮点数,m 和 n 是数字,指代输出的整数位数和小数位数。如 %8.2f 代表共输出 8 位数,其中 2 位是小数,6 位是整数。

输出格式:

​ \a: 输出警告声音

​ \b: 输出退格键,也就是 Backspace 键

​ \f: 清除屏幕

​ \n: 换行

​ \r: 回车,也就是 Enter 键

​ \t: 水平输出退格键,也就是 Tab 键

​ \v: 垂直输出退格键,也就是 Tab 键

[root@localhost ~]# printf '%s %s %s\n' 1 2 3 4 5 6

[root@localhost ~]# printf '%s' $(cat student.txt)

在 awk 命令的输出中支持 print 和 printf 命令

  • print:print 会在每个输出之后自动加入一个换行符(Linux 默认没有 print 命令)
  • printf:printf 是标准格式输出命令,并不会自动加入换行符,如果需要换行,需要手工加入换行符

# awk 命令

[root@localhost ~]# awk '条件1{动作1} 条件2{动作2}...' 文件名

条件(pattern):

​ 一般使用关系表达式作为条件:

​ x>10 判断变量 x 是否大于 10

​ x>=10 大于等于

​ x<=10 小于等于

动作(Action):

​ 格式化输出

​ 流程控制语句

[root@localhost ~]# df -h | awk '{printf $1 "\t" $5 "\t" $6 "\n"}'

BEGIN

[root@localhost ~]# awk 'BEGIN{printf "This is a transcript \n"} {printf \$2 "\t" \$6 "\n"}' student.txt

读取文本之前执行动作

FS 内置变量

[root@localhost ~]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf \$1 "\t" \$3 "\n"}'

指定文本的分隔符

END

[root@localhost ~]# awk 'END{printf "The End\n"} {printf \$2 "\t" \$6 "\n"}' stuent.txt

在所有数据处理完之后再执行的动作

关系运算符

[root@localhost ~]# cat student.txt | grep -v Name | awk '$6>=87 {printf $2 "\n"}'

# sed 命令

sed 是一种几乎包括在所有 UNIX 平台(包括 Linux)的轻量级流编辑器。sed 主要是用来将数据进行选取、替换、删除、新增的命令。

[root@localhost ~]# sed [选项] '[动作]' 文件名

选项:

​ -n: 一般 sed 命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过 sed 命令处理的行输出到屏幕。

​ -e: 允许对输入数据应用多条 sed 命令编辑

​ -i: 用 sed 的修改结果直接修改读取数据的文件,而不是由屏幕输出

动作:

​ a: 追加,再当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用 "\" 代表数据未完结。

​ c: 行替换,用 c 后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用 "\" 代表数据未完结。

​ i: 插入,在当期行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用 "\" 代表数据未完结。

​ d: 删除,删除指定的行。

​ p: 打印,输出指定的行。

​ s: 字串替换,用一个字符串替换另一个字符串。格式为 “行范围 s / 旧字串 / 新字串 /g”(和 vim 中的替换格式类似)。

# 字符处理命令

# 排序命令 sort

[root@localhost ~]# sort [选项] 文件名

选项:

​ -f: 忽略大小写

​ -n: 以数值型进行排序,默认使用字符串型排序

​ -r: 反向排序

​ -t: 指定分隔符,默认是分隔符是制表符

​ -k n [,m]: 按照指定的字段范围排序。从第 n 字段开始,m 字段结束(默认到行尾)

[root@localhost ~]# sort -t ":" -k 3,3 /etc/passwd

#指定分隔符是 ":",用第三字段开头,第三字段结尾排序,就是只用第三字段排序。

# 统计命令 wc

[root@localhost ~]# wc [选项] 文件名

选项:

​ -l: 只统计行数

​ -w: 只统计单词书

​ -m: 只统计字符数

# 条件判断

# 按照文件类型进行判断

image-20220903221455746

两种判断格式

  • [root@localhost ~]# test -e /root/install.log

  • [root@localhost ~]# [ -e /root/install.log ]

# 按照文件权限进行判断

image-20220903222238843

# 两个文件之间进行比较

image-20220903222434892

# 两个整数之间进行比较

image-20220903222802700

# 字符串的判断

image-20220903223208059

# 多重条件判断

image-20220903223551506

# 流程控制

# if 语句

单分支 if 条件语句

if [ 条件判断式 ];then
	程序
fi
#或者
if [条件判断式]
	then
		程序
fi

单分支条件语句需要注意几个点:

  • if 语句使用 fi 结尾,和一般语言使用大括号结尾不同
  • [条件判断式] 就是使用 test 命令判断,所以中括号和条件判断式之间必须由空格
  • then 后面跟符合条件之后执行的程序,可以放在 [] 之后,用 ";" 分隔。也可以换行写入,就不需要 ";" 了

双分支 if 条件语句

if [ 条件判断式 ]
	then
		条件成立时,执行的程序
	else
		条件不成立时,执行的另一个程序
fi

多分支 if 条件语句

if [ 条件判断式1 ]
	then
		当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]
	then
		当条件判断式2成立时,执行程序2
#... 省略更多条件...
else
	当所有条件都不成立时,最后执行此程序
fi

# case 语句

多分支 case 条件语句

case 语句和 if...elif...else 语句一样都是多分支条件语句,不过和 if 多分支条件语句不同的是,case 语句只能判断一种条件关系,而 if 语句可以判断多种条件关系。

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

# for 循环

语法 1

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

语法 2

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

# while 循环与 until 循环

while 循环

while 循环是不定循环,也称作条件循环。只要条件判定式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和 for 的固定循环不太一样了。

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

until 循环

until 循环,和 while 循环相反,until 循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

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