文章目录
while 循环和 until 循环
while 循环语句
基本语法为:
bash
while <条件表达式>
do
指令...
done
如果该条件表达式成立,则执行while 循环体里的命令或语句(即语法中do和done之间的指令),每一次执行到done时就会重新判断while条件表达式是否成立,直到条件表达式不成立时才会跳出while 循环体。
示例:
1,初始资金1000,赚到10000000后躺平
bash
#!/bin/bash
target=10000000
money=1000
while ((money<=target))
do
echo -n "I'm working hard...Total:"
sleep 0.5
money=$[ money +1000000 ]
echo $money
done
2,猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第 10 天早上想再吃时,发现只剩下一个桃子了。问原来有多少个桃子?
for循环语句示例:
bash
#!/bin/bash
sum=1
for ((num=1;num<=9;num++))
do
#let sum+=num
sum=$[ (sum + 1)*2 ]
done
echo $sum
while循环语句示例:
bash
#!/bin/bash
num=1
day=10
while ((day>1))
do
num=$(((num+1)*2))
day=$((day-1))
done
echo "原来桃子数量:$num"
3,每隔3秒监控一次sshd服务,如果sshd服务未运行,则启动服务。
bash
#!/bin/bash
while ((1==1))
do
if ! systemctl is-active sshd &>/dev/null;then
systemctl start sshd && echo "$date Start sshd ..success"
fi
sleep 3
done
4,开发脚本:
- 随机产生一个50以内正整数,存放到/tmp/guess_number
- 提示用户输入一个50以内正整数
- 如果用户猜的数字大了,则提示用户猜大了,继续加油。继续提示用户输入一个50以内正整数。
- 如果用户猜的数字小了,则提示用户猜小了,继续加油。继续提示用户输入一个50以内正整数。
- 如果用户猜中数字,则提示用户:你好棒!退出脚本。
- 提示共计猜的次数。
bash
#!/bin/bash
guess_result_file=/tmp/guess_number
# 生成一个小于50的正整数
num_real=$[ RANDOM%50+1 ]
echo $num_real > ${guess_result_file}
# 定义猜测次数变量
count=0
while true
do
read -p "请输入一个50以内正整数:" num
# 随着猜测次数增加
let count++
if (($num>50 || $num<1));then
echo "错误"
elif (($num==$num_real));then
echo "第 $count 次猜测,你好棒!正确答案是 $num_real"
exit
elif (($num > $num_real));then
echo "第 $count 次猜测:猜大了,继续加油"
elif (($num < $num_real));then
echo "第 $count 次猜测:猜小了,继续加油"
fi
done
until 循环
基本语法
bash
until <条件表达式>
do
指令...
done
until 循环语句的用法与while 循环语句的用法类似,区别是until会在条件表达式不成立时,进入循环 执行指令;条件表达式成立时,终止循环。
示例:
1,初始资金1000,赚到10000000后躺平
bash
#!/bin/bash
target=10000000
money=1000
until ((money>=target))
do
echo -n "I'm working hard...Total:"
sleep 0.5
money=$[ money +1000000 ]
echo $money
done
shell脚本例题
1,开发脚本cpu_load.sh:消耗完系统所有cpu资源。
bash
#!/bin/bash
cpu_count=$(lscpu |grep '^CPU(s):' | grep -o '[0-9]')
# 定义一个消耗系统所有cpu资源函数
function cpu_load (){
sum=0
while true
do
sum=$((1+1))
done
}
# 产生和cpu数相同个数的进程
for ((num=1;num<=cpu_count;num++))
do
cpu_load &
done
2,当进程被kill后再次生成
bash
#!/bin/bash
cpu_count=$(lscpu |grep '^CPU(s):' | grep -o '[0-9]')
md5sum /dev/zero &
while true
do
current_load=$(ps axo command,%cpu --sort -%cpu --no-header |grep -c md5sum)
if ((current_load<cpu_count));then
md5sum /dev/zero &
fi
sleep 1
done
shell三剑客
正则表达式
- 正则表达式作为一个 pattern ,将 pattern 与要搜索的字符串进行匹配,以便查找一个或多个字符串。
- 正则表达式,自成体系,由普通字符(例如字符 a 到 z)和元字符组成的文字模式。
- 普通字符:没有显式指定为元字符的所有可打印和不可打印字符字符,包括所有大写和 小写字母、所有数字、所有标点符号和其他一些符号。
- 元字符:出了普通字符之外的字符。 正则表达式,工具(vim、grep、less等)和程序语言(Perl、Python、C等)都使用正则表达式。
正则表达式分类:
- 普通正则表达式
- 扩展正则表示,支持更多的元字符
环境准备
bash
[root@server ~ 15:01:52]# vim words
[root@server ~ 15:02:20]# cat words |grep 'cat'
cat
category
acat
concatenate
clt
普通字符
bash
[root@server ~ 15:02:20]# cat words |grep 'cat'
cat
category
acat
concatenate
clt
字符集
[...]
匹配 [...] 中的任意一个字符。
bash
[root@server ~ 15:02:59]# cat words |grep 'c[ab]t'
cat
category
acat
concatenate
cbt
[a-z] [A-Z] [0-9]
-
a-z\] ,匹配所有小写字母。
-
0-9\] ,匹配所有数字。
[root@server ~ 15:03:19]# cat words |grep 'c[a-z]t'
cat
category
acat
concatenate
cbt
clt
[root@server ~ 15:03:31]# cat words |grep 'c[A-Z]t'
[root@server ~ 15:03:40]# echo cEt >> words
[root@server ~ 15:03:52]# cat words |grep 'c[A-Z]t'
cEt
[root@server ~ 15:03:53]# cat words |grep 'c[0-9]t'
c1t
[root@server ~ 15:04:00]# cat words |grep 'c[a-z0-9]t'
cat
category
acat
concatenate
c1t
cbt
clt
[root@server ~ 15:04:11]# cat words |grep 'c[a-zA-Z0-9]t'
cat
category
acat
concatenate
c1t
cbt
clt
cEt
[root@server ~ 15:04:20]# echo c-t >> words
要想匹配-符号,将改符号写在第一个位置
[root@server ~ 15:04:38]# cat words |grep 'c[-a-zA-Z0-9]t'
cat
category
acat
concatenate
c1t
cbt
clt
cEt
c-t
##### \[\^...\]
匹配除了 \[...\] 中字符的所有字符。
```bash
[root@server ~ 15:04:50]# cat words |grep 'c[^ab]t'
c1t
clt
cEt
c-t
# ^放中间会被当做普通字符
[root@server ~ 15:05:10]# cat words |grep 'c[a^b]t'
cat
category
acat
concatenate
cbt
.
匹配除换行符( \n 、 \r )之外的任何单个字符,相等于 [^\n\r] 。
bash
[root@server ~ 15:05:22]# cat words |grep 'c.t'
cat
category
acat
concatenate
c1t
cbt
clt
cEt
c-t
\
将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。 例如, 'n' 匹配字符 'n'。 \n 匹配换行符。序列 \ 匹配 \ ,而 ( 则匹配 ( 。
bash
[root@server ~ 15:05:41]# echo c.t >> words
[root@server ~ 15:06:00]# cat words |grep 'c\.t'
c.t
|
| 符号是扩展表达式中元字符,指明两项之间的一个选择。要匹配 | ,请使用\ | 。
bash
# 使用egrep或者grep -E 匹配
[root@server ~ 15:06:06]# cat words |egrep 'cat|dog'
cat
category
acat
concatenate
dog
[root@server ~ 15:06:38]# cat words |grep -E 'cat|dog'
cat
category
acat
concatenate
dog
| 选项 | 描述 |
|---|---|
| [[:digit:]] | 数字: 0 1 2 3 4 5 6 7 8 9 等同于[0-9] |
| [[:xdigit:]] | 十六进制数字: 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f等同于[0-9a-fA-F] |
| [[:lower:]] | 小写字母:在 C 语言环境和ASCII字符编码中,对应于[a-z] |
| [[:upper:]] | 大写字母:在 C 语言环境和ASCII字符编码中,对应于[A-Z] |
| [[:alpha:]] | 字母字符:[[:lower:]和[[:upper:]];在C语言环境和ASCII字符编码中,等同于**[A-Za-z]** |
| [[:alnum:]] | 字母数字字符:[:alpha:]和[:digit:];在C语言环境和ASCII字符编码中,等同于**[0-9A-Za-z]** |
| [[:blank:]]或者[[:space:]] | 空白字符:在 C 语言环境中,它对应于制表符、换行符、垂直制表符、换页符、回车符和空格。 |
| [[:punct:]] | 标点符号:在C语言环境和ASCII字符编码中,它对应于!" # $ % &'()*+,-./:;<=>?@[]^_`{|}~ |
| [[:print:]]或者 [[:graph:]] | 可打印字符: [[:alnum:]]、[[:punct:]]。 |
| [[:cntrl:]] | 控制字符。在 ASCII中, 这些字符对应八进制代码000到037和 177 (DEL)。 |
非打印字符
终端中不显示的字符,例如换行符。
| 字符 | 描述 |
|---|---|
| \cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
| \s | 匹配任何空白字符 ,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
| \S | 匹配任何非空白字符 。等价于 [^ \f\n\r\t\v]。 |
| \w | 匹配字母、数字、下划线。等价于 [A-Za-z0-9_] |
| \W | 匹配任何非单词字符。等价于[^A-Za-z0-9_] |
| \t | 匹配一个制表符。等价于 \x09 和 \cI。 |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
grep 命令支持
\w、\W、\s、\S。
定位符
^
匹配行首位置。
bash
[laoma@shell ~]$ cat words | grep '^cat'
cat
category
$
匹配行末位置。
bash
[laoma@shell ~]$ cat words | grep 'cat$'
cat
acat
[laoma@shell ~]$ cat words | grep '^cat$'
cat
# 查询/etc/profile文件中有效行
[laoma@shell ~]$ cat /etc/profile | egrep -v '^#|^$'
# -v 取反,不显示匹配的内容
# 查看 /etc/ansible/ansible.cfg 中有哪些 section
[laoma@shell ~]$ cat /etc/ansible/ansible.cfg | egrep '^\['
# 查看 /var/log/message Aug 19 14:01 到 Aug 19 14:06 时间段发生的事件
[laoma@shell ~]$ sudo cat /var/log/messages | egrep '^Aug 19 14:0[1-6]
\b
匹配一个单词边界。
bash
[laoma@shell ~]$ echo hello cat >> words
[laoma@shell ~]$ cat words | grep '\bcat'
cat
category
hello cat
[laoma@shell ~]$ cat words | grep 'cat\b'
cat
acat
hello cat
[laoma@shell ~]$ cat words | grep '\bcat\b'
cat
hello cat
\B
非单词边界匹配。
bash
[laoma@shell ~]$ cat words | grep '\Bcat'
acat
concatenate
\< 和 \>
\<,匹配一个单词左边界。\>,匹配一个单词右边界。
bash
[laoma@shell ~]$ cat words | grep '\<cat'
cat
category
hello cat
[laoma@shell ~]$ cat words | grep 'cat\>'
cat
acat
hello cat
限定次数
*
匹配前面的子表达式任意次数。
bash
[laoma@shell ~]$ echo dg >> words
[laoma@shell ~]$ echo doog >> words
[laoma@shell ~]$ cat words | grep 'do*g'
dog
dg
doog
+
+ 是扩展表达式元字符,匹配前面的子表达式一次以上次数。
bash
[laoma@shell ~]$ cat words | egrep 'do+g'
dog
doog
?
? 是扩展表达式元字符,匹配前面的子表达式一次以下次数。
bash
[laoma@shell ~]$ cat words | egrep 'do?g'
dog
dg
{n}
{} 是扩展表达式元字符,用于匹配特定次数。例如:{n},配置n次。
bash
[laoma@shell ~]$ cat words | egrep 'do{2}g'
doog
{m,n}
{m,n},是扩展表达式元字符,用于匹配次数介于m-n之间。
bash
[laoma@shell ~]$ echo dooog >> words
[laoma@shell ~]$ echo doooog >> words
[laoma@shell ~]$ cat words | egrep 'do{2,3}g'
doog
dooog
{m,}
{m,},是扩展表达式元字符,匹配前面的子表达式m次以上次数。
bash
[laoma@shell ~]$ cat words | egrep 'do{2,}g'
doog
dooog
doooog
{,n}
{,n},是扩展表达式元字符,匹配前面的子表达式n次以下次数。
bash
[laoma@shell ~]$ cat words | egrep 'do{,3}g'
dog
doog
dg
dooog
()
标记一个子表达式。
bash
[laoma@shell ~]$ echo dogdog >> words
[laoma@shell ~]$ echo dogdogdog >> words
[laoma@shell ~]$ echo dogdogdogdog >> words
[laoma@shell ~]$ cat words | egrep '(dog){2,3}'
dogdog
dogdogdog
dogdogdogdog
[laoma@shell ~]$ cat words | egrep '(dog){2,}'
dogdog
dogdogdog
dogdogdogdog
综合案例
如何过滤出以下文件中所有有效IPv4地址?
bash
0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
999.9.9.9
01.1.1.1
10.0.0.0
0.1.1.1
266.1.1.1
248.1.1.1
256.1.1.1
具体步骤如下:
bash
# 首先确定地址每位数范围
# 一位数,范围是 [0-9]
# 两位数,十位数 [1-9],个位数 [0-9]
# 三位数,1开头 1[0-9][0-9]
# 2开头 2[0-4][0-9]
# 25开头 25[0-5]
# 用 | 组合起来,三位数的要用()括起来当作一个整体:
([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])
# 加上中间的 . 要使用转义符\
([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))\.
# 重复三次
(([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))\.){3}
# 加上最后一位
(([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))\.){3}([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))
# 测试
[root@server ~ 15:56:11]# cat ip.list | egrep '^(([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))\.){3}([0-9]|[1-9][0-9]|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))$'
0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
10.0.0.0
0.1.1.1
248.1.1.1
# 优化整合
一位数和二位数
[0-9]|[1-9][0-9]
=> [1-9]?[0-9]
三位数1开头
1[0-9][0-9]
=> 1[0-9]{2}
# 得到
[1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]
# 最终结果
((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3})([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])
# 测试
[root@server ~ 16:35:39]# cat ip.list | egrep '^((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3})([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
10.0.0.0
0.1.1.1
248.1.1.1