一丶 目标
- 了解shell中的通配符
- 熟悉grep,cut,sort等小工具与shell中的通配符的使用
文本处理工具
1.grep工具
grep是行过滤工具,用于根据关键字进行行过滤
语法的选项
语法:
# grep [选项] '关键字' 文件名
选项:
-o: 打印匹配关键字
-w: 根据单词显示
-i: 不区分大小写
-v: 取反查找
-c: 统计匹配到的次数
-n: 显示行号
-r: 逐层便利目录查找
-A: 显示匹配行及后面多少行
-B: 显示匹配行以及后面有多少行
-C: 显示匹配行前后多少行
-l: 只列出匹配的文件名
-L: 列出不匹配的文件名
-e: 使用正则匹配
-E: 使用扩展正则匹配
^: 正则匹配 以什么开头的行
$: 正则匹配 以什么结尾的行
^$: 匹配空行
--color=auto: 可以将找到的关键则部分加上颜色的显示
回顾grep
颜色显示(别名设置):
适用场景:比如说每一次使用grep需要进行加上颜色显示的时候都要加上–color,以下部分可以避免重复操作
# alias grep='grep --color=auto' //只针对当前终端或当前用户生效
永久生效
vim /etc/bashrc
#文件末尾添加
alias grep='grep --color=auto'
重新读取
source /etc/bashrc
grep常用操作练习
1.1在/etc/passwd过滤出关于"root"的行
[root@bogon ~]# grep 'root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
1.2.在/etc/passwd过滤出关于"root"的行,并显示匹配内容的行号
[root@bogon ~]# grep -n 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
1.3.在/etc/passwd过滤出关于"root"的行,并显示匹配内容的行号和不区分大小写(默认区分大小写)
[root@bogon ~]# grep -ni 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
1.4.匹配在/etc/passwd过滤出以"root"开头的行,并显示行号
[root@bogon ~]# grep -n '^root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
1.5.匹配在/etc/passwd过滤出以"bash"结尾的行,并显示行号
[root@bogon ~]# grep -n 'bash$' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
43:lishuang:x:1000:1000:lishuang:/home/lishuang:/bin/bash
1.6.匹配在/etc/passwd过滤出以"root"不以开头的行,并显示行号
[root@bogon ~]# grep -nv '^root' /etc/passwd
2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6:sync:x:5:0:sync:/sbin:/bin/sync
.........
1.7.匹配在/etc/passwd过滤出以"ftp"以开头的行,显示行号和过滤出ftp以上的前三行
[root@bogon ~]# grep -nB 3 '^ftp' /etc/passwd
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10-operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
1.8.匹配在/etc/passwd过滤出以"ftp"以开头的行,显示行号和过滤出ftp以上的后三行
[root@bogon ~]# grep -nA 3 '^ftp' /etc/passwd
12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13-nobody:x:99:99:Nobody:/:/sbin/nologin
14-systemd-bus-proxy:x:999:998:systemd Bus Proxy:/:/sbin/nologin
15-systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
1.9.匹配在/etc/passwd过滤出以"ftp"以开头的行,显示行号和过滤出ftp以上的前三行和后三行
[root@bogon ~]# grep -nC 3 '^ftp' /etc/passwd
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10-operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13-nobody:x:99:99:Nobody:/:/sbin/nologin
14-systemd-bus-proxy:x:999:998:systemd Bus Proxy:/:/sbin/nologin
15-systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
##关于A B C 选项适用场景:比如过生产环境中我们会遇到服务运行的一些问题,这时候排错我们基本上都是根据日志来解决问题,因为肯定大家已经发现了,grep是根据行进行过滤的,只显示匹配到的行,我们如果只过滤日志中的error信息的时候可能信息会显示的不全,那么就需要用到这些参数了
1.10.匹配在/etc/passwd过滤出以"ftp"以开头的行,并且只显示匹配到的单词,也就是只显示ftp本身
[root@bogon ~]# grep -o '^ftp' /etc/passwd
ftp
1.11.匹配在/etc/passwd过滤出以"ftp"单词开头的行
[root@bogon ~]# grep -w '^ftp' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
2.cut工具
cut是列截取工具,用于列的截取,与awk有相似之处,但是awk功能认为awk操作,虽然比cut语法复杂,但是还是要功能要强大需要,强烈推荐学习awk
法语和选项
语法:
# cut 选项 文件名
常用选项:
-c: 以字符为单位进行分割,截取 ##比如-c1,5 截取第一个字符和第五个字符
-d: 自定义分隔符,默认为制表符\t ## 比如以”:“进行分割,那么只要该行出现冒号,就被视为一列
-f: 与-d一起使用,指定截取哪块区域 ##比如-f1-5 截取第一列到第五列
举例说明:
# cut -d: -f1 /etc/passwd 以冒号分割,截取第一列内容
# cut -d: -f1,6,7 /etc/passwd 以冒号分割,截取第1,6,7列内容
练习
2.1 过滤出/etc/passwd的前5个字符
[root@bogon ~]# cut -c 1-5 /etc/passwd
root:
bin:x
daemo
adm:x
lp:x:
sync:
shutd
halt:
.....
-
2过滤/etc/passwd所有的用户名称
##首先要考虑的肯定是这个文件是以什么作为分割的(以冒号作为分割列),用户名出现在第一列
[root@bogon ~]# cut -d: -f1 /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-bus-proxy
systemd-network
dbus
polkitd
....
2.3 /etc/passwd过滤出用户名称和uid的内容
[root@bogon ~]# cut -d: -f1,3 /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
....
##补充:你一定发现了”-“就是start和end的意思,开始的结束,”,“是和的意思,就比如1,7列
3.练习
使用grep和cut列出当前系统级别
查看运行级别的方法
- 命令runlevel
- 配置文件 /etc/inittab
[root@bogon ~]# runlevel |cut -c 3
5
[root@bogon ~]# runlevel | cut -d' ' -f2
5
[root@bogon ~]# grep -v '^#' /etc/inittab | cut -d: -f2
5
##当然有很多方法这里不再赘述
4.sort工具
sort工具用于排序;他将文件的每一行作为一个单位,从首字符向后,依次按ASCLL码值进行比较,最后他们以升序输出
语法和选项
-u:去除重复行
-r:降序排序,默认是升序
-o:将升序结果输出到文件中,类似重定向符号>
-n:以数字排序,默认是按字符排序
-t:分隔符
-k:第N列
-b:忽略前导空格
-R:随机排序,每次运行的结果均不同
举例说明
# sort -n -t: -k3 /etc/passwd 按照用户的uid以升序的方式排序
# sort -nr -t: -k3 /etc/passwd 按照用户的uid以降序的方式排序
# sort -nu test.txt #按照数字排序
# sort -nr test.txt #按照数字排序并且去重
# sort -nur test.txt #去重并以降序方式排序
# sort -nur test.txt -o test3.txt #按照数字排序并将结果重定向到test3.txt
# sort -R test.txt #随机排序,每次运行的结果均不同
# sort -u test.txt #去除重复行
练习
4.1按照用户的uid以升序的方式排序,显示第5个,并且去重
[root@bogon ~]# sort -nu -t: -k3 /etc/passwd | head -5 | tail -1
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
4.2按照用户的uid以降序的方式排序,显示第5个,并且去重
[root@bogon ~]# sort -nur -t: -k3 /etc/passwd | head -5 | tail -1
polkitd:x:998:997:User for polkitd:/:/sbin/nologin
4.3 按照用户的uid以降序的方式排序,显示第5个 重定向到1.txt
[root@bogon ~]# sort -nur -t: -k3 /etc/passwd | head -5 | tail -1 >1.txt
[root@bogon ~]# cat 1.txt
polkitd:x:998:997:User for polkitd:/:/sbin/nologin
5.uniq工具
uniq用于去除连续的重复的行
常见选项
-i:忽略大小写
-c:统计重复行次数
-d:只显示重复行
举例说明
# uniq 2.txt
# uniq -d 2.txt
# uniq -dc 2.txt
练习
练习文本
[root@bogon ~]# cat 2.txt
aaa
111
aaa
444
555
555
555
111
aaa
aaa
[root@bogon ~]# uniq 2.txt
aaa
111
aaa
444
555
111
aaa
默认情况下uniq只去除连续重复的行,如果想去除所有重复的行,那么可以使用sort -u 如下所示
[root@bogon ~]# sort -u 2.txt
111
444
555
aaa
统计连续的行的重复次(只用被连续重复的时候才会被统计)
[root@bogon ~]# uniq -c 2.txt
1 aaa
1 111
1 aaa
1 444
3 555
1 111
2 aaa
可以看到555连续重复的行为3次 ,aaa为两次
5.1只显示不连续重复的行
[root@bogon ~]# uniq -u 2.txt
aaa
111
aaa
444
111
- 2只显示连续重复的行
[root@bogon ~]# uniq -d 2.txt
555
aaa
6.tee工具
tee工具是从标准输入读取并写入到标准输出的文件,即:双向覆盖重定向(屏幕输出|文本输入)
选项
-a: 双向追加重定向
练习
[root@bogon ~]# echo hello
hello
[root@bogon ~]# echo hello |tee 3.txt
hello
[root@bogon ~]# cat 3.txt
hello
[root@bogon ~]# echo lishuang |tee -a 3.txt
lishuang
[root@bogon ~]# cat 3.txt
hello
lishuang
作用通俗来讲就是在屏幕上标准输出一份,在文件里面标准输入一份,-a选项的作用也就是追加的意思
[root@bogon ~]# cut -d: -f1 /etc/passwd | sort | head -5 | grep -o 'adm' | tee 4.txt
adm
[root@bogon ~]# cat 4.txt
adm
##如果有没有理解的小伙伴 我们可以拆分理解以下
[root@bogon ~]# cut -d: -f1 /etc/passwd
root
bin
daemon
....
##打印出所有用户
[root@bogon ~]# cut -d: -f1 /etc/passwd | sort | head -5
abrt
adm
avahi
bin
chrony
##依次按ASCLL码值进行比较也就是按照首字母为abcdefg…进行排序,head显示前5列
[root@bogon ~]# cut -d: -f1 /etc/passwd | sort | head -5 | grep -o 'adm' | tee 4.txt
adm
##grep -o选项只帅筛选指定内容,将内容双向输出和输入
很获取的到这种办法有很简单的办法,但是组合使用是想让我们回顾之前学习的
7.diff工具
diff工具用于逐行比较文件的不同
注意:diff描述两个文件不同的方式是告诉我们怎么改变第一个文件之后与第二个文件匹配
语法和选项
语法:
diff [选项] 文件1 文件2
常用选项:
选项 | 含义 | 备注 |
---|---|---|
-b | 不检查空格 | |
-B | 不检查空白行 | |
-i | 不检查大小写 | |
-w | 忽略所有的空格 | |
–normal | 正常格式显示(默认) | |
-c | 上下文格式显示 | |
-u | 合并格式显示 |
举例说明:
-
比较两个不同文件异同,文件准备:
[root@bogon ~]# cat -n file1 1 aaaa 2 111 3 hello world 4 222 5 333 6 bbb [root@bogon ~]# cat -n file2 1 aaa 2 hello 3 111 4 222 5 bbb 6 333 7 world
1)正常显示
[root@bogon ~]# diff file1 file2
1c1,2 第一个文件的第1行需要改变(c=change)才能和第二个文件的第1行匹配
< aaaa 小于号"<"表示左边文件(file1)文件内容
--- ---表示分隔符
> aaa 大于号">"表示右边文件(file2)文件内容
> hello
3d3 第一个文件的第3行删除(d=delete)后才能和第二个文件的第3行匹配
< hello world
5d4 第一个文件得第5行删除后才能和第二个文件的第4行匹配
< 333
6a6,7 第一个文件的第6行追加(a=add)内容后才能和第二个文件得第6到7行匹配
> 333 需要增加的内容在第二个文件里是333和world
> world
2)上下文格式显示
[root@bogon ~]# diff -c file1 file2
*** file1 2020-11-11 19:33:06.248080308 +0800 第一个文件file1以***作为标识
--- file2 2020-11-11 19:32:49.561944839 +0800 第二个文件以file2以---作为标识
*************** 分隔符
*** 1,6 **** ***代表file1文件,1,6表示1到6行
! aaaa !表示该行需要修改才能与第二个文件匹配
111
- hello world -表示需要删除改行才与第二个文件匹配
222
- 333 -表示需要删除改行才与第二个文件匹配
bbb
--- 1,7 ---- 以---开头表示file2文件,1,7表示1到7行
! aaa 表示第一个文件需要修改才能与第二个文件匹配
! hello 表示第一个文件需要修改才能与第二个文件匹配
111
222
bbb
+ 333 表示第一个文件需要加上该行才与第二个文件匹配
+ world 表示第一个文件需要加上该行才与第二个文件匹配
3)合并格式显示
[root@bogon ~]# diff -u file1 file2
--- file1 2020-11-11 19:33:06.248080308 +0800 ---表示file1文件
+++ file2 2020-11-11 19:32:49.561944839 +0800 +++表示file2文件
@@ -1,6 +1,7 @@ -1,6表示第一个文件的1-6行 +1,7表示第二个文件得1-7行
-aaaa -表示删除
+aaa +表示添加
+hello
111
-hello world
222
-333
bbb
+333
+world
更加理解的应该是第三种方法 打开file文件按照- 和+符号增删操作就可以和file2文件一样了
比较两个目录不同 相同文件的内容
默认情况下也会比较两个目录里相同文件的内容
[root@bogon ~]# mkdir /dir1
[root@bogon ~]# mkdir /dir2
[root@bogon ~]# mv file1 /dir1/
[root@bogon ~]# mv file2 /dir2/
[root@bogon ~]# diff /dir1/ /dir2/
只在 /dir1/ 存在:file1
只在 /dir2/ 存在:file2
[root@bogon ~]# diff /dir1/file1 /dir2/file2
1c1,2
< aaaa
---
> aaa
> hello
3d3
< hello world
5d4
< 333
6a6,7
> 333
> world
如果只需要比较两个目录里文件的不同,不需要进一步比较文件内容,需要加-q选项
[root@bogon ~]# mkdir test1 test2
[root@bogon ~]# touch test1/file{1..5}
[root@bogon ~]# touch test2/file{1..3}
[root@bogon ~]# touch test2/file5 test2/file6
[root@bogon ~]# diff -q test1/ test2
只在 test1 存在:file4
只在 test2 存在:file6
其他小技巧:
有时候我们需要以一个文件为标准,去修改其他文件,并且修改的地方较多时,我们可以通过打补丁的方式完成
适用场景:当我们在生产环境中,需要更改多个配置文件,如果反复进行增删改操作,那么势必会很浪费时间
1)先找出文件不同,然后输出到一个文件
[root@bogon ~]# diff -uN /dir1/file1 /dir2/file2 >file.patch
-u:上下文模式
-N:将不存在的文件当作空文件
2)将不同内容打补丁到
[root@bogon ~]# patch /dir1/file1 file.patch
patching file /dir1/file1
##patch命令用于将文件合并,以制表符进行分割,下面会详细解释
3)测试验证
[root@bogon ~]# diff /dir1/file1 /dir2/file2
[root@bogon ~]#
#这样的话file1更改的与file2就一摸一样了
8.paste工具
paste工具用于合并文件行
常用选项:
-d:自定义间隔符,默认是tab也就是制表符\t
-s:串行处理,非并行,默认为并行处理
练习
准备文本
8.1 默认会以tab也就是制表符隔开
[root@bogon ~]# paste test1.txt test2.txt
aaa ddd
bbb eee
ccc fff
8.2 分隔符
[root@bogon ~]# paste -d , test1.txt test2.txt
aaa,ddd
bbb,eee
ccc,fff
8.3 串行处理
[root@bogon ~]# paste -s -d --- test1.txt test2.txt
aaa-bbb-ccc
ddd-eee-fff
[root@bogon ~]# paste -s test1.txt test2.txt
aaa bbb ccc
ddd eee fff
9.tr工具
tr用于字符转换,替换和删除;主要用于删除文件控制字符或进行字符转换
语法和选项
语法:
用法1:命令的执行结果交给tr处理,其中string1用于查询,string2用户转换处理
# commands | tr 'string1' 'string2'
用法2: tr处理的内容来自文件,记住要使用"<"标准输入
# tr tr 'string1' 'string2' < filename
用法3: 匹配string1进行相应操作,如删除操作
#tr options 'string1' < filename
常用选项
-d 删除字符串1种所有输入字符
-s 删除所有重复出现字符序列,只保留一个;即将重复出现字符串压缩为一个字符串
常匹配字符串:
#其实也就是正则
字符串 | 含义 | 备注 |
---|---|---|
a-z或[:lower:] | 匹配所有小写字符 | |
A-Z或[:upper:] | 匹配所有大写字符 | |
0-9或[:digit:] | 匹配所有数字 | |
[:alnum:] | 匹配所有字母和数字 | |
[:alpha:] | 匹配所有字母 | |
[:blank:] | 所有水平空白 | |
[:punct:] | 匹配所有标点符号 | |
[:space:] | 所有水平或垂直的空格 | |
[:cntrl:] | 所有控制字符 | \f \n \r \t |
练习
9.1将/etc/passwd所有字母替换为大写显示出来
[root@bogon ~]# cp /etc/passwd 1.txt
[root@bogon ~]# tr 'a-z' 'A-Z' < 1.txt
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
BIN:X:1:1:BIN:/BIN:/SBIN/NOLOGIN
DAEMON:X:2:2:DAEMON:/SBIN:/SBIN/NOLOGIN
ADM:X:3:4:ADM:/VAR/ADM:/SBIN/NOLOGIN
LP:X:4:7:LP:/VAR/SPOOL/LPD:/SBIN/NOLOGIN
SYNC:X:5:0:SYNC:/SBIN:/BIN/SYNC
SHUTDOWN:X:6:0:SHUTDOWN:/SBIN:/SBIN/SHUTDOWN
HALT:X:7:0:HALT:/SBIN:/SBIN/HALT
......
[root@bogon ~]# cat 1.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
.....
##以上所有内容都不会对文件本身做修改
9.2 替换所有字母和数字为@符号
[root@bogon ~]# tr 'A-z0-9' '@' < 1.txt
@@@@:@:@:@:@@@@:/@@@@:/@@@/@@@@
@@@:@:@:@:@@@:/@@@:/@@@@/@@@@@@@
@@@@@@:@:@:@:@@@@@@:/@@@@:/@@@@/@@@@@@@
@@@:@:@:@:@@@:/@@@/@@@:/@@@@/@@@@@@@
@@:@:@:@:@@:/@@@/@@@@@/@@@:/@@@@/@@@@@@@
@@@@:@:@:@:@@@@:/@@@@:/@@@/@@@@
@@@@@@@@:@:@:@:@@@@@@@@:/@@@@:/@@@@/@@@@@@@@
.....
#他与正则匹配也有一点不一样的地方,正则匹配a-Z匹配所有字母,而这里就需要A-z
9.3 将文件中的:和/替换为#
[root@bogon ~]# tr ':/' '#' < 1.txt
root#x#0#0#root##root##bin#bash
bin#x#1#1#bin##bin##sbin#nologin
daemon#x#2#2#daemon##sbin##sbin#nologin
adm#x#3#4#adm##var#adm##sbin#nologin
......
#这里需要注意的是tr工具只能一对一的进行替换,不会将:/替换为一个#号
9.4 将文件中小写字母全部删除
[root@bogon ~]# tr -d 'a-z' < 1.txt
::0:0::/://
::1:1::/://
::2:2::/://
::3:4:://://
::4:7::///://
其实也可以这样做
[root@bogon ~]# tr -d '[a-z]' < 1.txt
::0:0::/://
::1:1::/://
::2:2::/://
....
#效果的实现方式都是一样的,在正则中花括号表示或的意思,也就是说匹配多个字符或字符串,只要达到其中一个就会有结果
9.5 压缩文件中连续重复的字符
[root@bogon ~]# echo -e 'aaabbbccc\nabcabcabc' | tee test.txt
aaabbbccc
abcabcabc
[root@bogon ~]# tr -s 'abc' < test.txt
abc
abcabcabc
##一眼就看明白了就不解释了
练习2
结合上面我们之前学过的几个工具具做一次练习
1.使用小工具分别截取ens33的ip
[root@bogon ~]# ifconfig ens33| grep -o "inet.[0-9]\{3\}\.[0-9]\{3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
inet 192.168.20.20
[root@bogon ~]# ifconfig ens33 | grep -o "\binet\b.[0-9]\+.[0-9]\+.[0-9]\+.[0-9]\+"
inet 192.168.20.20
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'|cut -d' ' -f10
192.168.20.20
2.筛选出IP地址MAC地址以及子网掩码
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'|tr -d 'a-z' |tr ' ' '\n'| grep '[^$]'
192.168.20.20
255.255.255.0
192.168.20.255
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'|tr -d 'a-z' |tr ' ' '\n'| grep -v '^$'
192.168.20.20
255.255.255.0
192.168.20.255
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'| awk '{print $0}'
inet 192.168.20.20 netmask 255.255.255.0 broadcast 192.168.20.255
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'| awk '{print $2,$4,$6}'
192.168.20.20 255.255.255.0 192.168.20.255
[root@bogon ~]# ifconfig ens33 | grep '\binet\b'|tr -d 'a-z'
192.168.20.20 255.255.255.0 192.168.20.255
2.截取网卡ID
[root@bogon ~]# ifconfig ens33 | grep 'ether\b' | awk '{print $2}'
00:0c:29:70:36:61
[root@bogon ~]# ifconfig ens33 | grep 'ether\b' | tr -s ' '| cut -d' ' -f3
00:0c:29:70:36:61
3.列出所有普通用户并写入到文件中
[root@bogon ~]# cat /etc/passwd | cut -d':' -f1,2,3 | awk -v FS=":" '{if($3>=500){print $1}}'
systemd-bus-proxy
polkitd
unbound
libstoragemgmt
colord
saslauth
geoclue
nfsnobody
chrony
setroubleshoot
sssd
gnome-initial-setup
lishuang
mysql
[root@bogon ~]# cat /etc/passwd | cut -d':' -f1,2,3 | awk -v FS=":" 'BEGIN{printf "%s\n " , "普通用户"}{if($3>=500){printf "%s\n" , $1}}' | tee 1.txt
普通用户
systemd-bus-proxy
polkitd
unbound
libstoragemgmt
colord
saslauth
geoclue
nfsnobody
chrony
setroubleshoot
sssd
gnome-initial-setup
lishuang
mysql
二丶bash的特性
1.命令和文件自动补全
tab只能补全命令和文件(rhel6/Centos6).
2.常用的快捷键
^C 终止前台运行的程序
^Z 将前台运行的程序挂起到后台
^D 退出 等价exit
^L 清屏
^A | HOME 光标移动命令行的最前端
^E | END 光标移动到命令的后端
^U 删除光标前所有字符
^K 删除光标后所有字符
^R 搜索历史命令
3.常用的通配符(重点)
*:匹配0或多个任意字符
?:匹配任意单个字符
[list]: 匹配[list]中的任意单个字符,或者一组单个字符
[!list]: 匹配除了list中的任意单个字符
{string1,string2...}:匹配string1,string2或更多字符串
实例:
##可以看下他们的区别
[root@bogon ~]# mkdir aaa
[root@bogon ~]# cd aaa/
[root@bogon aaa]# touch file{1..20}.txt
[root@bogon aaa]# ll file?.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file1.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file2.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file3.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file4.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file5.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file6.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file7.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file8.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file9.txt
[root@bogon aaa]# ll file[0-9].txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file1.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file2.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file3.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file4.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file5.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file6.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file7.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file8.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file9.txt
[root@bogon aaa]# ll file[0-29].txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file1.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file2.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file9.txt
[root@bogon aaa]# ll file*.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file10.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file11.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file12.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file13.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file14.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file15.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file16.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file17.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file18.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file19.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file1.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file20.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file2.txt
[root@bogon aaa]# ll file{1,2}.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file1.txt
-rw-r--r--. 1 root root 0 11月 16 14:51 file2.txt
4.bash中的引号(重点)
- 双引号"" :会把引号中的内容当成整体来看待,允许通过$符号引用其他变量值
[root@bogon aaa]# echo $(hostname)
bogon
[root@bogon aaa]# echo "$(hostname)"
bogon
- 单引号’’ : 会把引号内容当成整体来看待,禁止引用其他变量值,shell中特殊符号中都被视为普通符号
[root@bogon aaa]# echo '$(hostname)'
$(hostname)
- 反撇号``: 反撇号和$()一样,括号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
[root@bogon aaa]# echo `echo $(hostname)`
bogon
[root@bogon aaa]# date
2020年 11月 16日 星期一 14:56:12 CST
[root@bogon aaa]# date +%F
2020-11-16
[root@bogon aaa]# echo `date +%F `
2020-11-16
多层嵌套如何解决?
[root@bogon aaa]# echo ` echo "`date +%F`" `
-bash: command substitution:行1: 寻找匹配的 `"' 是遇到了未预期的文件结束符
-bash: command substitution:行2: 语法错误: 未预期的文件结尾
[root@bogon aaa]# echo $(echo "`date +%F`")
2020-11-16
三丶shell编程模块课程目标
-
shell的基本语法结构
如:变量定义,条件判断,循环语句(for ,until,while),分支语句,函数和数组等:
-
基本正则表达式的运用
-
文件处理三剑客:grep,sed,awk工具的使用
-
使用shell脚本完成一些较复杂的任务,如:服务搭建,批量处理等
说明:以上内容仅仅是基本要求,还有很多更深更难得语法需要扩展学习,关于正则匹配和awk工具的使用可以参考注意的笔记
1.编程语言分类
前言
计算机只能认识(识别)机器语言(0和1)二进制,如(11000000这种)。但是,我们的程序猿们不能直接去写01这样的代码,所以,想要将程序员所开发的代码在计算机上运行,就必须找“人”(工具)来翻译成机器语言,这个“人”(工具)就是我们常常所说的编译器或者解释器。
解释型语言和编译型语言 | ||
---|---|---|
解释型语言 | 编译型语言 | |
概念 | 计算机不能直接的理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言的编写的程序。翻译的方式有两种,一个是编译,一个是解释。两种方式只是翻译的时间不同。 | |
特征 | 解释性语言是指它常用的执行机制是使用一个“解释器”来执行,解释器对于程序是一句一句“翻译”成机器语言来一句一句执行,例如shell脚本语言。 | 编译型语言是指它常用的执行机制是使用一个“编译器”来编译成机器语言,然后你就可以直接运行(执行)这个编译成的“可执行文件”。例如C语言你也可以为解释性语言(如shell脚本语言)写个编译器来编译,这样它就成了“编译语言” |
区别 | 不管是解释性语言还是编译型都可编译或解释,前提是有这样的编译器或解释器(比如你自己写一个),找不到这样的编译器你当然不能编译对于语言本身来说,各种编程语言本质没什么不同。所谓的“解释性”和“编译”指的是执行机制上的不同。 |
进而可推之解释性语言和编译型语言的优缺点
-
编译型语言
程序在执行之前需要一个专门的编译过程,将程序编译成一个机器语言文本,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台差些,如c,c++
-
解释型语言
程序不需要编译,程序在运行时由监视器翻译成机器语言,每执行依次都要翻译次,因为效率比较低,比如python/javascript/perl/ruby/shell等都是解释性语言
-
总结
编译型语言比解释语言的速度较快,但是不如解释性语言跨平台性能好。如果做底层开发或者大型应用程序或开发操作系统一般都用编译型语言。如果是一些服务器脚本及一些辅助的接口,对速度要求不高,对各个平台的兼容性有要求的话则一般都用解释性语言。
编译型语言:
- 编译型语言最大的优势之一就是其执行速度。用C/C++编写的程序运行速度要比用Java编写的相同程序快30%-70%。
- 编译型程序比解释型程序消耗的内存更少。
- 不利的一面——编译器比解释器要难写得多。
- 编译器在调试程序时提供不了多少帮助——有多少次在你的C语言代码中遇到一个“空指针异常”时,需要花费好几个小时来明确错误到底在代码中的什么位置。
- 可执行的编译型代码要比相同的解释型代码大许多。例如,C/C++的.exe文件要比同样功能的Java的.class文件大很多。
- 编译型程序是面向特定平台的因而是平台依赖的。
- 编译型程序不支持代码中实现安全性——例如,一个编译型的程序可以访问内存的任何区域,并且可以对你的PC做它想做的任何事情(大部分病毒是使用编译型语言编写的)
- 由于松散的安全性和平台依赖性,编译型语言不太适合开发因特网或者基于Web的应用。
解释型语言:
- 解释型语言提供了极佳的调试支持。一名Java程序员只需要几分钟就可以定位并修复一个“空指针异常”,因为Java运行环境不仅指明了异常的性质,而且给出了异常发生位置具体的行号和函数调用顺序(著名的堆栈跟踪信息)。这样的便利是编译型语言所无法提供的。
- 另一个优势是解释器比编译器容易实现
- 解释型语言最大的优势之一是其平台独立性
- 解释型语言也可以保证高度的安全性——这是互联网应用迫切需要的
- 中间语言代码的大小比编译型可执行代码小很多
- 平台独立性,以及严密的安全性是使解释型语言成为适合互联网和Web应用的理想语言的2个最重要的因素。
- 解释型语言存在一些严重的缺点。解释型应用占用更多的内存和CPU资源。这是由于,为了运行解释型语言编写的程序,相关的解释器必须首先运行。解释器是复杂的,智能的,大量消耗资源的程序并且它们会占用很多CPU周期和内存。
- 由于解释型应用的decode-fetch-execute(解码-抓取-执行)的周期,它们比编译型程序慢很多。
- 解释器也会做很多代码优化,运行时安全性检查;这些额外的步骤占用了更多的资源并进一步降低了应用的运行速度。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXAlWc5y-1606469552704)(C:\Users\48220\AppData\Roaming\Typora\typora-user-images\image-20201116152823639.png)]
如上图
- 简单说一下 c语言在编译之后,之后编译成本机能够识别的二进制机器码,那么对cpu,操作系统则会有一些显示,比如服务器的系统架构,cpu的型号,都会对机器码造成影响,可能导致识别不了
- shell相比较c语言来说,在与每一次执行都需要用解释器逐行解释一下
- java开发的程序,则需要在jvm环境上才能运行,因为java所编译出来的二进制文件必须要在java虚拟机上即可运行,所以跨平台性也是比较好的
2.shell的介绍
shell作用
将所需要的命令放到一个文件中,并给与它使用权限
shell脚本的概念
将要执行的命令按顺序保存到一个文本文件给该文件可执行权限
可结合各种Shell控制语句以完成更复杂的操作
shell脚本应用场景
重复性操作
交互性任务
批量事务处理
服务运行状态监控
定时任务执行
shell的作用-命令解释器,翻译官
介于系统内核与用户之间,负责解释命令行
用户登录shell
登陆后默认使用的shell程序一般为/bin/bash
不同shell的内部指令运行环境等会有所区别
编写脚本代码
使用vim文本编辑
每行一条Linux命令,按执行顺序依次编写
执行方式
方法一:sh脚本文件路径
#sh first.sh
方法二:./ 脚本文件路劲
#. /first.sh(需要执行权限)
方法三:source 脚本文件路径
#source first.sh
脚本的三构成
脚本声明
注释信息
可执行语句
交互式硬件设备
重定向操作:
标准输入(STDIN):默认的设备是键盘,文件编号为0,命令将从标准输入文件中读取在执行过程中需要的输入数据。
标准输出(STDOUT):默认的设备是显示器,文件编号为1,命令将执行后的输出结果发送到标准输出文件。
标准错误〈STDERR):默认的设备是显示器,文件编号为2,命令将执行期间的各种错误信息发送到标准错误文件。标准输入、标准输出和标准错误默认使用键盘和显示器作为关联的设备,与操作系统进行交互,完成最基本的输入、输出操作,即从键盘接收用户输入的各种命令字串、辅助控制信息,并将命令结果输出到屏幕上;如果命令执行出错,也会将错误信息反馈到屏幕上。
在实际的 Linux 系统维护中,可以改变输入、输出内容的方向,而不使用默认的标准输入、输出设备(键盘和显示器),这种操作称为重定向。
重定向操作
read使用的语法
read (选项)(参数)
选项:
-p 指定读取值时候的提示符
-t 指定读取值时候等待的时间
-a array 指定输入一个数组,赋值给array
-n 2 指定输入字符的任意类型的个数为2
不加参数,默认赋值给变量 REPLY
echo ¥ 变量名:读取信息
****重定向输入***************
[root@server1]#vi pass.txt
[root@server1~]#useradd lisi
[root@server1 ]# passwd --stdin lisi< pass.tX更改用户lisi 的密码。
passwd:所有的身份验证令牌已经成功更新。
管道操作符号|
增加筛选条件
总结:
-
shell就是人机交互的一个桥梁
-
shell的种类
[root@bogon aaa]# cat /etc/shells /bin/sh #是bash的一个快捷方式 /bin/bash #bash是大多数linux默认的shell,包含的功能几乎可以覆盖shell的所有功能 /sbin/nologin #表示非交互,不能登录操作系统 /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh #是csh的增强版,完全兼容csh /bin/csh #具有c语言风格的一种shell,具有很多特征,但也有一些缺陷
思考:
终端和shell有什么关系?
其实我们输入的每一条命令都是一条shell,只不过有些命令很快就执行完了所以我们看不到,我们我们打开一个mysql,将mysql ctrl+Z在后台运行我们在看一下
[root@bogon ~]# ps
PID TTY TIME CMD
22667 pts/3 00:00:00 bash
26258 pts/3 00:00:00 ps
mysql>
[1]+ 已停止 mysql
[root@bogon ~]# ps
PID TTY TIME CMD
22667 pts/3 00:00:00 bash
26430 pts/3 00:00:00 mysql
26756 pts/3 00:00:00 ps
四丶shell脚本介绍
1.什么是shell脚本
- 一句话概述
简单来说就是将需要执行的命令保存到文件中,按照顺序执行,他是解释性的,所以不需要进行编译
-
准备叙述
若干命令 + 脚本的基本格式 + 脚本特定语法 + 思想=shell脚本
2.什么时候用到脚本
重复化,复杂化的工作,通过把工作的命令携程脚本,以后仅仅需要执行这些脚本就能完成这些工作。
3.shell脚本能干啥?
- 自动化部署 lnmp/tomcat。。。
- 自动化管理 系统初始化脚本,批量更改主机密码,推送公钥。。。
- 自动化分析工具 统计网站访问量
- 自动化脚本 数据库备份,日志转储。。。。
4.如何学习shell脚本
- 尽可能记以更多的命令(记忆命令使用功能和使用场景)
- 掌握脚本的标准的格式(指定魔法字节,使用标准的执行方法运行脚本)
- 必须熟练掌握脚本的基本语法
5.学习shell脚本的秘诀
1.初阶:第一步能看懂别人写的脚本(记以命令使用功能和场景)
2.进阶:模仿练习别人写的脚本(多练)
3.高阶:独立完成(多思考)
6.shell脚本的基本写法
1.脚本第一行,魔法字符#!指定解释器[必写]
#!/bin/bash 表示以下内容使用bash解释器解析
注意:如果直接将解释器路径直接写死进脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以也可以使用:#!/bin/dev解释器
2.脚本的第二部分,注释(#号)作用,对脚本的基本信息进行描述【可选】
!#/bin/env bash
#以下内容是脚本的描述信息
# name:名字
#desc:描述describe
#path:存放路径
#usage: 用法
#update更新时间
#脚本具体内容
commands
...
3)脚本第三部分,脚本实现的具体代码内容
7.shell脚本的执行方法
标准执行方法
[root@bogon ~]# mkdir /shell01
[root@bogon ~]# cd /shell01/
[root@bogon shell01]# vim first_shell.sh
#!/bin/env bash
#以下内容是脚本的描述信息
# name:first_shell.sh
#desc:num1
#path:/shell01/first_shell.sh
#usage: /shell01/first_shell.sh
#update: 2020-11-16
echo "hello world"
echo "hello world"
echo "hello world"
[root@bogon shell01]# chmod +x first_shell.sh
#绝对路径
[root@bogon shell01]# /shell01/first_shell.sh
hello world
hello world
hello world
#相对路径
[root@bogon shell01]# ./first_shell.sh
hello world
hello world
hello world
注意:标准执行方法脚本必须要有可执行权限
非标准执行方法
[root@bogon shell01]# bash first_shell.sh
hello world
hello world
hello world
[root@bogon shell01]# sh first_shell.sh
hello world
hello world
hello world
[root@bogon shell01]# csh first_shell.sh
hello world
hello world
hello world
非标准的执行方法(不建议)
1.直接在命令行指定解释器执行
[root@bogon shell01]# bash -x first_shell.sh
+ echo 'hello world'
hello world
+ echo 'hello world'
hello world
+ echo 'hello world'
hello world
-x:一般用于排错,查看脚本的执行过程
-n:用来查看脚本的语法是否存在问题
2.使用source命令读取脚本文件,执行文件里面的代码
[root@bogon shell01]# source first_shell.sh
hello world
hello world
hello world
小试牛刀:写一个木有灵魂的脚本,要求如下:
-
删除/tmp目录下面的所有文件
-
然后在/tmp目录里创建三个目录,分别是dir1-dir3
-
拷贝/etc/hosts文件到刚创建的dir1目录里
-
最后打印“报告首长,任务已于什么时间完成任务”内容
[root@bogon shell01]# vim two_shell.sh
#!/bin/env bash
#name: shell
#desc: num2
#path: /shell01/two.sh
#usage: /shell01/two.sh
#update: 2020-11-16
rm -rf /tmp/*
mkdir /tmp/dir{1..3}
cp /etc/hosts /tmp/dir1
echo "报告首长,任务已于$(date +'%F +%T')完成任务"
[root@bogon shell01]# chmod +x two_shell.sh
[root@bogon shell01]# bash two_shell.sh
报告首长,任务已于2020-11-16 +22:03:28完成任务
五丶变量的定义
1.变量是什么?
一句话概述,变量是用来临时保存数据的,该数据是可以变化的数据
2.什么时候需要定义变量?
- 如果某个内容需要多次使用,并且在代码中多次重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值。
- 在代码运作的过程中,可能会把某些命令的执行结果保存起来,后续代码需要使用这些结果,就可以直接使用这个变量
3.变量如何定义?
变量名=变量值
变量名:用来临时保存数据的
变量值:用来临时的可变化的数据
[root@bogon shell01]# A='hello mr' 定义变量A
[root@bogon shell01]# echo $A 调用变量A
hello mr
[root@bogon shell01]# echo ${A} 也可以这样调用
hello mr
[root@bogon shell01]# A=hello 因为是变量所以可以变
[root@bogon shell01]# echo $A
hello
[root@bogon shell01]# unset A 取消变量
[root@bogon shell01]# echo $A
4.变量定义的规则
虽然可以定义变量(变量名)赋予任何值;但是对于变量名字也是有要求的
1)变量名区分大小写
[root@bogon shell01]# A=hello
[root@bogon shell01]# a=world
[root@bogon shell01]# echo $A
hello
[root@bogon shell01]# echo $a
world
2)变量名不能有特殊符号
[root@bogon shell01]# *a=hello
bash: *a=hello: 未找到命令...
[root@bogon shell01]# ?a=hello
bash: ?a=hello: 未找到命令...
特别说明。对于有空格的字符串给变量时,要用引号引起来 否则shell默认会进行拆分 world则是单独的
[root@bogon shell01]# A="hello world"
[root@bogon shell01]# echo $A
hello world
3)变量名不能以数字开头
[root@bogon shell01]# 1A=hello
bash: 1A=hello: 未找到命令...
[root@bogon shell01]# A1=hello
注意:不能以数字开头不代表变量名中不能包含数字
4)等号两边不能有任何空格
[root@bogon shell01]# a= 123
bash: 123: 未找到命令...
[root@bogon shell01]# a =123
bash: a: 未找到命令...
[root@bogon shell01]# a=123
5)变量可以以_下划线开头
[root@bogon shell01]# _A=hello
[root@bogon shell01]# echo $_A
hello
6)变量名尽量做到见名知意
NTP_IP=10.1.1.1
DIR=/U01/app1
TMP_FILE=/var/log/1.log
....
说明:一般变量名使用大写(小写也可以),不要在同一个脚本中全是a,b,c等不容易阅读
5.变量的定义方式有哪些?
1)基本方式
直接复制给一个变量
[root@bogon shell01]# A=123456789
[root@bogon shell01]# echo $A
123456789
[root@bogon shell01]# echo ${A:2}
3456789
[root@bogon shell01]# echo ${A:2:3}
345
花括号是什么意思呢?
花括号是对变量进行切片的
2)命令执行结果复制给变量
[root@bogon shell01]# a=`hostname`
[root@bogon shell01]# echo $a
bogon
[root@bogon shell01]# uname -r
3.10.0-514.el7.x86_64
[root@bogon shell01]# B=$(uname -r)
[root@bogon shell01]# echo $B
3.10.0-514.el7.x86_64
#可以使用反撇号,优先执行括号里面的内容,也可以使用$()
3)交互式定义变量(read)
**目的:**让用户自己给变量赋值,比较灵活
**语法:**read [选项] 变量名
常见选项:
选项 | 释意 |
---|---|
-p | 定义提示用户的信息 |
-n | 定义字符数(限制变量值的长度) |
-s | 不显示(不显示用户输入的内容) |
-t | 定义超时时间,默认单位为秒(限制用户输入变量值的超时时间) |
举例说明:
用户自己定义变量
用法1:用户自己定义变量值
[root@bogon shell01]# read name
harry
[root@bogon shell01]# echo $name
harry
用法二:设置提示信息
[root@bogon shell01]# read -p "input you name:" name
input you name:lishuang
[root@bogon shell01]# echo $name
lishuang
用法三:设置提示信息并且不显示
[root@bogon shell01]# read -s -p "input you password:" password
input you password:
[root@bogon shell01]# echo $password
123.com
用法四:设置字符串长度
[root@bogon shell01]# read -n 9 -p "input you password:" password
input you password:tiechuito[root@bogon shell01]#
#到规定长度自动退出
用法五:设置超时时间
[root@bogon shell01]# read -t 3 -p "name:" name
name:[root@bogon shell01]#
#到规定时间自动退出 单位为s
变量值来自于文件
[root@bogon shell01]# echo '192.168.20.20' > ip.txt
[root@bogon shell01]# cat ip.txt
192.168.20.20
[root@bogon shell01]# read -p "请输入IP地址:" IP < ip.txt
[root@bogon shell01]# echo $IP
192.168.20.20
4)定义有类型的变量(declare)
**目的:**给变量做一些限制,固定变量的类型。比如:整型,只读
**用法: **declare 选项 变量名=变量值
常用选项:
选项 | 释义 | 举例 |
---|---|---|
-i | 将变量看成整数 | declare -i A=123 |
-r | 定义只读不按量 | declare -r B=hello |
-a | 定义普通数组;查看普通数组 | |
-A | 定义关联数组;查看关联数组 | |
-x | 将变量通过环境导出 | declare -x AAA=123456 等于export AAA=123456 |
举例说明:
定义变量类型
正常情况下
[root@bogon ~]# A=123
[root@bogon ~]# echo $A
123
[root@bogon ~]# A=hello
[root@bogon ~]# echo $A
hello
定义变量为整型
[root@bogon ~]# declare -i A=123
[root@bogon ~]# echo $A
123
[root@bogon ~]# A=hello
[root@bogon ~]# echo $A
0
[root@bogon ~]# A=333
[root@bogon ~]# echo $A
333
定义只读变量
[root@bogon ~]# declare -r B=hello
[root@bogon ~]# echo $B
hello
[root@bogon ~]# B=world
-bash: B: 只读变量
以上的两种方式只在当前终端生效
[root@bogon ~]# env |grep -w A
那么如果永久写入环境变量呢
[root@bogon ~]# export A=999
[root@bogon ~]# env |grep -w A
A=999
[root@bogon ~]# declare -x b=999
[root@bogon ~]# env |grep -w b
b=999
取消变量,但是不可以取消只读变量,想要取消设置只读的变量,只需要重新启动bash
[root@bogon ~]# unset A
[root@bogon ~]# env |grep -w A
六丶变量的分类
1.本地变量
-
本地变量:当前用户自定义的变量。当前进程中有效,其他进程及其子进程中无效。
举例说明:
[root@bogon ~]# AA=123 [root@bogon ~]# echo $AA 123 切换用户无效 [root@bogon ~]# su lishuang [lishuang@bogon root]$ echo $AA 原因也是因为,只对当前进程生效,切换用户之后,也就是在当前用户root之下重新开了以下bash(也就是切换用户的操作) 等同切换用户 [root@bogon ~]# bash [root@bogon ~]# ps PID TTY TIME CMD 65242 pts/1 00:00:00 bash 126175 pts/1 00:00:00 bash 126237 pts/1 00:00:00 ps [root@bogon ~]# exit exit [root@bogon ~]# ps PID TTY TIME CMD 65242 pts/1 00:00:00 bash 126393 pts/1 00:00:00 ps [root@bogon ~]#
2.环境变量
-
环境变量:当前进程有效,并且能够被子进程调用
- env查看当前用户的环境变量
- set查询当前用户的所有变量(临时变量和环境变量)
- export 变量名=变量值 或者 变量名 = 变量值; export 变量名
举例说明:
[root@bogon ~]# export A=hello
[root@bogon ~]# env| grep ^A
A=hello
切换用于依旧生效
[root@bogon ~]# su lishuang
[lishuang@bogon ~]$ env| grep ^A
A=hello
定义环境变量方法
方法一:
[root@bogon ~]# aaa=ccc
[root@bogon ~]# env | grep ^aaa
[root@bogon ~]# export aaa
[root@bogon ~]# env | grep ^aaa
aaa=ccc
方法二:
[root@bogon ~]# declare -x BBB=hahahaha
[root@bogon ~]# env | grep ^BBB
BBB=hahahaha
方法三:
[root@bogon ~]# export CCC=xixixixi
[root@bogon ~]# env | grep ^CCC
CCC=xixixixi
3.全局变量
全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用。
解读相关配置文件
文件名 | 说明 | 备注 |
---|---|---|
$HOME/.bashrc | 当前用户的bash信息,用户登陆时读取 | 定义别名 |
$HOME/.bash/profile | 当前用户的环境变量,用户登陆时读取 | |
$HOME/.bash_logout | 当前用户推出当前shell时最后读取 | 定义用户退出时执行的程序等 |
/etc/bashrc | 全局的bash信息,所有用户都生效 | |
/etc/profile | 全局环境变量 | 信息和所有用户都生效 |
$HOME/.bash_history | ||
**说明:**以上文件修改后,都需要冲洗source让其生效,或者退出重新登录
- 用户登录系统读取相关文件的顺序
- etc/profile #读取全局变量
- $HOME/.bash/profile #当前用户的环境变量
- $HOME/.bashrc #别名信息
- /etc/bashrc
- $HOME/.bash_logout
当全局变量和局部变量冲突,一般为局部变量生效
4.系统变量
- **系统变量(内置bash中变量):**shell本身已经固定好了它的名字和作用
内置变量 | 含义 |
---|---|
$? | 上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误 |
$0 | 当前执行的程序或脚本名 |
$# | 脚本后面接的参数的个数 |
$* | 脚本后面的所有参数,参数当作一个整体输出,当一个变量参数之间以空格隔开 |
$@ | 脚本后面所有参数,参数时独立的,也是全部输出 |
$1~$9 | 脚本后面的呢位置参数,$1表示第一个位置参数,以此类推 |
( 10 ) (10)~ (10) (10) | 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上括起来) |
$$ | 当前所在进程的进程号,如echo $$ |
$! | 当前运行的最后一个进程号(当前终端) |
!$ | 调用最后一条命令历史中的参数 |
举例说明:
$?判断执行结果
[root@bogon ~]# ll .bashrc
-rw-r--r--. 1 root root 176 12月 29 2013 .bashrc
[root@bogon ~]# echo $?
0
[root@bogon ~]# ll .bashr
ls: 无法访问.bashr: 没有那个文件或目录
[root@bogon ~]# echo $?
2
[root@bogon ~]# lw .bashrc
bash: lw: 未找到命令...
[root@bogon ~]# echo $?
127
言而总之 返回结果为0代表执行OK
$0当前运行脚本
[root@bogon ~]# cd /shell02/
[root@bogon shell02]# vim dollar.sh
#!/bin/bash
printf "The complete list is %s\n" "$0"
[root@bogon shell02]# bash dollar.sh
The complete list is dollar.sh
$#传参
[root@bogon shell02]# vim a.sh
#/bin/bash
hostname $1
[root@bogon shell02]# ./a.sh aa
[root@bogon shell02]# bash
[root@aa shell02]#
实例传参:
[root@aa shell02]# vim variable.sh
首先不传参
[root@aa shell02]# bash variable.sh
$0=variable.sh
$#=0
$*=
$@=
$1=
$2=
$3=
$10=
$11=
传参看一下效果
[root@aa shell02]# bash variable.sh 1 2 3
$0=variable.sh
$#=3
$*=1 2 3
$@=1 2 3
$1=1
$2=2
$3=3
$10=
$11=
[root@aa shell02]# bash variable.sh 1 2 3 4
$0=variable.sh
$#=4
$*=1 2 3 4
$@=1 2 3 4
$1=1
$2=2
$3=3
$10=
$11=
[root@aa shell02]# bash variable.sh 1 2 3 4 5 6 7 8 9 10 11
$0=variable.sh
$#=11
$*=1 2 3 4 5 6 7 8 9 10 11
$@=1 2 3 4 5 6 7 8 9 10 11
$1=1
$2=2
$3=3
$10=10
$11=11
#传参以空格分开 代表对应的参数
$$查看进程pid
[root@bogon shell02]# ps
PID TTY TIME CMD
65242 pts/1 00:00:00 bash
125622 pts/1 00:00:00 ps
[root@bogon shell02]# echo $$
65242
[root@bogon shell02]# sh
sh-4.2# ps
PID TTY TIME CMD
65242 pts/1 00:00:00 bash
125843 pts/1 00:00:00 sh
125931 pts/1 00:00:00 ps
sh-4.2# echo $$
125843
sh-4.2#
$! 查看后台运行的最后一个进程号
[root@bogon shell02]# jobs
[root@bogon shell02]# sleep 500 &
[1] 777
[root@bogon shell02]# jobs
[1]+ 运行中 sleep 500 &
[root@bogon shell02]# echo $!
777
[root@bogon shell02]# sleep 501 &
[2] 1246
[root@bogon shell02]# echo $!
1246
查看进程PID
[root@bogon shell02]# ps -ef | grep -w sleep
root 777 65242 0 18:03 pts/1 00:00:00 sleep 500
root 1246 65242 0 18:04 pts/1 00:00:00 sleep 501
!$查看最后一条命令使用的参数
[root@bogon shell02]# ls -l
总用量 12
-rwxr-xr-x. 1 root root 23 11月 17 17:40 a.sh
-rw-r--r--. 1 root root 52 11月 17 17:29 dollar.sh
-rw-r--r--. 1 root root 162 11月 17 17:52 variable.sh
[root@bogon shell02]# echo !$
echo -l
-l
七丶shell之简单四则运算
算数运算:默认情况下,shell就能支持简单的整数运算
运算内容:加(+),减(-),乘(*),除(/),求余数(%)
1.四则运算符号
表达式 | 举例 |
---|---|
$(()) | echo $((1+1)) |
$[] | echo $[10-5] |
expr | expr 10/5 |
let | n=1;let n+=1 等价于 let n=n+1 |
实例说明
[root@bogon shell02]# echo $((1+1))
2
[root@bogon shell02]# echo $[1*1]
1
取余数
[root@bogon shell02]# echo $[10%3]
1
必须空格隔开
[root@bogon shell02]# expr 10/5
10/5
[root@bogon shell02]# expr 10 / 5
2
*号特殊进行转义
[root@bogon shell02]# expr 10 * 5
expr: 语法错误
[root@bogon shell02]# expr 10 \* 5
50
let使用
[root@bogon shell02]# let n=10;let n=n+1;echo $n
11
[root@bogon shell02]# let n+=2
[root@bogon shell02]# echo $n
13
n的3次方
[root@bogon shell02]# let n=n**3
[root@bogon shell02]# echo $n
2197
那么浮点数如何运算?
利用bc工具
[root@bogon shell02]# let n=n+2
[root@bogon shell02]# echo $n
2199
[root@bogon shell02]# echo $n+1.5|bc
2200.5
2.了解i++和++i
- 对变量的值的影响
[root@bogon shell02]# i=1
[root@bogon shell02]# let i++
[root@bogon shell02]# echo $i
2
[root@bogon shell02]# let i=1;let ++i; echo $i
2
- 对表达式的值的影响
[root@bogon shell02]# unset i
[root@bogon shell02]# i=1;j=1
[root@bogon shell02]# let x=i++ 先赋值,在运算
[root@bogon shell02]# let y=++j 先运算,在赋值
[root@bogon shell02]# echo $i
2
[root@bogon shell02]# echo $j
2
[root@bogon shell02]# echo $x
1
[root@bogon shell02]# echo $y
2
先赋值,在运算根据上例的意思等同于i++=1+1
先运算,在赋值根据上例的等一等同于++j=
八丶条件判断
- 熟悉条件判断语句,如判断整数,判断字符串等
- 熟悉流程控制语句基本语法,如if…else…
1.条件判断语法结构
思考:何为真(true)?何为假(false)?(布尔值)
1.1 条件判断语法格式
- 格式1:test条件表达式
- 格式2:[ 条件表达式 ]
- 格式3:[[条件表达式]] 支持曾正则 =-
特别说明:
1)[ 两边都要加空格 ]
2)[[ 两边都要加空格 ]]
3)更多判断,man test去查看,很看的参数都用来进行条件判断
1.2 条件判断相关参数
问:你要判断什么?
答:我要判断文件类型,判断文件新旧,判断字符串是否相等,判断权限
1)判断文件类型
判断参数 | 含义 |
---|---|
-e | 判断文件是否存在(任何类型文件) |
-f | 判断文件是否存在并且是一个普通文件 |
-d | 判断文件是否存在并且是一个目录 |
-L | 判断文件是否存在并且是一个软连接文件 |
-b | 判断文件是否存在并且是一个块设备 |
-S | 判断文件是否存在并且是一个套接字文件 |
-c | 判断文件是否存在并且是一个字符设备文件 |
-p | 判断文件是否存在并且是一个命名管道文件 |
-s | 判断文件是否存在并且是一个非空文件(有内容) |
举例说明:
判断文件是否存在
[root@bogon shell02]# touch file1
[root@bogon shell02]# echo hello > file2
[root@bogon shell02]# mkdir dir1
[root@bogon shell02]# test -e ./file
file1 file2
[root@bogon shell02]# test -e ./file1
[root@bogon shell02]# echo $?
0
[root@bogon shell02]#
[root@bogon shell02]# test -e ./test1
[root@bogon shell02]# echo $?
1
判断目录是否存在
[root@bogon shell02]# [ -d dir1 ];echo $?
判断软链接文件是否存在(但是无法判断是否有效)
[root@bogon shell02]# ln -s file1 test1
[root@bogon shell02]# ll
总用量 16
-rwxr-xr-x. 1 root root 23 11月 17 17:40 a.sh
drwxr-xr-x. 2 root root 6 11月 17 19:29 dir1
-rw-r--r--. 1 root root 52 11月 17 17:29 dollar.sh
-rw-r--r--. 1 root root 0 11月 17 19:28 file1
-rw-r--r--. 1 root root 6 11月 17 19:29 file2
lrwxrwxrwx. 1 root root 5 11月 17 19:33 test1 -> file1
-rw-r--r--. 1 root root 162 11月 17 17:52 variable.sh
[root@bogon shell02]# [ -L ./test1 ]; echo $?
0
判断一个文件是否存在
[root@bogon shell02]# [[ -f ./file1 ]]; echo $?
0
判断一个文件是否不存在
[root@bogon shell02]# [ ! -f ./file1 ]; echo $?
1
[root@bogon shell02]# [ -f ./file1 ]; echo $?
0
2)判断文件权限
判断参数 | 含义 |
---|---|
-r | 当前用户对其是否可读 |
-w | 当前用户对其是否可写 |
-x | 当前用户对其是否可执行 |
-u | 是否有suid,高级权限冒险位 |
-g | 是否sgid,高级权限强制位 |
-k | 是否有T位,高级权限粘滞位 |
举例说明
判断文件权限
[root@bogon shell02]# [ -f ./file1 ]; echo $?
0
[root@bogon shell02]# test -r a.sh;echo $?
0
[root@bogon shell02]# su lishuang
[lishuang@aa shell02]$ [ -r /shell02/a.sh ]; echo $?
0
[lishuang@aa shell02]$ [ -w /shell02/a.sh ]; echo $?
1
3)判断文件新旧
说明:这里的新旧指的是文件修改时间。
判断参数 | 含义 |
---|---|
file1 -nt file2 | 比较file1文件是否比file2文件新 |
file1 -ot file2 | 比较file2文件是否比file2文件旧 |
file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬链接,是否指向同一个inode |
举例说明:
判断文件新旧
[lishuang@aa shell02]$ ll
总用量 16
-rwxr-xr-x. 1 root root 23 11月 17 17:40 a.sh
drwxr-xr-x. 2 root root 6 11月 17 19:29 dir1
-rw-r--r--. 1 root root 52 11月 17 17:29 dollar.sh
-rw-r--r--. 1 root root 0 11月 17 19:28 file1
-rw-r--r--. 1 root root 6 11月 17 19:29 file2
lrwxrwxrwx. 1 root root 5 11月 17 19:33 test1 -> file1
-rw-r--r--. 1 root root 162 11月 17 17:52 variable.sh
[lishuang@aa shell02]$ test file1 -nt file2;echo $?
1
[lishuang@aa shell02]$ test file1 -ot file2;echo $?
0
判断文件是否相同
[root@bogon shell02]# diff -uN file1 file2 > file.patch
[root@bogon shell02]# patch file1 file.patch
patching file file1
[root@bogon shell02]# cat file1
hello
[root@bogon shell02]# cat file2
hello
[root@bogon shell02]# [ file1 -ef file2 ];echo $?
1
相同为1 不相同为0
4)判断整数
判断参数 | 含义 |
---|---|
-eq | 相等 |
-ne | 不等 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
实例说明:
[root@bogon shell02]# [ 1 -eq 2 ];echo $?
1
[root@bogon shell02]# [ 1 -eq 1 ];echo $?
0
5)判断字符串
判断参数 | 含义 |
---|---|
-z | 判断是否为空字符串,字符串长度为0则成立 |
-n | 判断是否为非空字符串,字符串长度不为0则成立 |
string1 = string2 | 判断字符串是否相等 |
string1 != string | 判断字符串是否不相等 |
实例说明:
判断字符串为空
[root@bogon shell02]# test -z "hello world"; echo $?
1
判断字符串为非空
[root@bogon shell02]# test -n "hello world"; echo $?
0
注意的是空格tab也算字符
[root@bogon shell02]# test -n " "; echo $?
0
[root@bogon shell02]# test -n ""; echo $?
1
判断字符串是否相等
[root@bogon shell02]# test "hello" = "world";echo $?
1
[root@bogon shell02]# test "hello" = "hello";echo $?
0
[root@bogon shell02]# test "hello" != "hello";echo $?
1
6)多重条件判断
判断符号 | 含义 | 举例 |
---|---|---|
-a 和 && | 逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ];echo $? [ 1 -eq 1 ] && [ 1 -ne 0 ];echo $? |
-o 和 || | 逻辑或 | [ 1 -eq 1 -o 1 -ne 1 ];echo $? [ 1 -eq 1 ] || [ 1 -eq 2 ];echo $? |
特别说明
- && 前面的表达式为真,才会执行后面的代码
- || 前面的表达式为假,才会执行后面的代码
- ;只用于分割命令或表达式
举例说明
-
数值比较
判断当前用户是否为root用户 [root@bogon shell02]# [ $(id -u) -eq 0 ] && echo "the user is root" the user is root [root@bogon shell02]# [ $(id -u) -ne 0 ] && echo "the user is not root" [root@bogon shell02]# [ $(id -u) -ne 0 ] && echo "the user is not root" || echo "the user is root" the user is root [root@bogon shell02]# test $uid -eq 0 && echo 'this is admin' this is admin [root@bogon shell02]# test $uid -ne 0 && echo 'this is admin' [root@bogon shell02]# test $uid -ne 0 && echo 'this is not admin' || echo this is admin this is admin
-
类C风格的数值比较
注意: 在(( ))中,=表示赋值,==表示判断
[root@bogon shell02]# ((`id -u`==0)) && echo 'the user is root' || echo 'the user is not root'
the user is root
7)判断符号[]和[[]]的区别
https://blog.csdn.net/whatday/article/details/85028898/具体参考这篇文档
字符串判断需要加双引号
[root@bogon ~]# A=
[root@bogon ~]# echo $A
[root@bogon ~]# test $A = hello
-bash: test: =: 期待一元表达式
[root@bogon ~]# test "$A" = "hello"
[root@bogon ~]# echo $?
1
[root@bogon ~]# [ "$A"="hello" ];echo $?
0
[root@bogon ~]# [ "$A" = "hello" ];echo $?
1
如果是空字符串匹配则双中括号则OK
[root@bogon ~]# [[ $A = hello ]];echo $?
1
[root@bogon ~]# A="abc"
[root@bogon ~]# [[ $A = hello ]];echo $?
1
[root@bogon ~]# [[ $A = abc ]];echo $?
0
判断软链接文件
[root@bogon ~]# mkdir file1
[root@bogon ~]# cd file1/
[root@bogon file1]# touch file{1,2}.txt
[root@bogon file1]# ln -s file1.txt test.txt
[root@bogon file1]# ln -s file2.txt test2.txt
[root@bogon file1]# ll
总用量 0
-rw-r--r--. 1 root root 0 11月 19 21:38 file1.txt
-rw-r--r--. 1 root root 0 11月 19 21:38 file2.txt
lrwxrwxrwx. 1 root root 9 11月 19 21:41 test2.txt -> file2.txt
lrwxrwxrwx. 1 root root 9 11月 19 21:39 test.txt -> file1.txt
软连接是根据源文件的,那么把原文件删除掉,这就是一个坏掉的链接了
[root@bogon file1]# rm -rf file1.txt
[root@bogon file1]# ll
总用量 0
-rw-r--r--. 1 root root 0 11月 19 21:38 file2.txt
lrwxrwxrwx. 1 root root 9 11月 19 21:41 test2.txt -> file2.txt
lrwxrwxrwx. 1 root root 9 11月 19 21:39 test.txt -> file1.txt
[root@bogon file1]# cat test.txt
cat: test.txt: 没有那个文件或目录
那么根据这点的话旧很好判断了,我们首先去判断是否为一个文件,再去判断是否为链接文件,这样的话就可以得到是否为一个好的链接了
第一种
[root@bogon file1]# [ -e test.txt -a -L test.txt ]; echo $?
1
[root@bogon file1]# [ -e test2.txt -a -L test2.txt ]; echo $?
0
第二种
[root@bogon file1]# [ -e test2.txt ] && [ -L test2.txt ]; echo $?
0
[root@bogon file1]# [ -e test.txt ] && [ -L test.txt ]; echo $?
1
第三种
[root@bogon file1]# [[ -e test2.txt && -L test2.txt ]]; echo $?
0
[root@bogon file1]# [[ -e test.txt && -L test.txt ]]; echo $?
1
当然还有很多种,test方法都还没用
1.3逻辑运算符总结
1.符号;和&&和||都可以用来分割命令或者表达式
2.分号(;)完全不考虑前面的语句是否正确执行,都会执行;后面的内容
3.&&符号,都需要&&前面的语句的正确性,前面语句正确执行才会执行&&后的内容;反之亦然
4.||符号,需要||前面的语句的非正确性,前面语句执行错误才会执行||后面的内容;反之亦然
5.如果&&和||一起出现,从左往右一次看,按照以上原则
语法结构:
1.test expr1
2.[ expr1 ]
3.[[ expr1 ]]
以及条件判断选项
-eq判断整数是否相等 -ef表示查看文件内容是否相同
利用man test命令可以学习到更多
比如 -s判断文件存在并且是否不为空 !-s则表示文件存在是否为空
2.流程控制语句
关键词:选择
2.1基本语法结构
1)if结构
F:为false,为假
T:表示true,为真
1.
if [ conditon ];then
command
command
fi
2.
if test 条件;then
命令
fi
3.
if [[]];then
命令
fi
4.
[ 条件 ] && cmmand
[root@bogon file1]# if [ 1 -eq 1 ];then echo hello;fi
hello
2)if…else结构
if [ condition ];then
command1
else
command2
fi
[ 条件 ] && command1 || command2
也就是条件满足则执行什么 条件不满足则执行什么
[root@bogon file1]# if [ 1 -ne 1 ];then echo hello;else echo world;fi
world
[root@bogon file1]# vim test.sh
#!/bin/env bash
#.....
if [ "$1" = "hello" ];then
echo world
else
echo hello
fi
[root@bogon file1]# chmod +x test.sh
[root@bogon file1]# ./test.sh
hello
[root@bogon file1]# ./test.sh hello
world
尝试以下 让用户自己输入字符串,如果用户输入的是hello,打印出world
[root@bogon file1]# vim test1.sh
#!/bin/bash
read -p "请输入一个字符串" str;
if [ "$str" = "hello" ];then
echo world
else
echo "匹配不正确"
fi
[root@bogon file1]# chmod +x test1.sh
[root@bogon file1]# ./test1.sh
请输入一个字符串hello
world
3)if双分支语句
if [ condition1 ];then
command1 结束
elif [ condition2];then
command2 结束
else
command3
fi
注释:
如果条件1满足,执行妙命令1后结束;如果条件1不满足,再看条件2,如果条件2满足则执行条件2,如果条件1和条件2都不满足执行命令3结束;
实例练习:
[root@bogon file1]# vim test2.sh
#/bin/bash
read -p "请输入一个数字:" num;
if [ $num -lt 100 ];then
echo "这个数字小于100"
elif [ $num -eq 100 ];then
echo "这个数字等于100"
else
echo "这个数字大于100"
fi
[root@bogon file1]# chmod +x test2.sh
[root@bogon file1]# ./test2.sh
请输入一个数字:100
这个数字等于100
[root@bogon file1]# ./test2.sh
请输入一个数字:99
这个数字小于100
[root@bogon file1]# ./test2.sh
请输入一个数字:101
这个数字大于100
4)if层层嵌套结构
if [ condition1 ];then
command1
if [ comdition2 ];then
command2
fi
else
if [ comdition3 ];then
command3
elif [ comditon4 ];then
command4
else
command5
fi
fi
如果条件1满足,执行命令1,如果条件2也满足执行命令2,如果不满足就只执行命令1结束;
如果条件1不满足,不看条件2,直接看条件3,如果条件3满足执行命令3;如果不满足则看条件4;否则执行命令5
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UyyMqR4L-1606469552707)(C:\Users\48220\AppData\Roaming\Typora\typora-user-images\image-20201121135544451.png)]
5)if应用案例
1.判断两台主机是否ping通
**需要:**判断当前主机是否和远程主机是否ping通
1.1 思路
- 使用哪个命令实现(ping命令 -c次数)
- 根据命令的执行结果状态来判断是否通($?)
- 根据逻辑和语法结构来编写脚本(条件判断或流程控制)
1.2 落地实现
[root@bogon file1]# cat test3.sh
#!/bin/bash
read -p "请输入您要ping的主机:" IP;
ping -c1 $IP &> /dev/null
if [ $? -eq 0 ];then
echo "此主机和$IP可以ping通"
else
echo "此主机不能和$IPping通"
fi
[root@bogon file1]# chmod +x test3.sh
[root@bogon file1]# ./test3.sh
请输入您要ping的主机:192.168.20.1
此主机不能和通
[root@bogon file1]# ./test3.sh
请输入您要ping的主机:www.baidu.com
此主机和www.baidu.com可以ping通
2.判断一个服务是否正常
**需求:**判断门户网站是否能够正常访问
2.1思路
-
可以判断进程是否存在,用/etc/init.d/httpd status 判断状态等方法
-
判断最好的访问是去直接访问以下,通过访问成功和失败的返回值来判断
三个命令elinks curl wget
[root@bogon ~]# yum -y install httpd
[root@bogon ~]# systemctl start httpd
[root@bogon ~]# curl 127.0.0.1
[root@bogon file1]# vim test4.sh
#!/bin/bash
#
#
web_server=192.168.20.20
curl $web_server &> /dev/null
[ $? -eq 0 ] && echo '当前网站服务OK' || echo '当前服务网站不ok,请立刻处理'
[root@bogon file1]# mkdir html
[root@bogon file1]# vim test4.sh
#!/bin/bash
#
#
web_server=www.baidu.com
wget -P html\ $web_server &> /dev/null
[ $? -eq 0 ] && echo '当前网站服务OK' && rm -rf html\ /index.* || echo '当前服务网站不ok,请立刻处理'
3.判断用户是否存在
**需求:**输入一个用户 判断是否存在,没有则创建
[root@bogon file1]# vim test5.sh
#!/bin/bash
read -p "请输入用户名:" user_name
id $user_name &> /dev/null
if [ $? = 0 ];then
echo "用户以存在"
else
echo "用户不存在" && useradd $user_name
fi
[root@bogon file1]# chmod +x test5.sh
[root@bogon file1]# ./test5.sh
请输入用户名:lishuang
用户以存在
[root@bogon file1]# ./test5.sh
请输入用户名:root
用户以存在
[root@bogon file1]# ./test5.sh
请输入用户名:aaa
用户不存在
[root@bogon file1]# cat /etc/passwd | tail -1
aaa:x:1003:1003::/home/aaa:/bin/bash
6)总结流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p77zXK4x-1606469552708)(C:\Users\48220\AppData\Roaming\Typora\typora-user-images\image-20201124222800848.png)]
九丶for循环语句
for循环语法结构
1.列表循环
列表for循环;用户将一组命令执行已知的次数
-
基本语法格式
for variable in {list} do command command done 或者 for variabel in a b c do command command done
实例练习
[root@bogon file1]# vim for1.sh #!/bin/bash for i in {1..5} do echo "$i" done [root@bogon file1]# chmod +x for1.sh [root@bogon file1]# ./for1.sh 1 2 3 4
[root@bogon file1]# vim for1.sh
#!/bin/bash
for i in {1..5}
do
echo hello
done
[root@bogon file1]# ./for1.sh
hello
hello
hello
hello
hello
[root@bogon file1]# cat for1.sh
#!/bin/bash
for i in a b c d e
do
echo $i
done
[root@bogon file1]# ./for1.sh
a
b
c
d
e
打印偶数
[root@bogon file1]# vim ./for1.sh
#!/bin/bash
for i in {0..50..2}
do
echo $i
done
[root@bogon file1]# ./for1.sh
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
50
seq
[root@bogon file1]# seq 10
1
2
3
4
5
6
7
8
9
10
[root@bogon file1]# vim for1.sh
#!/bin/bash
for i in $(seq 10)
do
echo $i
done
[root@bogon file1]# ./for1.sh
1
2
3
4
5
6
7
8
9
10
倒数打印数字
[root@bogon file1]# for i in {10..1};do echo $i ; done
10
9
8
7
6
5
4
3
2
1
[root@bogon file1]# for i in {10..1..-1};do echo $i ; done
10
9
8
7
6
5
4
3
2
1
[root@bogon file1]# seq 10 -1 1
10
9
8
7
6
5
4
3
2
1
seq打印奇数
[root@bogon file1]# seq 1 10
1
2
3
4
5
6
7
8
9
10
[root@bogon file1]# seq 1 1 10
1
2
3
4
5
6
7
8
9
10
[root@bogon file1]# seq 1 2 10
1
3
5
7
9
2.不带列表循环
不带列表的for循环执行时由用户指定参数和参数的个数
-
基本语法格式
for variable do command command done
-
举例说明
[root@bogon file1]# vim for2.sh [root@bogon file1]# chmod +x for2.sh [root@bogon file1]# ./for2.sh [root@bogon file1]# 传入参数 [root@bogon file1]# ./for2.sh 1 2 3 4 5 hello hello hello hello hello
3.类C风格的for循环
-
基本语法结构
for (( expr1;expr2;expr3 )) do command command .... done for (( i=1;i<=5;i++ )) do echo $u done expr1:定义变量并赋初值 expr2:决定是否进行循环(条件) expr3:决定循环变量如何改变,决定循环什么时退出
实例练习
[root@bogon ~]# for (( i=1;i<=10;i++));do echo $i;done 1 2 3 4 5 6 7 8 9 10 打印偶数 [root@bogon ~]# for (( i=1;i<=10;i+=2));do echo $i;done 1 3 5 7 9
4.应用案例
(一)脚本计算1-100奇数和
思路:
-
定义一个变量来保存奇数的和
-
找出1-100的奇数,保存到另一个变量里
-
从1-100中找出奇数后,在相加,然后将和赋值给变量
-
遍历完毕后,将sum的值打印出来
方法一:
[root@bogon file1]# vim for3.sh
#!/bin/bash
sum=0
for (( i=1;i<=100;i=i+2 ))
do
let sum=$sum+$i
done
if [ $? -eq 0 ];then
echo $sum
fi
[root@bogon file1]# ./for3.sh
2500
方法二:
可能会看不懂,这种方法时首先打印出1-100的所有数字,然后去判断1-100除2取余,如果不等于0则打印出来,然后在进行计算
[root@bogon file1]# vim for4.sh
[root@bogon file1]# chmod +x for4.sh
#!/bin/bash
sum=0
for (( i=1;i<=100;i++ ))
do
if [ $[$i%2] -ne 0 ];then
let sum=$sum+$i
fi
done
echo $sum
~
[root@bogon file1]# ./for4.sh
2500
方法三:
#!/bin/bash
sum=0
for (( i=1;i<=100;i++ ))
do
if [ $[$i%2] -eq 0 ];then
continue ##跳出循环,直接下一个循环
else
let sum=$sum+$i
fi
done
echo "1-100的奇数和为:$sum"
或者
#!/bin/bash
sum=0
for (( i=1;i<=100;i++ ))
do
test $[$i%2] -eq 0 && continue || let sum=$sum+$i
done
echo "1-100的奇数和为:$sum"
循环控制语句
循环体: do…done之间的内容
- continue:继续,表示循环体内的下面的代码不执行,重新开始下一次循环
- break:打断,马上停止执行本次循环没执行循环体后面的代码
- exit:表示直接跳出程序
实例练习:
1.break
break 当$i=3的时候,直接退出循环
[root@bogon file1]# cat for6.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
test $i -eq 3 && break || touch /tmp/file$i
done
echo hello
[root@bogon file1]# ./for6.sh
hello
[root@bogon file1]# ll /tmp/
总用量 1960
-rw-r--r--. 1 root root 0 11月 25 17:55 file1
-rw-r--r--. 1 root root 0 11月 25 17:55 file2
2.continue
continue 当i=3的时候,则跳过,继续直接下个循环语句
[root@bogon file1]# cat for6.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
test $i -eq 3 && continue || touch /tmp/file$i
done
echo hello
[root@bogon file1]# ./for6.sh
hello
[root@bogon file1]# ll /tmp/
总用量 1960
-rw-r--r--. 1 root root 0 11月 25 17:59 file1
-rw-r--r--. 1 root root 0 11月 25 17:59 file2
-rw-r--r--. 1 root root 0 11月 25 17:59 file4
-rw-r--r--. 1 root root 0 11月 25 17:59 file5
3.exit
当满足条件i=3的时候会直接退出脚本
[root@bogon file1]# cat for6.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
test $i -eq 3 && exit || touch /tmp/file$i
done
echo hello
[root@bogon file1]# ./for6.sh
[root@bogon file1]# ll /tmp/
总用量 1960
-rw-r--r--. 1 root root 0 11月 25 18:05 file1
-rw-r--r--. 1 root root 0 11月 25 18:05 file2
㈡ 判断所输整数是否为质数
质数(素数):只能被1和它本身整除的数叫质数。
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
思路
- 让用户输入一个数,保存到一个变量里
read -p "请输入一个正整数:" num
- 如果能被其他数整除就不是质数——>
$num%$i
是否等于0$i=2到$num-1
- 如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
- 测试序列从2开始,输入的数是4——>得出结果
$num
不能和$i
相等,并且$num
不能小于$i
实现
#!/bin/env bash
#定义变量来保存用户所输入数字
read -p "请输入一个正整数字:" number
#先排除用户输入的数字1和2
[ $number -eq 1 ] && echo "$number不是质数" && exit
[ $number -eq 2 ] && echo "$number是质数" && exit
#循环判断用户所输入的数字是否质数
#seq 2 $[$number-1] 四则运算,seq打印除从2到$number-1的序列
for i in `seq 2 $[$number-1]`
do
[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exit
done
echo "$number是质数"
优化思路:没有必要全部产生2~$[$number-1]序列,只需要产生一半即可。
更好解决办法:类C风格完美避开了生成序列的坑
for (( i=2;i<=$[$number-1];i++))
do
[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exit
done
echo "$number是质数"
(三) 判断所输整数是否为质数
需求:**批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123
思路
- 添加用户的命令
useradd -G class
- 判断class组是否存在
grep -w ^class /etc/group
或者groupadd class
- 根据题意,判断该脚本循环5次来添加用户
for
- 给用户设置密码,应该放到循环体里面
实现
[root@localhost file1]# vim for8.sh
#!/bin/env bash
#首先去查看是否由class组
grep -w ^class /etc/group
if [ $? -ne 0 ];then
groupadd class
fi
#创建用户
for ((i=1;i<=5;i++))
do
useradd -G class u$i
echo "成功创建用户u$i"
echo 123.com | passwd --stdin u$i
done
[root@localhost file1]# chmod +x for8.sh
[root@localhost file1]# ./for8.sh
class:x:1004:
成功创建用户u1
更改用户 u1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
成功创建用户u2
更改用户 u2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
成功创建用户u3
更改用户 u3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
成功创建用户u4
更改用户 u4 的密码 。
passwd:所有的身份验证令牌已经成功更新。
成功创建用户u5
更改用户 u5 的密码 。
passwd:所有的身份验证令牌已经成功更新。
方法一:
#!/bin/bash
#判断class组是否存在
grep -w class /etc/group &>/dev/null
[ $? -ne 0 ] && groupadd class
#批量创建5个用户
for i in {1..5}
do
useradd -G class u$i
echo 123|passwd --stdin u$i
done
方法二:
#!/bin/bash
#判断class组是否存在
cut -d: -f1 /etc/group|grep -w class &>/dev/null
[ $? -ne 0 ] && groupadd class
#循环增加用户,循环次数5次,for循环,给用户设定密码
for ((i=1;i<=5;i++))
do
useradd u$i -G class
echo 123|passwd --stdin u$i
done
方法三:
#!/bin/bash
grep -w class /etc/group &>/dev/null
test $? -ne 0 && groupadd class
或者
groupadd class &>/dev/null
for ((i=1;i<=5;i++))
do
useradd -G class u$i && echo 123|passwd --stdin u$i
done
(四)局域网内脚笨检查主机网络通讯
需求
写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
以192.168.20.0网段为例子,只有192.168.20.2网关能够ping通
#!/bin/bash
for ((i=1;i<=254;i++))
do
ping -c1 192.168.20.$i &>/dev/null
if [ $? -eq 0 ];then
echo "192.168.20.$i,OK" >> /tmp/file1.txt
else
echo "192.168.20.$i,DOWN" >> /tmp/file2.txt
fi
done
[root@localhost file1]# grep -w 192.168.20.2 /tmp/file1.txt
192.168.20.2,OK
Linux time命令的用途,在于量测特定指令执行时所需消耗的时间及系统资源等资讯
执行的很慢 [root@localhost file1]# time ./for9.sh 简化简本执行
延伸扩展:shell脚本并发
并行执行:
{程序}&表示将程序放到后台并行执行,如果需要等待程序执行完毕再进行下面内容,需要加wait
#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
do
{
ping -c1 $ip.$i &>/dev/null
if [ $? -eq 0 ];then
echo "$ip.$i is ok" >> /tmp/ip_up.txt
else
echo "$ip.$i is down" >> /tmp/ip_down.txt
fi
}&
done
wait
echo "ip is ok...."
[root@server ~]# time ./ping.sh
ip is ok...
real 0m3.091s
user 0m0.001s
sys 0m0.008s
(五) 判断闰年
需求3:
输入一个年份,判断是否是润年(能被4整除但不能被100整除,或能被400整除的年份即为闰年)
#!/bin/bash
read -p "Please input year:(2017)" year
if [ $[$year%4] -eq 0 -a $[$year%100] -ne 0 ];then
echo "$year is leap year"
elif [ $[$year%400] -eq 0 ];then
echo "$year is leap year"
else
echo "$year is not leap year"
fi
总结
- FOR循环语法结构
- FOR循环可以结合条件判断和流程控制语句
- do …done 循环体
- 循环体里可以是命令集合,再加上条件判断以及流程控制
- 控制循环语句
- continue 继续,跳过本次循环,继续下一次循环
- break 打断,跳出循环,执行循环体外的代码
- exit 退出,直接退出程序
十丶while循环语句
特点:条件为真就进入循环;条件为假就退出循环
##1. while循环语法结构
while 表达式
do
command...
done
while [ 1 -eq 1 ] 或者 (( 1 > 2 ))
do
command
command
...
done
循环打印1-5数字
FOR循环打印:
for ((i=1;i<=5;i++))
do
echo $i
done
while循环打印:
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
应用案例
(一)打印出1-100偶数的和
for
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
do
let sum=$sum+$i
done
echo "$sum"
while
#!/bin/bash
#定义变量
sum=0
i=2
#循环打印1-50的偶数和并且计算后重新赋值给sum
while [ $i -le 50 ]
do
let sum=$sum+$i
let i+=2
done
#打印sum的值
echo "1-50的偶数和为:$sum"
Linux服务器运行久时,系统时间就会存在一定的误差,一般情况下可以使用date命令进行时间设置,但在做数据库集群分片等操作时对多台机器的时间差是有要求的,此时就需要使用ntpdate进行时间同步
26 Nov 17:41:40 ntpdate[112842]: no server suitable for synchronization found
遇到这种报错,请放行123端口
[root@localhost file1]# firewall-cmd --add-port=123/tcp
success
[root@localhost file1]# ntpdate -u time.nist.gov
26 Nov 17:45:00 ntpdate[116834]: adjust time server 132.163.97.6 offset -0.019218 sec
[root@localhost file1]# date +%Y:%m:%d-%H:%M:%S
2020:11:26-17:56:49
[root@localhost file1]# date +%Y:%m:%d-%H:%M:%S
2020:11:26-17:56:49
(二)脚本同步系统时间
具体要求
- 写一个脚本,30秒同步一次系统时间,时间同步服务器10.1.1.1
- 如果同步失败,则进行邮件报警,每次失败都报警
- 如果同步成功,也进行邮件通知,但是成功100次才通知一次
思路
-
每隔30s同步一次时间,该脚本是一个死循环 while 循环
-
同步失败发送邮件 1) ntpdate 10.1.1.1 2) rdate -s 10.1.1.1
-
同步成功100次发送邮件 定义变量保存成功次数
实现
#!/bin/env bash
# 该脚本用于时间同步
NTP=NTP=time.nist.gov
count=0
while true
do
ntpdate $NTP &>/dev/null
if [ $? -ne 0 ];then
echo "system date failed" |mail -s "check system date" root@localhost
else
let count++
if [ $count -eq 100 ];then
echo "systemc date success" |mail -s "check system date" root@localhost && count=0
fi
fi
sleep 30
done
#!/bin/bash
#定义变量
count=0
NTP=time.nist.gov
while true
do
rdate -s $ntp-server &>/dev/null
if [ $? -ne 0 ];then
echo "system date failed" |mail -s 'check system date' root@localhost
else
let count++
if [ $[$count%100] -eq 0 ];then
echo "system date successfull" |mail -s 'check system date' root@localhost && count=0
fi
fi
sleep 3
done
十一丶 until语法结构
until expression [ 1 -eq 1 ] (( 1 >= 1 ))
do
command
command
...
done
打印1-5数字
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
i=1
until [ $i -gt 5 ]
do
echo $i
let i++
done
应用案例
###㈠ 具体需求
- 使用until语句批量创建10个用户,要求stu1—stu5用户的UID分别为1001—1005;
- stu6~stu10用户的家目录分别在/rhome/stu6—/rhome/stu10
㈡ 思路
- 创建用户语句
useradd -u|useradd -d
- 使用循环语句(until)批量创建用户
until循环语句结构
- 判断用户前5个和后5个
条件判断语句
㈢ 落地实现
#!/bin/env bash
if [ -d /rhome ];then
echo "/rhome目录已存在"
else
mkdir /rhome
echo "/rhome不存在,已完成创建"
fi
i=1
until [ $i -gt 10 ]
do
if [ $i -le 5 ];then
useradd -u $[1000+$i] stu$i
echo 123|passwd --stdin stu$i
else
useradd -d /rhome/stu$i stu$i
echo 123|passwd --stdin stu$i
fi
let i++
done
==================================================
#!/bin/bash
i=1
until [ $i -gt 10 ]
do
if [ $i -le 5 ];then
useradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$i
else
[ ! -d /rhome ] && mkdir /rhome
useradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i
fi
let i++
done
总结
- FOR循环语法结构
- FOR循环可以结合==条件判断和流程控制语句==
- do ......done 循环体
- 循环体里可以是命令集合,再加上条件判断以及流程控制
- 控制循环语句
- continue 继续,跳过本次循环,继续下一次循环
- break 打断,跳出循环,==执行==循环体外的代码
- exit 退出,直接退出程序
# 十丶while循环语句
**特点:**==条件为真就进入循环;条件为假就退出循环==
##1. while循环语法结构
```powershell
while 表达式
do
command...
done
while [ 1 -eq 1 ] 或者 (( 1 > 2 ))
do
command
command
...
done
循环打印1-5数字
FOR循环打印:
for ((i=1;i<=5;i++))
do
echo $i
done
while循环打印:
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
应用案例
(一)打印出1-100偶数的和
for
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
do
let sum=$sum+$i
done
echo "$sum"
while
#!/bin/bash
#定义变量
sum=0
i=2
#循环打印1-50的偶数和并且计算后重新赋值给sum
while [ $i -le 50 ]
do
let sum=$sum+$i
let i+=2
done
#打印sum的值
echo "1-50的偶数和为:$sum"
Linux服务器运行久时,系统时间就会存在一定的误差,一般情况下可以使用date命令进行时间设置,但在做数据库集群分片等操作时对多台机器的时间差是有要求的,此时就需要使用ntpdate进行时间同步
26 Nov 17:41:40 ntpdate[112842]: no server suitable for synchronization found
遇到这种报错,请放行123端口
[root@localhost file1]# firewall-cmd --add-port=123/tcp
success
[root@localhost file1]# ntpdate -u time.nist.gov
26 Nov 17:45:00 ntpdate[116834]: adjust time server 132.163.97.6 offset -0.019218 sec
[root@localhost file1]# date +%Y:%m:%d-%H:%M:%S
2020:11:26-17:56:49
[root@localhost file1]# date +%Y:%m:%d-%H:%M:%S
2020:11:26-17:56:49
(二)脚本同步系统时间
具体要求
- 写一个脚本,30秒同步一次系统时间,时间同步服务器10.1.1.1
- 如果同步失败,则进行邮件报警,每次失败都报警
- 如果同步成功,也进行邮件通知,但是成功100次才通知一次
思路
-
每隔30s同步一次时间,该脚本是一个死循环 while 循环
-
同步失败发送邮件 1) ntpdate 10.1.1.1 2) rdate -s 10.1.1.1
-
同步成功100次发送邮件 定义变量保存成功次数
实现
#!/bin/env bash
# 该脚本用于时间同步
NTP=NTP=time.nist.gov
count=0
while true
do
ntpdate $NTP &>/dev/null
if [ $? -ne 0 ];then
echo "system date failed" |mail -s "check system date" root@localhost
else
let count++
if [ $count -eq 100 ];then
echo "systemc date success" |mail -s "check system date" root@localhost && count=0
fi
fi
sleep 30
done
#!/bin/bash
#定义变量
count=0
NTP=time.nist.gov
while true
do
rdate -s $ntp-server &>/dev/null
if [ $? -ne 0 ];then
echo "system date failed" |mail -s 'check system date' root@localhost
else
let count++
if [ $[$count%100] -eq 0 ];then
echo "system date successfull" |mail -s 'check system date' root@localhost && count=0
fi
fi
sleep 3
done
十一丶 until语法结构
until expression [ 1 -eq 1 ] (( 1 >= 1 ))
do
command
command
...
done
打印1-5数字
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
i=1
until [ $i -gt 5 ]
do
echo $i
let i++
done
应用案例
###㈠ 具体需求
- 使用until语句批量创建10个用户,要求stu1—stu5用户的UID分别为1001—1005;
- stu6~stu10用户的家目录分别在/rhome/stu6—/rhome/stu10
㈡ 思路
- 创建用户语句
useradd -u|useradd -d
- 使用循环语句(until)批量创建用户
until循环语句结构
- 判断用户前5个和后5个
条件判断语句
㈢ 落地实现
#!/bin/env bash
if [ -d /rhome ];then
echo "/rhome目录已存在"
else
mkdir /rhome
echo "/rhome不存在,已完成创建"
fi
i=1
until [ $i -gt 10 ]
do
if [ $i -le 5 ];then
useradd -u $[1000+$i] stu$i
echo 123|passwd --stdin stu$i
else
useradd -d /rhome/stu$i stu$i
echo 123|passwd --stdin stu$i
fi
let i++
done
==================================================
#!/bin/bash
i=1
until [ $i -gt 10 ]
do
if [ $i -le 5 ];then
useradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$i
else
[ ! -d /rhome ] && mkdir /rhome
useradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i
fi
let i++
done