grep是行过滤工具,用于根据关键字进行行过滤
语法:
# grep [选项] '关键字' 文件名
常用选项:
OPTIONS:
-i:不区分大小写
-v:查找不包含指定的内容的行,反向选择
-w:按单词搜索
-o:打印匹配到的次数
-c:统计匹配到的次数
-n:显示行号
-r:逐层遍历目录查找
-A:显示匹配行及后面多少行
-B:显示匹配行及前面多少行
-C:显示匹配行前后多少行
-l:只列出匹配的文件名
-L:列出不匹配的文件名
-e:使用正则匹配
-E:使用扩展正则匹配
^key:以关键字开头
key$:以什么关键字结尾
^$:匹配空行
--color=auto:可以将找到的关键词部分加上颜色的显示
颜色设置(别名设置):
临时设置:
alias grep='grep --color=auto'
永久设置:
修改配置文件/etc/bashrc,在最后面添加alias grep='grep --color=auto',最后刷新,source /etc/bashrc
cut是列截取工具,由于列的截取
语法:
# cut 选项 文件名
常用选项:
-c:以字符为单位进行分割,截取
-d:自定义分隔符,分隔符\t
-f:与-d一起使用,指定截取哪个区域
-c:以字符为单位进行分割,截取
实例:
[root@localhost hua]# cut -c1-5 passwd |head
root:
bin:x
daemo
adm:x
lp:x:
sync:
shutd
halt:
mail:
opera
-d:自定义分隔符,默认为制表符\t
-f:与-d一起使用,指定截取哪个区域
实例:
[root@localhost hua]# cut -d: -f1,7 passwd |head
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
sort工具用于排序,他将文件的每一行作为一个单位,从首字符向后,一次按ASCII码值进行比较,最后将他们按升序输出。
语法和选项
-u:去除重复行
-r:降序排列,默认是升序
-o:将排序结果输出到文件中,类似重定向符号>
-n:以数字排序,默认是按字符排序
-t:分隔符
-k:第N列
-b:忽略前导空格
-R:随机排序,每次运行的结果均不同
范例:
#1、先把passwd前面10行重定向到1.txt
#2、以数字降序排序,指定分隔符,第三列,重定向到2.txt
sort -nr -t: -k3 1.txt -o 2.txt
uniq用于去除连续的重复行
选项:
-i:忽略大小写
-c:统计重复行次数
-d:只显示重复行
去除重复行sort -u和uniq的区别:
- 对文本重复行进行统计个数
# 先排序,去掉相邻的重复行,然后统计重复行个数
sort 1.txt |uniq -c
- 对文本重复行次数进行排序
# sort -n可以识别每行开头的数字,并按其大小进行排序,降序加个r
sort 1.txt |uniq -c|sort -nr
- 对重复行去重
sort phonenum.txt |uniq -c |sort -nr |awk '{print $2}'>p.txt #去重后保留
tee工具时从标准输入读取并写入到标准输出和文件,即:双向覆盖重定向(屏幕输出|文本输入)
# 取出除了#开头的行内容,和取出除掉空行的行,然后输入到一个文件,相当于备份修改的内容
[root@localhost hua]# grep -v '^#' 1.txt | grep -v '^$' |tee -a beifen.txt
3 4 5
7 8 9
9 7 6
diff工具用于逐行比较文件的不同
注意:diff描述两个文件不同的方式是告诉我们怎么改变第一个文件之后与第二个文件匹配
语法和选项:
语法:
diff [选项] 文件1 文件2
选项:
选项 | 含义 | 备注 |
---|---|---|
-b | 不检查空格 | |
-B | 不检查空白行 | |
-i | 不检查大小写 | |
-w | 忽略所有的空格 | |
–normal | 正常格式显示(默认) | |
-c | 上下问格式显示 | |
-u | 合并格式显示 |
# 1、显示结果是1.txt怎么样改变才可以和2.txt相同
# 2、
[root@localhost hua]# cat -n 1.txt
1 aaaa
2 111
3 hello world
4 222
5 333
6 bbb
[root@localhost hua]# cat -n 2.txt
1 aaa
2 hello
3 111
4 222
5 bbb
6 333
[root@localhost hua]# diff 1.txt 2.txt
1c1,2 第一个文件的第1行需要改变(c=change)才能和第二个文件的第1到2行匹配
< aaaa 小于号“<”表示左边文件(file1)文件内容
--- 表示分隔符
> aaa 大于号“>”表示右边文件(file2)文件内容
> hello
3d3 第一个文件的第3行删除(d=delete)后才能和第二个文件的第3行匹配
< hello world
5d4 第一个文件的第5行删除后才能和第二个文件的第4行匹配
< 333
6a6 第一个文件的第6行(a=add)内容后才能和第二个文件的第6行匹配
> 333 需要增减的内容在第二个文件的333
[root@localhost hua]# diff -c 1.txt 2.txt
*** 1.txt 2021-04-21 00:28:21.999376943 +0800
--- 2.txt 2021-04-21 00:28:43.802577665 +0800
***************
*** 1,6 **** 以***开头表示file1文件,1,6表示1到6行
! aaaa !表示该行需要修改彩玉第二个文件匹配
111
- hello world -表示需要删除改行才与第二个文件匹配
222
- 333 -表示需要删除改行才与第二个文件匹配
bbb
--- 1,6 ---- 以---开头表示file2文件,1,6表示1到6行
! aaa !表示第一个文件需要修改才与第二个文件匹配
! hello !表示第一个文件需要修改才与第二个文件匹配
111
222
bbb
+ 333 +表示第一个文件需要加上该行才与第二个文件匹配
[root@localhost hua]# cat 1.txt
aaaa
111
hello world
222
333
bbb
[root@localhost hua]# cat 2.txt
aaa
hello
111
222
bbb
333
[root@localhost hua]# diff -u 1.txt 2.txt
前两行主要列出需要比较的文件名和文件的时间戳,文件名前面的符号----表示file1,+++表示file2
--- 1.txt 2021-04-21 00:28:21.999376943 +0800
+++ 2.txt 2021-04-21 00:28:43.802577665 +0800
@@ -1,6 +1,6 @@ -代表第一个文件的1到6行,+代表第二个文件的1到6行
-aaaa 第一个文件删除aaaa
+aaa 第一个文件加aaa
+hello
111
-hello world 第一个文件减去hello world
222
-333
bbb
+333
1、比较两个目录和目录里的文件的不同
默认情况下也会比较两个目录里相同文件的内容,可以比较内容
如果只需要比较两个目录文件的不同,不需要进一步比较文件内容,需要加-q选项
[root@localhost hua]# mkdir dir1 dir2 #创建两个文件夹
[root@localhost hua]# touch dir1/file{1..5} #给dir1文件夹创建5个文件
[root@localhost dir2]# touch file{1..3}
[root@localhost dir2]# touch test{1..2}
[root@localhost hua]# ls -R dir* #查看两个文件夹下面的文件
dir1:
file1 file2 file3 file4 file5
dir2:
file1 file2 file3 test1 test2
2、将不同的内容打补丁,使其与之相同
(1)#先找出文件的不同,然后输出到一个文件
#-u:上下文模式
#-N:将不存在的文件当做空文件
(2)将不同的内容打补丁到文件
#由于是已file2为准,所以要把不同的打到file1这样才能是file1和file2相同
patch file1 file.patch
[root@localhost dir1]# cat file1
111
222
333
444
555
666
777
888
[root@localhost dir1]# cat file2
111
222
333
444
[root@localhost dir1]# diff file1 file2
5,8d4
< 555
< 666
< 777
< 888
[root@localhost dir1]# diff file1 file2>file.patch
[root@localhost dir1]# patch file1 file.patch
patching file file1
[root@localhost dir1]# diff file1 file2
[root@localhost dir1]# cat file1
111
222
333
444
paste工具用户合并文本行
常用选项:
-d:自定义间隔符,默认是tab,显示结果的间隔用什么表示
-s:串行处理,非并行,相当于第一个文件用第一行显示,第二个文件全在第二行
[root@localhost dir1]# cat file1
hell
word
1234
[root@localhost dir1]# cat file2
123
vieh
daf
3423432
[root@localhost dir1]# paste file1 file2
hell 123
word vieh
1234 daf
3423432
tr用于字符准换,替换和删除,主要用于删除文件中控制字符或进行字符转换
语法和选项
1、命令的执行结果交给tr处理,其中string1用于查询,string用于转换处理
commands|tr 'string1' 'string2'
2、tr处理的内容来自文件,记住要使用“<”标准输入
tr 'string1' 'string2' <filename
3、匹配string1进行相应操作,如删除操作
tr options 'string1' <filename
常用选项
-d:删除字符串1中所有输入字符
-s:删除所有重复出现字符序列,只保留第一个,即将重复字符串压缩为一个字符串
常匹配字符串
字符串 | 含义 | 备注 |
---|---|---|
a-z或[:lower:] | 匹配所有小写字母 | 如果匹配多个的话[0-9A-Za-z] |
A-Z或[:upper:] | 匹配所有大写字母 | |
0-9或[:digit:] | 匹配所有数字 | |
[:alnum:] | 匹配所有数字和字母 | |
[:alpha:] | 匹配所有字母 | |
[:blank:] | 所有水平空白行 | |
[:punct:] | 匹配所有标点符号 | |
[:space:] | 匹配所有水平或垂直的空格 | |
[:cntrl:] | 所有控制字符 | \f ctrl-L 走换行页 \n ctrl-J 换行 \r ctrl-m 回车 \t ctrl-l tab键 使用的时候直接输入这个就好,比如\n |
实例:
#把小写字母和数字替换成#
tr 'a-z0-9' '#' <passwd
#删除匹配到的字符
tr -d 'a-z' <passwd
#删除所有重复出现字符序列,压缩
tr -s 'a-z'< passwd
#1、提取ip地址,出现空格太多,不好使用cut,可以使用tr的-s压缩命令
[root@localhost dir1]# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.178.129 netmask 255.255.255.0 broadcast 192.168.178.255
inet6 fe80::344a:b86c:e906:a81c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:aa:29:4a txqueuelen 1000 (Ethernet)
RX packets 54664 bytes 20517979 (19.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 33463 bytes 3833682 (3.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost dir1]# ifconfig ens33 | grep broadcast |cut -d' ' -f10,12
192.168.178.129 netmask
[root@localhost dir1]# ifconfig ens33 | grep broadcast |cut -d' ' -f10,12|tr -d 'a-zA-Z'
192.168.178.129
#2、提取所有的地址
[root@localhost dir1]# ifconfig ens33| grep cast
inet 192.168.178.129 netmask 255.255.255.0 broadcast 192.168.178.255
[root@localhost dir1]# ifconfig ens33| grep cast|tr -d 'a-zA-Z'
192.168.178.129 255.255.255.0 192.168.178.255
#3、提取所有的地址后,实现换行
(1)
[root@localhost dir1]# ifconfig ens33| grep cast|tr -d 'a-zA-Z'|tr ' ' '\n'| grep -v '^$'
192.168.178.129
255.255.255.0
192.168.178.255
(2)
[root@localhost hua]# ifconfig ens33 | grep cast | tr -s ' ' |cut -d' ' -f3,5,7
192.168.178.129 255.255.255.0 192.168.178.255
[root@localhost hua]# ifconfig ens33 | grep cast | tr -s ' ' |cut -d' ' -f3,5,7|tr ' ' '\n'
192.168.178.129
255.255.255.0
192.168.178.255
Tab只能补全命令和文件
^c 终止前后台运行的程序
^z 将前台运行的程序挂起到后台
^d 退出 等价exit
^l 清屏
^a|home 光标移到命令行的最前端
^e|end 光标移到命令行的后端
^u 删除光标前所有字符
^k 删除光标后所有字符
^r 搜索历史命令,敲关键字就好了
*:匹配0或多个任意字符
?:匹配任意单个字符
[list]:匹配[list]中的任意单个字符
[!list]:匹配除list中的任意单个字符
{string,string2,.......}:匹配string,string2或更多字符串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJkIatUu-1638867876874)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210429131342410.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZiNF08x-1638867876878)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210429133046281.png)]
shell介于内核与用户之间,负责命令的解释
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQ3eSrwJ-1638867876879)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210506130138017.png)]
总结
[root@localhost etc]# cat shells
/bin/sh #是bash的一个快捷方式
/bin/bash #bash是大多数linux默认的shell,包含的功能几乎可以涵盖shell所有的功能
/usr/bin/sh
/usr/bin/bash
思考:终端和shell是什么关系
终端是一个程序,提供一个窗口,shell来解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIMgCg3U-1638867876881)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210506131102964.png)]
(一)什么是shell脚本?
—句话概括
简单来说就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译。
准确叙述
若干命令+脚本的基本格式+脚本特定语法+思想= shell脚本
(二)什么时候用到shell脚本?
重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅仅需要执行脚本就能完成这些工作。
(三)shell脚本能干啥?
1、自动化软件部署 LAMP/LNMP/Tomcat…
2、自动化管理 系统初始化脚本、批量更改主机密码、推送公钥…
3、自动化分析处理 统计网站访问量
4、自动化备份 数据库备份,日志转储
多看(看懂)—>模仿(多练)—>多思考(多写)
1)脚本第一行,魔法字符#!指定解释器【必写】
#!/bin/bash表示以下内容使用bash解释器解析
注意:
如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以
使用:#!/bin/env 解释器(bash)
# ! /bin/env bash
# 以下内容是对脚本的基本信息的描述
# Name:名字
# Desc:描述describe
# Path :存放路径
# usage:用法
# update:更新时间
#下面就是脚本的具体内容commands
(1)标准:
#两种标准方式执行脚本,标准执行方式脚本必须要有可执行的权限(建议)
[root@localhost hua]# /data/hua/shell01.sh
hell world!
hell world!
hell world!
[root@localhost hua]# ./shell01.sh
hell world!
hell world!
hell world!
(2)非标准:
#非标准的执行方法(不建议)前提是脚本没有执行权限
1.直接在命令行指定解释器执行
-x:一般用于排错,查看脚本的执行过程
-n:用来查看脚本的语法是否有问题
例子:
[root@localhost hua]# bash -x shell01.sh
+ echo 'hell world!'
hell world!
+ echo 'hell world!'
hell world!
+ echo 'hell world!'
hell world!
2.使用source命令读取脚本文件,执行文件里的代码
例子:
[root@localhost hua]# source shell01.sh
hell world!
hell world!
hell world!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3nSuvYy-1638867876881)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210507133936855.png)]
[root@localhost hua]# cat shell01.sh
#! /bin/env bash
# 以下内容是对脚本的基本信息的描述
# Name:shell01
# Desc:第一个脚本
# Path:/data/hua
# usage:/data/hua/shell01.sh
# update:2021-05-07
path=/data/hua/huachuanbin
rm -rf ${path}*
mkdir -p ${path}/dir{1..3}
cp /etc/hosts /data/hua/huachuanbin/dir1
echo "报告,任务已于`date '+%F %T'`时间完成"
echo "$(date +'+%F %T')"
#两种引用命令的方式:
`date '+%F %T'`
$(date +'+%F %T')
第25节
—句话概活:变量是用来临时保存数据的,该数据是可以变化的数据。
变量名=变量值
变量名:用来临时保存数据的
变量值:就是临时的可变化的数据
[root@localhost hua]# A=hell
[root@localhost hua]# echo $A
hell
[root@localhost hua]# echo ${A}
hell
[root@localhost hua]# A=WORLD
[root@localhost hua]# echo $A
WORLD
[root@localhost hua]# unset A #取消变量,再次调用是空的
[root@localhost hua]# echo $A
虽然可以给变量(变量名)赋予任何值;但是,对于变量名也是要求的!
变量名区分大小写
变量名不能有特殊符号
变量名不能以数字开头
等号两边不能有任何空格
变量名尽量做到见名知意
直接赋值一个变量
[root@localhost hua]# echo $a
12345
[root@localhost hua]# echo ${a}
12345
[root@localhost hua]# echo ${a:2:3} #表示a变量中第3个字符开始截取,截取3个字符,1代表第0个字符
345
说明:
$变量名和${变量名}的异同
相同点:都可以调用变量
不同点:${变量名}可以只截取变量的一部分,而$变量名不可以
#有两种方式
1、$()
[root@localhost hua]# a=$(hostname)
2、``
[root@localhost hua]# a=`hostname`
#查看系统版本
root@localhost hua]# cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
#查看内核版本
[root@localhost hua]# uname -r
3.10.0-1127.el7.x86_64
**目的:**让用户自己给变量赋值,比较灵活
**语法:**read [选项] 变量名
常见选项:
选项 | 释义 |
---|---|
-p | 定义提示用户的信息 |
-n | 定义字符数(限制变量值的长度) |
-s | 不显示(不显示用户输入的内容) |
-t | 定义超时时间,默认单位为秒(限制用户输入变量值的超时时间) |
举例:
用法一:用户自己定义变量值
#1.普通用法
[root@localhost hua]# read name
huachuanbin
[root@localhost hua]# echo $name
huachuanbin
#2.-p,提示内容
[root@localhost hua]# read -p "请输入名字:" name
请输入名字:huachuanbin
[root@localhost hua]# echo $name
huachuanbin
#3.-s和-p,隐藏输入的内容
[root@localhost hua]# read -s -p "请输入密码:" pass
请输入密码:
[root@localhost hua]# echo $pass
1234567890
#4.显示输入字符长度
[root@localhost hua]# read -n 5 -p "请输入名字:" name
请输入名字:fhdsa
[root@localhost hua]# echo $name
fhdsa
#5.限制时间,需要在限定时间范围内按下回车才行
[root@localhost hua]# read -t 3 -p "请输入名字:" name
请输入名字:123
[root@localhost hua]# echo $name
123
用法二:变量值来自文件
#先编辑一个ip.txt输入ip地址,然后用read读取
[root@localhost hua]# read -p "请输入ip地址" IP
[root@localhost hua]# echo $IP
10.213.34.123
**目的:**给变量做一些限制,固定变量的类型,比如:整型、只读
**用法:**declare 选项 变量名=变量值
常用选项:
选项 | 释义 | 举例 |
---|---|---|
-i | 将变量看成整数 | declare -i A=23 |
-r | 定义只读变量 | declare -r B=hello |
-a | 定义普通数组;查看普通数组 | |
-A | 定义关联数组;查看关联数组 | |
-x | 将变量通过环境导出 | declare -x AAA=123456 等于export AAA=123456 |
举例说明:
#定义整数,赋值其他的会变为0
[root@localhost hua]# declare -i a=123
[root@localhost hua]# echo $a
123
[root@localhost hua]# a=hello
[root@localhost hua]# echo $a
0
#定义只读变量
[root@localhost hua]# declare -r a=hello
[root@localhost hua]# echo $a
hello
[root@localhost hua]# unset a
-bash: unset: a: 无法反设定: 只读 variable
#将变量通过环境导出
(1)第一种方法
[root@localhost ~]# aaa=hua
[root@localhost ~]# export aaa
[root@localhost ~]# env | grep aaa
aaa=hua
(2)第二种用declare -x
[root@localhost ~]# declare -x bbb=chuan
[root@localhost ~]# env | grep bbb
bbb=chuan
[root@localhost ~]# ps #开启一个终端就是启动一个bash
PID TTY TIME CMD
2087 pts/0 00:00:00 bash
2102 pts/0 00:00:00 ps
[root@localhost ~]# a=123 #定义一个本地变量,切换到其他用户和子进程则输出不了
[root@localhost ~]# echo $a
123
[root@localhost ~]# /bin/bash #再开启一个bash,相当于是一个子进程了
[root@localhost ~]# ps
PID TTY TIME CMD
2087 pts/0 00:00:00 bash
2103 pts/0 00:00:00 bash
2112 pts/0 00:00:00 ps
[root@localhost ~]# ps -auxf | grep bash #查看父子关系,可以看到2103是子进程
root 2087 0.0 0.0 115676 2156 pts/0 Ss 18:22 0:00 \_ -bash
root 2103 0.0 0.0 115672 2128 pts/0 S 18:22 0:00 \_ /bin/bash
root 2114 0.0 0.0 112824 984 pts/0 S+ 18:22 0:00 \_ grep --color=auto bash
文件名 | 说明 | 备注 |
---|---|---|
$HOME /.bashrc | 当前用户的bash信息,用户登录时读取 | 定义别名,umask、函数等 |
$HOME /.bash_profile | 当前用户的环境变量,用户登录时读取 | |
$HOME /.bash_logout | 当前用户退出当前shell时最后读取 | 定义用户退出时执行的程序等 |
/etc/bashrc | 全局的bash信息,所有用户都生效 | 定义全局别名,umask、函数等 |
/etc/profile | 全局环境变量信息 | 系统和所有用户都生效 |
$HOME /.bash_history | 当前用户的历史命令记录 |
说明:以上文件修改后,都需要重新source让其生效或者退出重新登录
#查看用户的bash信息
[root@localhost ud]# cat .bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then #全局下面有这个文件存在
. /etc/bashrc #.等同于source,读取一个文件,刷新
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
脚本重点用到的:#?、KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲、*、$@、$1- 9 、 9、 9、$
内置变量 | 含义 |
---|---|
#? | 上一条命令执行后返回的状态;状态值为0表示执行正常,非o表示执行异常或错误 |
$0 | 当前执行的程序或脚本名 |
$# | 脚本后面接的参数的个数 |
$* | 脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
$@ | 脚本后面所有参数,参数是独立的,也是全部输出 |
$1-$9 | 脚本后面的位置参数,$1表示第1个位置参数,依次类推 |
10 − {10}- 10−{n} | 扩展位置参数,第10个位置变量必须用0大括号括起来(2位数字以上扩起来) |
$$ | 当前所在进程的进程号,如echo $$ |
$! | 后台运行的最后一个进程号(当前终端) |
!$ | 调用最后一条命令历史中的参数 |
36节
实例:
1、上一条命令执行后返回的状态;状态值为0表示执行正常,非o表示执行异常或错误(#?)
[root@localhost ~]# lll
-bash: lll: 未找到命令
[root@localhost ~]# echo $?
127
2、一些举例使用,$前面有\代表是转义了
#! /bin/env bash
#name:Variable.sh
#.......
echo "1、当前执行的程序或脚本名:"
echo "\$0=$0"
echo "2、脚本后面接的参数个数:"
echo "\$#=$#"
echo "3、脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开:"
echo "\$*=$*"
echo "4、脚本后面所有参数,参数是独立的,也是全部输出:"
echo "\$@=$@"
echo "5、扩展位置参数,第10个位置变量必须用0大括号括起来(2位数字以上扩起来):"
echo "\${12}=${12}"
echo "6、打印第1个:"
echo "\$1=$1"
3、后台运行的最后一个进程号(当前终端)$!
[root@localhost hua]# ps
PID TTY TIME CMD
2947 pts/0 00:00:00 bash
3144 pts/0 00:00:00 ps
[root@localhost hua]# jobs #查看当前终端的后台程序
[root@localhost hua]# sleep 500 & #程序放到后台去运行
[1] 3145
[root@localhost hua]# jobs
[1]+ 运行中 sleep 500 &
[root@localhost hua]# sleep 600 #按下ctrl+z,放到后台暂停
^Z
[2]+ 已停止 sleep 600
[root@localhost hua]# jobs
[1]- 运行中 sleep 500 &
[2]+ 已停止 sleep 600
[root@localhost hua]# ps
PID TTY TIME CMD
2947 pts/0 00:00:00 bash
3145 pts/0 00:00:00 sleep
3147 pts/0 00:00:00 sleep
3152 pts/0 00:00:00 ps
[root@localhost hua]# echo "$!"
3145
#杀死后台的进程
[root@localhost mail]# jobs
[1]- 运行中 sleep 500 &
[2]+ 运行中 sleep 100 &
[root@localhost mail]# kill -9 %1
[root@localhost mail]# jobs
[1]- 已杀死 sleep 500
[2]+ 运行中 sleep 100 &
4、调用最后一条命令历史中的参数(!$)
[root@localhost hua]# ls -l
总用量 16
-rw-r--r--. 1 root root 0 5月 14 13:38 1.txt
-rwxr-xr-x. 1 root root 85 5月 8 20:05 2.sh
drwxr-xr-x. 5 root root 42 4月 21 23:47 huachuanbin
-rw-r--r--. 1 root root 14 5月 8 16:17 ip.txt
-rwx--x--x. 1 root root 340 4月 21 23:37 shell01.sh
-rwxr-xr-x. 1 root root 554 5月 8 21:31 variable.sh
[root@localhost hua]# echo !$
echo -l
-l
算数运算:默认情况下,shell就只能支持简单的整数运算
运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
表达式 | 举例 |
---|---|
$(()) | echo $((1+1)) |
$[] | echo $[10-5] |
expr | expr 10 / 5 |
let | n=1;let n+= 等价于 let n=n+1 |
#举例
#1、$(())的用法举例
[root@localhost hua]# echo $((10*3))
30
#2、$[]的用法举例
[root@localhost hua]# echo $[10*8]
80
#3、expr的用法举例,注意:expr的数值需要空格,并且*需要转义
[root@localhost hua]# expr 10 \* 2
20
#4、let的用法举例
简单用法:
[root@localhost hua]# n=1;let n+=3;echo $n
4
[root@localhost hua]# let n-=1;echo $n
3
求几次方的用法
[root@localhost hua]# n=2;let n=n**3;echo $n
8
[root@localhost hua]# let n=n**3;echo $n
512
#1、直接输入bc,输入计算的数值,退出使用quit
[root@localhost hua]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1+1.5
2.5
quit
#2、由于一般的方法计算小数点值,会报错,这个时候使用bc工具即可
[root@localhost hua]# $((1+1.5))
-bash: 1+1.5: 语法错误: 无效的算术运算符 (错误符号是 ".5")
[root@localhost hua]# echo 1+1.5|bc
2.5
#求平方
[root@localhost hua]# echo 3^2|bc
9
[root@localhost hua]# i=1;j=1;let i++;let ++j;echo $i;echo $j
2
2
[root@localhost hua]# i=1;j=1;
[root@localhost hua]# echo $i;echo $j;
1
1
[root@localhost hua]# let x=i++;let y=++j
[root@localhost hua]# echo $i;echo $j
2
2
[root@localhost hua]# echo $x;echo $y
1
2
思考:何为真(true),何为假(false)
特别说明:
判断参数 | 含义 |
---|---|
-e | 判断文件是否存在(任何类型文件) |
-f | 判断文件是否存在并且是一个普通文件 |
-d | 判断文件是否存在并且是一个目录 |
-L | 判断文件是否存在并且是一个软连接文件 |
-b | 判断文件是否存在并且是一个块设备文件 |
-s | 判断文件是否存在并且是一个套接字文件 |
-c | 判断文件是否存在并且是一个字符设备文件 |
-p | 判断文件是否存在并且是一个命名管道文件 |
-s | 判断文件是否存在并且是一个非空文件(有内容) |
用$?判断上一条命令执行的结果,0为真,不为0为假
[root@localhost hua]# test -e ./file1
[root@localhost hua]# echo $?
0
[root@localhost hua]# test -e ./test
[root@localhost hua]# echo $?
1
用$?判断上一条命令执行的结果,0为真,不为0为假
[ -d /data/hua/huachuanbin/dir1 ];echo $?
[root@localhost hua]# [ -d /data/hua/huachuanbin/dir1 ];echo $?
0
[ -L /data/hua/test ];echo $?
先创建一个软链接,用$?判断上一条命令执行的结果,0为真,不为0为假,如果原文件删除了,判断还是真
[root@localhost hua]# ln -s file1 test
[root@localhost hua]# ll
总用量 16
-rw-r--r--. 1 root root 0 5月 14 13:38 1.txt
-rwxr-xr-x. 1 root root 85 5月 8 20:05 2.sh
-rw-r--r--. 1 root root 0 5月 14 16:11 file1
-rw-r--r--. 1 root root 0 5月 14 16:11 file2
-rw-r--r--. 1 root root 0 5月 14 16:11 file3
-rw-r--r--. 1 root root 0 5月 14 16:11 file4
drwxr-xr-x. 5 root root 42 4月 21 23:47 huachuanbin
-rw-r--r--. 1 root root 14 5月 8 16:17 ip.txt
-rwx--x--x. 1 root root 340 4月 21 23:37 shell01.sh
lrwxrwxrwx. 1 root root 5 5月 14 16:26 test -> file1
-rwxr-xr-x. 1 root root 554 5月 8 21:31 variable.sh
[root@localhost hua]# [ -L /data/hua/test ];echo $?
0
不存在则为真
[ ! -d ./dir7 ];echo $?
[root@localhost huachuanbin]# ll
总用量 0
drwxr-xr-x. 2 root root 19 4月 21 23:47 dir1
drwxr-xr-x. 2 root root 6 4月 21 23:47 dir2
drwxr-xr-x. 2 root root 6 4月 21 23:47 dir3
[root@localhost huachuanbin]# [ ! -d ./dir7 ];echo $?
0
判断参数 | 含义 |
---|---|
-r | 当前用户对其是否可读 |
-w | 当前用户对其是否可写 |
-x | 当前用户对其是否可执行 |
-u | 是否有suid,高级权限冒险位 |
-g | 是否sgid,高级权限强制位 |
-k | 是否有t位,高级权限粘滞位 |
实例:
test -r shell01.sh ;echo $?
[ -x huachuanbin ];echo $?
说明:这里的新日指的是文件的修改时间。三=
判断参数 | 含义 |
---|---|
file1 -nt file2 | 比较file1是否比file2新 |
file1 -ot file2 | 比较file1是否比file2l旧 |
file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode |
实例:
[root@localhost hua]# [ file1 -nt file2 ];echo $?;
0
[root@localhost hua]# [ file1 -ot file2 ];echo $?;
1
[root@localhost hua]# [ file1 -ef file2 ];echo $?;
1
判断参数 | 含义 |
---|---|
-eq | 相等 |
-ne | 不等 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
判断参数 | 含义 |
---|---|
-z | 判断是否为空字符串,字符串长度为0则成立 |
-n | 判断是否为非空字符串,字符串长度不为0则成立 |
string1 = string2 | 判断字符串是否相等 |
string 1 != string2 | 判断字符串是否不相等 |
实例:
#四种用法
[root@localhost hua]# test -z "hell world";echo $?
1
[root@localhost hua]# test -n "hell world";echo $?
0
[root@localhost hua]# test "hello" = "world";echo $?
1
[root@localhost hua]# test "hello" != "world";echo $?
0
判断符号 | 含义 | 举例 |
---|---|---|
-a 和&& | 逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ] [ 1-eq 1 ]&&[ 1 -ne 0 ] |
-o 和|| | 逻辑或 | [ 1 -eq 1 -o 1 -ne 1] [ 1 -eq 1] |
特别说明:
&& 前面的表达式为真,才会执行后面代码
|| 前面的表达式为假,才会执行后面的代码
; 只用于分割命令或表达式
实例:
#注意:多个运算符在一起的时候,没有优先级,从左往右,
[root@localhost ~]# [ $(id -u) -eq 0 ] && echo "admin"||echo "is not admin"
admin
#这里切换到普通用户了
[ud@localhost ~]$ [ $(id -u) -eq 0 ] && echo "admin"||echo "is not admin"
is not admin
#前面表达式为假,执行了BBB的,然后BBB为真,则输出了CCC
[ud@localhost ~]$ [ 1 -eq 2 ] && echo AAA || echo BBB && echo CCC
BBB
CCC
#前面表达式为假,执行了AAA,然后AAA为真,输出了后面两个
[ud@localhost ~]$ [ 1 -eq 2 ] || echo AAA && echo BBB && echo CCC
AAA
BBB
CCC
注意:在(())中,=表示赋值;==表示判断
[root@server ~]# ((1==2)) ;echo $?
[root@server ~]#((1<2)) ;echo $?
[root@server ~]#((2>=1)) ;echo $?
[root@server ~]#((2!=1)) ;echo $?
[root@server ~]# ((`id -u`==0) ) ;echo $?
[root@server ~]# ((a=123)) ;echo $a
[root@server ~]# unset a
[root@server ~]#((a==123)) ;echo $?
如果其中一个字符串为空的话,字符串判断要加双引号,或者用两层中括号括起来的时候也可以,没有双引号会报错
注意:双引号引起来,看作一个整体;=和==在[字符串]比较中都表示判断
[root@server ~]# a='he11o wor1d ' ; b=wor1d
[root@server ~]# [ $a = $b ] ; echo $?
[rootaserver ~]#[ "$a" = "$b” ];echo $?
[root@server ~]#[ "$a" != "Sb” ] ;echo $?
[root@server ~]# [ "$a" !== "$b” ];echo $? 错误,要用上面这个格式
[root@server ~]# [ "$a" == "Sb”];echo $?
[root@server ~]# test "$a" != "$b " ;echo $?
实例:
[root@localhost hua]# A=hello;B=world;[ "$A" = "$B" ];echo $?
1
[root@localhost hua]# A=hello;B=world;[ "$A" != "$B" ];echo $?
0
[root@localhost hua]# A=hello;B=world;[ "$A" == "$B" ];echo $?
1
#判断一个文件是否存在,并且是链接文件,有这三种写法,第二三种需要加两个[],或者分开
[root@localhost hua]# [ -e test -a -L test ];echo $?
0
[root@localhost hua]# [[ -e test && -L test ]];echo $?;
0
[root@localhost hua]# [ -e test ] &&[ -L test ];echo $?;
0
语法结构:
(1)test expr1
(2)[ expr1 ]
(3)[[ expr1 ]]
条件判断:
-d 、-L、-e、-w、-ef、-n、-z、
-s:判断文件是否不为空;!=判断文件是否为空文件(通过man test查询得到)
1.符号;和&&和H都可以用来分割命令或者表达式
2.分号(;)完全不考虑前面的语句是否正确执行,都会执行;号后面的内容
3.&&符号,需要考虑&&前面的语句的正确性,前面语句正确执行才会执行&&后的内容;反之亦然
4.||符号,需要考虑| |前面的语句的非正确性,前面语句执行错误才会执行||后内容;反之亦然
5.如果&&和一起出现,从左往右依次看,按照以上原则
注意:只要正确,就要一直往前冲
F:表示false,为假
T:表示true,为真
if [ condition ];then
command
command
fi
if test 条件;then
命令
fi
[ 条件 ] && command
注意:分叉入口,二选一
if [ condition ];then
command1
else
commend2
fi
[ 条件 ] && command1 ||command2
实例:
#! /bin/env bash
if [ "$1" = "hello" ];then
echo " 正确!"
else
echo "错误"
fi
#题目:提示用户自己输入hello,然后输出helloworld,否则输出请重新输入hello
#! /bin/env bash
read -p "请输入hello:" str
if [ "$str" = "hello" ];then
echo "$str,world!"
else
echo "请重新输入hello"
fi
注意:选择很多,能走的只有一条
if [ condition1 ];then
command1 结束
elif [ condition2 ];then
command2 结束
else
command3
fi
注释:
如果条件1满足,执行命令1后结束;如果条件1不满足,再看条件2,如果条件2满足执行命令2后结束;如果条件1和条件2都不满足执行命令3结束.
实例:
#! /bin/env bash
if [ 1 -eq 2 ];then
echo a
elif [ 2 -ne 2 ];then
echo b
elif [ 3 -gt 3 ];then
echo c
else
echo 4
fi
#结果输出为4
if [ condition1 ] ;then
command1 #满足了前面的if则会执行这个
if [ condition2 ];then
command2
fi
else
if [ condition3 ];then
command3
elif [ condition4 ] ;then
command4
else
command5fi
fi
注释:
如果条件1满足,执行命令1;如果条件2也满足执行命令2,如果不满足就只执行命令1结束;
如果条件1不满足,不看条件2;直接看条件3,如果条件3满足执行命令3;如果不满足则看条件4,如果条件4满足执行命令4;否则执行命令5
# ping -c1 可以指定ping的次数
# &>/dev/null ping的结果不要了,丢到黑洞里面去
# & 表示 等同于 的意思
脚本实现:
#! /bin/env bash
read -p "请输入要ping的ip地址:" ip
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ]
then
echo "当前主机可以和$ip ping通"
else
echo "当前主机不可以和$ip ping通"
fi
#自己写的:
#! /bin/env bash
read -p "请输入要ping的ip地址:" ip
ping -c1 $ip
if [ $? = 0 ]
then
echo "可以ping通"
else
echo "ping不通"
fi
自己写的
#! /bin/env bash
read -p "请输入要判断程序是否在的程序名:" ip
ps -ef | grep $ip | grep -v grep &>/dev/null
if [ $? -eq 0 ]
then
echo "当前进程存在"
else
echo "当前进程不存在"
fi
或者
test $? -eq 0 && echo "进程存在" || echo "进程不存在"
举例:pgrep httpd
pgrep命令:以名称为依据从运行进程队列中查找进程,并显示查找到的进程id选项
-o:仅显示找到的最小(起始)进程号;
-n:仅显示找到的最大(结束)进程号;
-1:显示进程名称;
-P:指定父进程号;pgrep -p 4764 查看父进程下的子进程id
-g:指定进程组;
-t:指定开启进程的终端;
-u:指定进程的有效用户ID。
wget:下载页面
curl:请求页面
elinks:
#1、判断服务是否可用
#! /bin/env bash
read -p "请输入要判断的网址:" ip
curl $ip &>/dev/null
if [ $? = 0 ]
then
echo "输入的网址可以提供服务"
else
echo "输入的网址不可提供服务"
fi
或者:
[ $? = 0 ] && echo "可以提供服务" || echo "不可以提供服务"
#2、下载网址,并删除下载文件
#! /bin/env bash
read -p "请输入要判断的网址:" ip
wget -P /data/hua/huachuanbin $ip &>/dev/null
if [ $? = 0 ]
then
echo "下载成功"
rm -r /data/hua/huachuanbin/index*
else
echo "下载失败"
fi
#自己写的
#! /bin/env bash
read -p "请输入要查找的用户名:" name
cat passwd |cut -d: -f1,3 | grep -w $name
if [ $? -eq 0 ]
then
echo "你输入的用户名为:$name,是存在的,id是:$a,na是:$b"
else
echo "你输入的用户名为:$name,该用户是不存在的"
fi
#视频里的
#! /bin/env bash
read -p "请输入要查找的用户名:" name
id $name &>/dev/null
if [ $? -eq 0 ]
then
echo "你输入的用户名为:$name,是存在的,id是:$a,na是:$b"
else
echo "你输入的用户名为:$name,该用户是不存在的"
fi
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kw8iqepO-1638867876882)(C:\Users\HCB\AppData\Roaming\Typora\typora-user-images\image-20210523230719874.png)]
58节
列表for循环,用于将一组命令执行已知的次数
#打印1到5
#! /bin/env bash
for var in 1 2 3 4 5 #这里或者是{1..5}
do
echo $var
done
#1、打印1到50之间的偶数
#! /bin/env bash
for i in {1..50}
do
a=$(($i%2)) #这里可以用a=$[$i%2],或者a=`expr $i % 2`
if [ $a -eq 0 ]
then
echo $i
fi
done
#2、用一条命令打印1到100的奇数,这里的2代表步长为2:
for i in {1..100..2};do echo $i; done
#从10打印到1
(1)for i in {10..1};do echo $i;done
(2)seq 10 -1 1 #-1为步长
(3)for i in {10..1..-1};do echo $i;done
不带列表的for循环执行时由用户指定参数和参数的个数
基本语法格式:
for variable
do
command
command
.....
done
举例说明:
[root@localhost hua]# cat test.sh
#! /bin/env bash
for i
do
echo "hello,$i"
done
[root@localhost hua]# ./test.sh 1
hello,1
[root@localhost hua]# ./test.sh 1 2 3 4 5
hello,1
hello,2
hello,3
hello,4
hello,5
[root@localhost hua]# ./test.sh {1..5}
hello,1
hello,2
hello,3
hello,4
hello,5
接班语法机构
for(( expr1;expr2;expr3))
do
command
command
.....
done
for ((i=1;i<=10;i++))
do
echo "hello,$i"
done
expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出
思路:
1.定义一个变量来保存奇数的和I
⒉.找出1-100的奇数,保存到另一个变量里
3.从1-100中找出奇数后,再相加,然后将和赋值给变量
4.遍历完毕后,将sum的值打印出来
#自己写的,最终输出2500
#! /bin/env bash
sum=0
for ((i=1;i<=100;i++))
do
a=$((i%2))
if [ $a -gt 0 ]
then
sum=$((sum+$i))
fi
done
echo $sum
#方法一:
#! /bin/env bash
sum=0
for i in {1..100..2}
do
let sum=`expr $sum + $i`
done
echo $sum
#方法二
#! /bin/env bash
sum=0
for ((i=1;i<=100;i+=2))
do
let sum=`expr $sum + $i`
done
echo $sum
#方法三
#! /bin/env bash
sum=0
for ((i=1;i<=100;i++))
do
if [ $[$i%2] -ne 0 ]
then
let sum=$sum+$i
fi
done
echo $sum
或者
test $[$i%2] -ne 0 && sum=`expr $sum + $i
test $[$i%2] -ne 0 && let sum=$sum+$i
#方法四,continue
#! /bin/env 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 $sum
continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环
break:打断;马上停止执行本次循环,执行循环体后面的代码
exit:表示直接跳出程序
实例:
1、continue用法
#1、打印奇数和
#! /bin/env 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 $sum
#2、结果是i输出6,并且除了2,创建了1345
#! /bin/env bash
for ((i=1;i<=5;i++))
do
test $i -eq 2 && continue ||touch /data/hua/file$i.doc
done
echo $i
2、break用法
#i=2后,跳出循环,并创建了file.doc和输出echo $i
#! /bin/env bash
for ((i=1;i<=5;i++))
do
test $i -eq 2 && break ||touch /data/hua/file$i.doc
done
echo $i
3、exit用法
#创建了两个文件,到第三个直接退出程序,所以不会执行echo $i
#! /bin/env bash
for ((i=1;i<=5;i++))
do
test $i -eq 3 && exit ||touch /data/hua/file$i.doc
done
echo $i
1、判断一个目录是否存在
test -d /data/hua/huachuanbin/ ;if [ $? -eq 0 ];then echo "存在";fi
2、判断一个目录是否存在,如果没有则创建
test -d /data/hua/huachuanbin/ ;if [ $? -eq 0 ];then echo "存在";else mkdir /data/hua/huachuanbin;fi
3、判断一个目录是否不存在,不存在则创建
[ ! -d /data/hua/huachuanbin ] && mkdir /data/hua/huachuanbin || echo "存在"
4、用if判断,判断一个目录是否不存在,不存在则创建
if [ ! -d /data/hua/huachuanbin ] ;then mkdir /data/hua/huachuanbin ;else echo "存在";fi
5、判断一个文件是否存在并且不为空,空的话删除 ! -s代表为空文件
if [ ! -s /data/hua/huachuanbin/1.txt ] ;then rm -rf /data/hua/huachuanbin/1.txt;else echo "不为空";fi
质数只能被1和他本身整除,有第三中情况的都不是质
数
#! /bin/env bash
#定义变量来保存用户输入的数字
read -p "请输入一个数字:" number
#先排除用户输入的1和2
[ $number -eq 1 ]&& echo "你输入为1,重新输入" &&exit
[ $number -eq 2 ]&& echo "你输入为2,重新输入" &&exit
#判断用户,seq这里再除以2,为了优化,这样能节省一半,因为可以被2整除就可以节省一半
for i in `seq 2 $[$number-1]`
do
[ $[$number%$i] -eq 0 ] && echo "不是质数" && exit
done
echo "是质数"
mkpasswd -l 8 #代表随机生成8位密码
#1、echo 123 |passwd --stdin u$i更新用户密码信息,适用于shell脚本
#2、useradd -g 不为用户创建新组, 而使用 -g 后的指定用户组,-G 后面跟一个用户组列表,使用户属于指定的多个用户组。
#! /bin/bash
grep -w ^class /etc/group &>/dev/null
[ $? -ne 0 ]&& groupadd class
for ((i=1;i<=5;i++))
do
useradd -G class u$i
echo 123 |passwd --stdin u$i
done
自己写的
#! /bin/bash
ip=192.168.178
for i in {1..300}
do
ping -c1 $ip.$i &>/dev/null
if [ $? -eq 0 ]
then
echo "可以ping通:$ip.$i" >> ok.txt
else
echo "不可以ping通:$ip.$i" >> not.txt
fi
done
并发执行:{程序}&表示将程序放到后台并行执行,如果需要等待程序执行完毕再进行下面内容,需要加wait
1、查看脚本执行时间
[root@localhost hua]# time ./tesh.sh
real 0m24.322s
user 0m0.003s
sys 0m0.057s
2、并发执行,在循环体加{}&,wait是等待,等待上一个执行才执行下一个,这样可以极大节省时间,并发执行
#! /bin/bash
ip=192.168.178
for i in {1..300}
do
{
ping -c1 $ip.$i &>/dev/null
if [ $? -eq 0 ]
then
echo "可以ping通:$ip.$i" >> ok.txt
else
echo "不可以ping通:$ip.$i" >> not.txt
fi
}&
done
wait
echo "所有测试完毕"
for循环语法结构
for循环可以结合条件判断和流程控制语句
控制循环语句
continue 继续,跳过本次循环,继续下一次循环
break 跳出循环,执行循环体外的代码
exit 退出,直接退出程序
特点:条件为真就进入循环;条件为假就退出循环
#1、格式:
while 表达式
do
command
done
#2、举例:
while [ 1 -eq 1 ]或者(( 1>2))
do
command
done
#3、从1加到5
#! /bin/bash
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
或者,类c风格
i=1;while(($i<=10));do echo $i;let i+=2;done
自己写的
#打印1到50之间偶数和
#! /bin/bash
i=1
sum=0
while [ $i -le 50 ]
do
if [ $[$i%2] -eq 0 ]
then
sum=$[$sum+$i]
fi
let i++
done
echo $sum
#方法一:
#! /bin/bash
sum=0
for ((i=0;i<=50;i+=2))
do
let sum=$sum+$i
done
echo $sum
#方法二:
#! /bin/bash
sum=0
i=2
while [ $i -le 50 ]
do
let sum=$sum+$i 或者:sum=$[$sum+$i]
let i+=2 i=$[$i+2]
done
echo $sum
自己写的:
#! /bin/bashntp=120.25.115.20num=0while truedo ntpdate $ntp if [ $? -ne 0 ] then num=$[$num+1] echo "在时间$(date)同步失败,次数是$num" |mail -s "ntp同步失败" [email protected] sleep 6 else num=$[$num+1] if [ $[$num%5] -eq 0 ] then echo "在时间$(date)同步成功,次数是$num次" |mail -s "ntp同步" [email protected] fi fidone
视频实例:
#! /bin/bash
ntp=192.168.178.130
count=0
a=0
while true
do
ntpdate $ntp &>/dev/null #同步该ntp服务器的时间
if [ $? -ne 0 ]
then
echo "ntp service connect failed" |mail -s "check ntp service" 1549245143@qq.com #如果报错,则输出错误信息到指定邮箱,echo后面的为内容,后面的-s后面的为标题,发送到本地服务器内用root@localhost,路径在/var/spool/mail
let a++ #实现报错5次就退出程序
if [ $a -eq 5 ]
then
exit
fi
else
let count++
if [ $count -eq 100 ] # 或者$[$count%100] -eq 0,则后面不需要置0,count=0
then
echo "ntp service connect success" |mile -s "check ntp service" 1549245143@qq.com && count=0
fi
fi
sleep 3
done
同步时间:
#1、按下ctrl+r,输入ntpdate 会自动显示配置文件的ntp服务器,回车即可(这里用回以前默认的配置文件)
[root@localhost etc]# ntpdate 1.centos.pool.ntp.org
9 Jun 14:25:18 ntpdate[2309]: adjust time server 203.107.6.88 offset 0.001046 sec
#2、xinetd服务
(1)安装
yum -y install xinetd
(2)启动
service xinetd start
(3)进入配置文件
/etc/xinetd.d
(4)打开开关
time-dgram文件,这里改为no
# This is for quick on or off of the service
disable = no
(5)查看端口
netstat -nltup | grep 37
(6)用rdate同步时间( rdate命令用于显示其他主机的日期与时间。)
rdate -s 0.centos.pool.ntp.org
(7)linux主机查看邮件的位置
/var/spool/mail
(8)修改脚本为rdate -s 0.centos.pool.ntp.org
(9)测试,关掉xinetd服务,然后一直tail -f /var/spool/mail/root
service xinetd stop
(8)由于是个死循环,放后台执行的方法
./tesh.sh &
查看用jobs
杀死用kill -9 %1 #这里百分之一要看前面括号里面的值
until expression [ 1 -eq 1 ] ((1>=1)) do commnd commnd done
#(1)
#! /bin/bash
i=5
until [ $i -lt 1 ]
do
if [ $i -eq 100 ]
then
exit
fi
echo $i
let i++
done
#(2)
i=5;until (($i<1));do echo $i;let i--;done
(1)使用until语句批量创建10个用户,要求stu1-stu2分别为1001-1005
(2)stu6-stu10用户的家目录分别在/rhome/stu6-/rhome/stu10
(1)创建用户语句
useradd -u 指定用户ID号。该值在系统中必须是唯一的
useradd -d 指定用户登入时的主目录,替换系统默认值/home/<用户名>
(2)使用循环语句until批量创建用户
(3)判断用户前五个和后五个
要想简练脚本的话,两者合为一起,里面用ifelse
#! /bin/bash
test -d /rhome && echo "存在" || mkdir /rhome;echo "不存在,已创建"
i=1
until [ $i -gt 5 ]
do
useradd -u $[1000+$i] stu$i
echo 123|passwd --sdtin stu$i
let i++
done
until [ $i -gt 10 ]
do
useradd -d /rhome/stu$i stu$i
echo 123|passwd --sdtin stu$i
let i++
done
系统变量:RANDOM,默认会产生0-332767的随机整数
打印一个随机数echo $RANDOM查看系统上一次生成的随机数set | grep RANDOM产生0~1之间的随机数echo $[ $RANDOM%2]产生0~2之间的随机数echo $[ $RANDOM%3]
需求:随机产生以139开头的电话号码,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行。
思路:
作者写的:
判断是否有重复
[root@localhost hua]# cat phonenum.txt |wc -l
1001
[root@localhost hua]# cat phonenum.txt |sort -u |wc -l
1001
给重复的排序
[root@localhost hua]# sort phonenum.txt |uniq -c|sort -nr |head
#! /bin/bashfile=/data/hua/phonenum.txtfor ((i=0;i<=1000;i++))do n1=$[$RANDOM%10] n2=$[$RANDOM%10] n3=$[$RANDOM%10] n4=$[$RANDOM%10] n5=$[$RANDOM%10] n6=$[$RANDOM%10] n7=$[$RANDOM%10] n8=$[$RANDOM%10] echo $i 139$n1$n2$n3$n4$n5$n6$n7$n8 >>$file done
自己写的,可以实现
#! /bin/bashtest -f /data/hua/phonenum.txt if [ $? -ne 0 ] then touch /data/hua/phonenum.txt else echo "文件存在" fifile=phonenum.txtfor ((i=0;i<=1000;i++))do echo $i 139$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10] >>$file done
需求:
1、在上面的1000个里面抽奖4个幸运观众,显示出这5个幸运观众
2、单只显示头3位数和尾号的4位数,中间用*代替
思路:
1、确定幸运观众所在的行,0-1000 随机找出一个数字 ,从1开始加1 [ [ [RANDOM%1000+1]
2、将电话号码提取出来
3、显示前3个和后4个到屏幕
#! /bin/bashphone=/data/hua/phonenum.txtfor i in {1..5}do line=`cat $phone |wc -l` #获取这个文件的行号 luck=`head -$[$RANDOM%$line+1] $phone |tail -1` #获取号码 echo 第$i个幸运号码是:${luck:0:3}****${luck:7:4} #变量截取字符,并中间用*表示 sed -i "/$luck/d" $phone #删除抽中的行 done
需求:批量创建5个用户,每个用户的密码为一个随机数
思路:
#! /bin/bashecho user{1..5}:Lins$[$RANDOM%9000+1000]|tr -s ' ' '\n' >>user.pass #生成账户和随机密码保存到文件,密码是四位数以上的,范围是1000-9999for i in {1..5}do user=`head -$i user.pass |tail -1 |cut -d: -f1` #截取文件里的用户 pass=`head -$i user.pass |tail -1 |cut -d: -f2` #截取文件里的密码 useradd $user #添加用户 echo $pass |passwd --stdin $user #设置密码done
#1、随机数永远是两位数echo $[$RANDOM%90+10] #求余100才是0-99,由于是两位需要加10 ,相当于0加10,90加10,这样就是10-99范围的数字
for循环
#1、列表循环for i in {1..5} ;do echo $i; done#2、类C风格for ((i=1;i<=5;i++));do echo $i; done
while循环
#1、普通版i=1;while [ $i -le 5 ];do echo $i ;let i++; done#2、类c风格i=1;while(($i<=5));do echo $i ;let i++; do
until循环
#1、普通版i=1 ;until [ $i -gt 5 ];do echo $i;let i++ ;done#2、类c风格i=1 ;until(($i>5));do echo $i;let i++ ;done
关键字:大圈套小圈
**时钟:**分针与秒针,秒针一圈,分针转一格,循环嵌套就是外层循环一次,内层循环一轮。
1
12
123
1234
12345
#1、脚本实现,用for类c风格#! /bin/env bashfor ((i=1;i<=5;i++))do for ((j=1;j<=$i;j++)) do echo -n $j #-n代表不换行 doneecho done输出:112123123412345#2、脚本实现,用while的类c风格,结合#! /bin/env bashfor ((i=1;i<=5;i++))do j=1 while (($j<=$i)) do echo -n $j let j++ doneechodone
12345
1234
123
12
1
#! /bin/env bashfor ((i=1;i<=5;i++))do for ((j=1;j<=6-$i;j++)) do echo -n $j #-n代表不换行 doneecho done
5
54
543
5432
54321
#! /bin/env bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=6-$i;j--)) #第一个输出5,5大于等于5,输出第一个5
do
echo -n $j #-n代表不换行
done
echo
done
54321
5432
543
54
5
#! /bin/env bashfor ((i=1;i<=5;i++))do for ((j=5;j>=$i;j--)) do echo -n $j #-n代表不换行 doneechodone
(1)变量名=变量值
echo $变量名
echo ${变量名}
(2)read -p "提示用户信息:" 变量名
(3)declare -i/-x/-r 变量名=变量值
(1)if [ 条件判断 ];then command fi (2)if [ 条件判断 ];then command else command fi(3)if [ 条件判断1 ];then command1 elif [ 条件判断2 ];then command2 fi
forwhileuntil
exit 退出整个程序break 结束当前循环,或跳出本层循环continue 忽略本次循环剩余的代码,直接进行下一次循环shift 是位置参数向左移动,默认移动是1位,可以使用shift 2
./ tesh.sh 1 2 3 4 5相当于先加了1,然后把2位移到左边第一位,以此类推,如果shift为2 那就是位移两位,可以加1到10的奇数#! /bin/env bashsum=0while [ $# -ne 0 ]do let sum=$sum+$1 #加第一个参数$1shiftdoneecho $sum
expect 自动应答,tcl语言
要安装这个命令:expect
为什么要设置set timeout时间,是由于网络问题需要等待一下
检查是否已经安装:yum list | grep expect安装:yum -y install expect查看 :rpm -ql expect,可以看到/usr/bin/expect,所以在脚本里面需要用这个解释器解析,首行是这个
执行命令(显示调用):expect tesh.sh
实例:
脚本执行方式:#./expect1.sh#/shell04/expect1.sh#expect -f expect1.sh(1)登录上去什么不做#!/usr/bin/expect#开启一个程序spawn ssh [email protected]#捕获相关内容expect { "(yes/no)?" {send "yes\r";exp_continue} "password:" {send "123456\r"}}interact //交互,这个是登录上去什么都不做,如果没有这个的话,会自动退出(2)登录上去,使用变量#!/usr/bin/expectset ip 192.168.178.130 set pass 123456 set timeout 5 #开启一个程序spawn ssh root@$ip#捕获相关内容expect { "(yes/no)?" {send "yes\r";exp_continue} "password:" {send "$pass\r"}}interact //交互
(1)登录主机删除相关内容,并创建文件
#!/usr/bin/expect
set ip 192.168.178.130
set pass 123456
set timeout 5
#开启一个程序
spawn ssh root@$ip
#捕获相关内容
expect {
"(yes/no)?" {send "yes\r";exp_continue}
"password:" {send "$pass\r"}
}
expect "#" #这里也可以用跟上面一样的花括号,因为这里只要捕获一个#,所以这样写也可以
send "rm -rf /tmp/*\r"
send "touch /tmp/file{1..3}.txt\r"
send "date\r"
send "exit\r"
expect eof #代表程序结束
(2)登录上去创建用户和删除东西
#!/usr/bin/expect
set ip 192.168.178.131
set pass 123456
set timeout 3
spawn ssh root@$ip
expect {
"(yes/no)?" {send "yes\r";exp_continue}
"password:" {send "$pass\r"}
}
expect {
"#" {send "useradd expectest;touch /tmp/expctest;exit\r"}
}
expect eof
#实现远程登录主机创建用户并删除文件
#!/bin/bash
while read ip pass #ip地址和密码来自下面的ip.txt
do
/usr/bin/expect <<-END &>/dev/null #-是制表符,如果没有的话,下面的END要左靠齐,<<看到下面的END后会结束程序
spawn ssh root@$ip #开启一个程序
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#" { send "useradd hua;rm -rf /tmp/*;exit\r" } #exit退出去再回车
expect eof #代表这个程序结束 /usr/bin/expect但还是撤不出来,所以后面要敲一个END,看到他完全撤出
END
echo "$ip服务器用户创建完毕"
done <ip.txt
实例:
#执行的时候需要加上ip和密码,$argv 0,$argv 1相当于第一个和第二个参数,传参
#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
set timeout 5
#开启一个程序
spawn ssh root@$ip
#捕获相关内容
expect {
"(yes/no)?" {send "yes\r";exp_continue}
"password:" {send "$pass\r"}
}
interact //交互
#实现远程登录主机创建用户并删除文件#!/bin/bashwhile read ip pass #ip地址和密码来自下面的ip.txtdo /usr/bin/expect <<-END &>/dev/null #-是制表符,如果没有的话,下面的END要左靠齐,<<看到下面的END后会结束程序 spawn ssh root@$ip #开启一个程序 expect { "yes/no" { send "yes\r";exp_continue } "password:" { send "$pass\r" }} expect "#" { send "useradd hua;rm -rf /tmp/*;exit\r" } #exit退出去再回车 expect eof #代表这个程序结束 /usr/bin/expect但还是撤不出来,所以后面要敲一个END,看到他完全撤出 ENDecho "$ip服务器用户创建完毕"done /dev/null spawn ssh root@$ip expect { "yes/no" { send "yes\r";exp_continue } "password:" { send "$pass\r" }} expect "#" { send "useradd huachuanbin;rm -rf /tmp/*;exit\r" } expect eof ENDecho "$ip服务器用户创建完毕"done < ip.txt
简单实现步骤:
#1、先在主机A创建yunwei用户,并切入该账户,生成秘钥对ssh-keygen 提示后一直输入回车即可ssh-keygen -P '' -f id_rsa #这里可以跳过提示直接生产文件,但是不会生成.ssh目录#2、进入存放公钥的隐藏目录cd /home/yunwei/.ssh可以看到公钥是id_rsa.pub#3、复制公钥到B主机ssh-copy-id root@B在B服务器中的/root/.ssh目录下面有authorized_keys文件,该文件内容是和A服务器的id_rsa.pub一致#4、这样就可以实现主机A可以免密登录主机B
写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上
说明:主机和密码文件已经提供
1、跳板机上的yunwei用户生成密钥对
2、判断expect程序是否安装
3、判断局域网内主机是否ping通(循环判断)
4、测试验证是否免密登录
把生成的公钥推送到能够ping通的主机
测试验证是否免密登录成功
循环判断局域网内主机是否ping通
检查
jumper-server 有yunwei用户yunwei用户sudo授权登录root用户执行visudo命令,加上yunwei## Allow root to run any commands anywhereroot ALL=(ALL) ALLyunwei ALL=(root) NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf /这段话意思是ALL=(root)以管理员root身份去做事情,不要输入密码NOPASSWD:ALL,不要关机!/sbin/shutdown,不要关机!/sbin/init,不要删除根下面的所有文件!/sbin/shutdown解释说明:1)第一个字段yunwei指定的是用户:可以是用户名,也可以是别名。每个用户设置一行,多个用户设置多行,也可以将多个用户设置成一个别名后再进行设置。2)第二个字段ALL指定的是用户所在的主机:可以是ip,也可以是主机名,表示该sudo设置只在该主机上生效,ALL表示在所有主机上都生效!限制的一般都是本机,也就是限制使用这个文件的主机;一般都指定为"ALL"表示所有的主机,不管文件拷到那里都可以用。比如: 10.1.1.1=...则表示只在当前主机生效。3)第三个字段(root)括号里指定的也是用户:指定以什么用户身份执行sudo,即使用sudo后可以享有所有root账号下的权限。如果要排除个别用户,可以在括号内设置,比如ALL=(ALL , ! orac1e, !pos).4)第四个字段ALL指定的是执行的命令:即使用sudo后可以执行所有的命令。除了关机和删除根内容以外;也可以设置别名。NOPASSwD:ALL表示使用sudo的不需要输入密码。5)也可以授权给一个用户组%admin ALL=(ALL) ALL表示admin组里的所有成员可以在任何主机上以任何用户身份执行任何命令#!/bin/env bash#判断公钥是否存在[ ! f /home/yunwei/.ss/id_rsa ] && ssh-keygen -P '' -f ~/.ssh/id_rsa#循环判断主机是否ping通,如果Ping通推送公钥tr ':' ' ' /dev/null if [ $? -eq 0 ];then echo $ip >> ~/ip_up.txt /usr/bin/expect <<-END &> /dev/null spawn ssh-copy-id root@ip expect { "yes/no" { send "yes\r";exp_continue } "password:" {send "$pass\r" } } expect eof END fi}&donewaitecho "公钥已经推送完毕,正在测试........"#测试验证remote_ip=`tail -1 ~/ip_up.txt`ssh root@$remote_ip hosname &>/dev/nulltest $? -eq 0 && echo "公钥成功推送完毕"
功能一:管理员创建用户和安装expect软件包
#!/bin/env bashhome_dir=/home/yunwei/#判断yunwei账号是否存在{id yunwei[ $? -ne 0 ]&& useradd yunwei && echo 123456|passwd --stdin yunwei} &> /dev/null#判断expect程序是否安装rpm -q expect[ $? -ne 0 ] && yum -y install expect && echo "expect 软件已经成功安装"
功能二:切换运维用户判断主机是否ping通,并且运维用户推送公钥
(1)for循环写法
#!/bin/env bash
#判断密钥对是否存在(输完这一步,切换到命令行模式,输入set list,END前面会有一个^I,这个就是制表符)
#判断是否存在秘钥文件,没有则生成,并生成到目录/home/yunwei/.ssh/下面
home_dir=/home/yunwei
[ ! -f $home_dir/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f $home_dir/.ssh/id_rsa &>/dev/null
#循环检查主机的网络并且进行公钥推送
ip_txt=$home_dir/ip.txt
for i in `cat $ip_txt`
do
ip=`echo $i|cut -d: -f1`
pass=`echo $i|cut -d: -f2`
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
/usr/bin/expect <<-END
set timeout 10
spawn ssh-copy-id root@$ip
expect "yes/no" { send "yes\r";exp_continue }
expect "password:" { send "$pass\r" }
expect eof
END
else
echo $ip >>$home_dir/ip_down.txt
fi
done
(2)while循环写法
#!/bin/env bash
#判断密钥对是否存在(输完这一步,切换到命令行模式,输入set list,END前面会有一个^I,这个就是制表符)
home_dir=/home/yunwei
[ ! -f $home_dir/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f $home_dir/.ssh/id_rsa &>/dev/null
#循环检查主机的网络并且进行公钥推送
ip_txt=$home_dir/ip.txt
while read ip pass
do
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
/usr/bin/expect <<-END
set timeout 10
spawn ssh-copy-id root@$ip
expect "yes/no" { send "yes\r";exp_continue }
expect "password:" { send "$pass\r" }
expect eof
END
else
echo $ip >>$home_dir/ip_down.txt
fi
done</home/yunwei/ip.txt
注释:
for循环用的ip.txt文件内容是192.168.178.129:123456,以冒号分割
while循环用的ip.txt文件内容是192.168.178.129 123456,以空格分割
#!/bin/env bash#判断密钥对是否存在(输完这一步,切换到命令行模式,输入set list,END前面会有一个^I,这个就是制表符)home_dir=/home/yunwei[ ! -f $home_dir/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f $home_dir/.ssh/id_rsa &>/dev/null#循环检查主机的网络并且进行公钥推送while read ip pass #把:号变成空格,处理的数据来自于ip.txt,并赋值给while的变量do ping -c1 $ip &>/dev/null if [ $? -eq 0 ];then echo $ip >> ~/ip_up.txt /usr/bin/expect <<-END &>/dev/null set timeout 10 spawn ssh-copy-id root@$ip expect { "yes/no" { send "yes\r";exp_continue } "passwd:" { send "$pass\r" } } expect eof END else echo $ip >>$home_dir/ip_down.txt fidone
1、普通数组只能使用整数作为数组索引(元素的下标)2、关联数组可以使用字符串作为数组索引(元素的下标)
数组名[索引下标]=值
arrary[0]=v1
arrary[1]=v2
arrary[2]=v3
arrary[3]=v4
数组名=(值1 值2 值3 .....)
array=(var1 var2 var3)
array1=(`cat /etc/passwd`) #将文件中每一行赋值给array1数组,注意要把密码文件的空格去掉:sed 's/ //g' /etc/passwd把空格替换为没有空格
array2=(`ls /root`)
array3=(harry amy jack "Miss Hou")
array4=(1 2 3 4 "hell world" [10]=linux)
${数组名[元素下标]}
echo ${array[0]} #获取数组里第一个元素
echo ${array[*]} #获取数组里的所有元素
echo ${#array[*]} #获取数组里的所有元素个数
echo ${!array[@]} #获取数组元素的索引下标
echo ${array[@]:1:2} #访问指定的元素;1代表从下标为1的元素开始获取,2代表获取后面几个元素
查看普通数组信息:
declare -a
declare -A asso_array1
declare -A asso_array2
declare -A asso_array3
数组名[索引or下标]=变量值
#asso_array1[linux]=one
#asso_array1[java]=two
#asso_array1[linux]=three
查看:declare -A
asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="miss you")
let方式,可以定义下标和值
[root@localhost ~]# declare -A books #定义数组
[root@localhost ~]# let books[linux]++ #定义一个数组名和变量值
[root@localhost ~]# declare -A #查看数组信息
declare -A books='([linux]="1" )'
[root@localhost ~]# let books[linux]++ #在当前数组在执行++
[root@localhost ~]# declare -A
declare -A books='([linux]="2"
[root@localhost ~]# let books[java]+=5 #定义一个数组名,变量值直接为5
[root@localhost ~]# declare -A
declare -A books='([java]="5" [linux]="2" )'
113节
[root@localhost hua]# A=/root/huachuanbin/hua/a.txt #一个文件目录和文件赋予给A[root@localhost hua]# echo $A/root/huachuanbin/hua/a.txt[root@localhost hua]# dirname $A #取出目录/root/huachuanbin/hua[root@localhost hua]# basename $A #取出文件a.txt
一个"%"代表从右往左去掉一个/key/两个"%%"代表从右往左最大去掉/key/一个"#"代表从左往右去掉一个/key/两个"##"代表从左往右最大去掉/key/举例:[root@localhost hua]# url=www.taobao.com[root@localhost hua]# echo ${#url} #输出多少个字节14[root@localhost hua]# echo ${url#*.} #从左往右去掉一个key,以点为分割taobao.com[root@localhost hua]# echo ${url##*.} #从左往右最大去掉key,以点为分割,输出comcom[root@localhost hua]# echo ${url%.*} #从右往左去掉一个key,以点为分割,*通配符,代表.后面的值www.taobao[root@localhost hua]# echo ${url%%.*} #从右往左最大去掉key,以点为分割www
写一个脚本,统计web服务的不同连接状态个数
1、找出查看网站连接的状态的命令
两者的命令执行结果是一样的,监听状态的顺序不一致
netstat -antp | grep 80
ss -antp | grep 80|awk -F' ' '{print $1}'
2、如何统计不同的状态,循环去统计,需要计算
#!/bin/env bash
declare -A status
s=`ss -antp | grep 80|awk -F' ' '{print $1}'`
for i in $s
do
let status[$i]++
done
for j in ${!status[*]}
do
echo $j: ${status[$j]}
done
输出结果为:
[root@localhost ~]# ./test.sh
ESTAB: 1
TIME-WAIT: 2
LISTEN: 1
1、case语句为多重匹配语句
2、如果匹配成功,执行相匹配的命令
说明:pattern表示需要匹配的模式
case var in #定义变量;var代表是变量名
pattern 1) #模式1;用|分割多个模式,相当于or,比如可以这样 hell|workd|h)
commamd1 #需要执行的语句
;; #两个分好代表命令结束
pattern 2)
commamd2
;;
pattern 3)
commamd3
;;
*) #default,不满足以上模式,默认执行*)下面的语句
commamd4
;;
esac #esac表示case语句结束
#!/bin/env bash
case $1 in
start|s)
service httpd start &>/dev/null && echo "service is starting....."
;;
stop|t)
service httpd stop &>/dev/null && echo "service is stoping......"
;;
restart|r)
service httpd restart &>/dev/null && echo "service is restarting........."
;;
*)
echo "请输入你要的动作"
;;
esac
作者写的:两层case,实现指定的服务和动作
#!/bin/env bash
read -p "请输入需要管理的服务名称(ftp|httpd):" service
case $service in
httpd|apache)
read -p "请输入要操作的动作:" action
case $action in
start|s)
service httpd start &>/dev/null && echo "service is starting....."
;;
stop|t)
service httpd stop &>/dev/null && echo "service is stoping......"
;;
restart|r)
service httpd restart &>/dev/null && echo "service is restarting........."
;;
esac
;;
vsftpd|ftp)
echo "ftp is running"
;;
*)
echo "请输入你要管理的服务名称ftp|httpd"
;;
esac
自己写的,可以实现用户自己输入服务,然后输入动作
#!/bin/env bash
read -p "请输入需要管理的服务名称:" service
read -p "请输入要操作的动作:" action
case $action in
start|s)
service $service start &>/dev/null && echo "$service service is starting....."
;;
stop|t)
service $service stop &>/dev/null && echo "$service service is stoping......"
;;
restart|r)
service $service restart &>/dev/null && echo "$service service is restarting........."
;;
*)
echo "请输入动作(start|stop|restart)"
esac
需求:
模拟一个多任务维护界面;当执行程序时先显示总菜单
**********请选择**********h 显示命令帮助f 显示磁盘分区d 显示磁盘负载m 查看内存使用u 查看系统负载q 退出程序*************************
思路:
1、打印菜单
2、交互式让用户输入操作编号,然后做出相应处理
1、cat可以处理标准输入的内容,并打印出来,如下遇到END则结束,并输出
[root@localhost ~]# cat <
> HE
> LOO
> END
HE
LOO
2、切换用户执行命令后还会回到当前用户
(1)切换用户执行东西
[root@localhost ~]# su - yunwei <
> echo hello
> END
上一次登录:三 9月 1 03:05:34 CST 2021pts/0 上
hello
(2)在免密登录的主机上执行建立文件
[root@localhost ~]# ssh [email protected]<
> cd /home/huachuanbin
> touch test.test
> END
落地实现:
每次都会打印菜单在上面,并且执行一个命令之前会清屏
#!/bin/env bash
#1、菜单打印
cat <<EOF
**********请选择**********
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘负载
m 查看内存使用
u 查看系统负载
q 退出程序
*************************
EOF
#2、用户选择内容
while read -p "请选择需要操作的内容(help h)" action
do
clear #清屏
cat <<-EOF
**********请选择**********
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘负载
m 查看内存使用
u 查看系统负载
q 退出程序
*************************
EOF
case $action in
h|help)
cat <<-EOF
**********请选择**********
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘负载
m 查看内存使用
u 查看系统负载
q 退出程序
*************************
EOF
;;
f)
lsblk
;;
d)
df -h
;;
m)
free -h
;;
u)
uptime
;;
q)
exit
;;
*)
echo "请输入正确值"
esac
done
方法1:
函数名()
{
函数体(一堆命令的稽核,来实现某个功能)
}
方法2:
function 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
函数中return说明:
function 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
echo hello
return #1、return可以结束一个函数
echo world
return 10 #2、return默认返回函数中最后一个命令状态值,也可以给定参数值,用$?可以看到是10
}
#专门写一个函数文件,然后sourc这个文件(重新读取),直接输入函数名会出现函数里的结果
#!/bin/env bash
hello()
{
echo "is hello function!"
}
haha()
{
echo $1 #定义一个传参的函数
}
[root@localhost ~]# source test.sh
[root@localhost ~]# hello
is hello function!
[root@localhost ~]# haha 888
888
1、定义到用户的环境变量下,局部变量
[root@localhost ~]# vi ~/.bashrc
文件中增加如下内容
menu()
{
cat <<EOF
**********请选择**********
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘负载
m 查看内存使用
u 查看系统负载
q 退出程序
*************************
EOF
}
haha()
{
echo $1
}
注意:当用户打开bash的时候会读取该文件
2、定义到全局的变量下
把函数编写到下面
vi /etc/bashrc
1、简单的脚本调用
#!/bin/env bash
hello()
{
echo "is hello function!"
}
haha() #调用函数
2、一个脚本调用其他脚本函数
#!/bin/env bash
hello()
{
echo "is hello function!"
}
source /root/test.sh #读取另外一个脚本
hello;world #调用本脚本和其他脚本函数
需求:
思路:
交互式定义多个变量来保存用户信息
如果不输入一直提示输入
根据用户输入信息做出匹配判断
#简单实现用户输入姓名,如不输入一直提示输入
#!/bin/bash
input_fun()
{
input_var="" #先定义一个输入的变量为空值
output_var=$1 #把第一个参数复制给输出的变量
while [ -z $input_var ] #判断输入变量是否为空
do
read -p "$output_var" input_var #读取第一个参数的值(请输入你的姓名:),变量为输入变量
done
echo $input_var #如果输入变量有值,那么直接输出值
}
input_fun 请输入你的姓名: #这个代表函数的第一个参数$1
脚本最终实现
#1、最终实现连续输入三个内容,如不输入一直提示输入(第一种方法)
#!/bin/bash
input_fun()
{
input_var="" #先定义一个输入的变量为空值
output_var=$1 #把第一个参数复制给输出的变量
while [ -z $input_var ] #判断输入变量是否为空
do
read -p "$output_var" input_var #读取第一个参数的值(请输入你的姓名:),变量为输入变量
done
echo $input_var #如果输入变量有值,那么直接输出值
}
name=`input_fun 请输入你的姓名:`
sex=`input_fun 请输入你的性别:`
old=`input_fun 请输入你的年龄:`
echo 姓名结果:$name
echo 性别结果:$sex
echo 年龄结果:$old
#2、最终实现连续输入三个内容,如不输入一直提示输入(第二种方法),并使用case
#!/bin/bash
fun()
{
read -p "$1" name
if [ -z $name ];then
fun $1
else
echo $name
fi
}
#调用函数并且获取用户的姓名、性别、年龄分别赋值给na、sex、age
na=`fun 请输入你的姓名:`
sex=`fun 请输入你的性别:`
age=`fun 请输入你的年龄:`
echo $na
echo $sex
echo $age
#通过性别判断年龄阶段
case $sex in
man|m)
if [ $age -gt 18 -a $age -le 35 ];then
echo "你是中年大叔!"
elif [ $age -gt 35 ];then
echo "你是老年人"
else
echo "你是年轻人"
fi
;;
woman|w)
if [ $age -gt 18 -a $age -le 35 ];then
echo "你是中年大妈!"
elif [ $age -gt 35 ];then
echo "你是老年大妈"
else
echo "你是女孩"
fi
;;
*)
echo "请输入m或者w判断"
;;
esac
1、任务背景
现有跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可以操作跳板机上的所有目录文件,存在数据被误删除的安全隐患,所有希望做一些安全策略来保证跳板机的正常使用
2、具体需求
欢迎使用jumper-server,请选择你要操作的主机:
1.DB1-Master
2.DB2-Slave
3.web1
4.web2
h.hlep
q.exit
3、综合分析
脚本实现
实现登录运维账号先提示菜单供用户选择
把以下脚本文件放到yunwei账号家目录/home/yunwei,在运维的家目录/home/yunwei/.bashrc添加以下内容:
/home/yunwei/t.sh #执行脚本
exit #当执行完脚本q键后,执行exit命令,就可以实现当用户操作完之后直接退出终端
#!/bin/env bash
#菜单打印
menu()
{
cat <<EOF
******请选择******
1.DB1-Master
2.DB2-Slave
3.web1
4.web2
h.hlep
q.exit
*****************
EOF
}
trap : 2 #屏蔽信号,当按下ctrl+c没有任何反应
menu
while true
do
read -p "请选择你要访问的主机:" host
case $host in
1)
ssh [email protected] source 1.sh # 在这末尾加source 1.sh代表读取130主机的这个脚本,把一些功能写进130主机,这样就能实现跨主机访问
;;
2)
ssh [email protected]
;;
3)
echo "您已进入web1"
;;
4)
echo "您已进入web2"
;;
h)
echo "hlep文档"
;;
q)
exit
;;
*)
echo 请重新输入
;;
esac
done
回顾信号:
查看:kill -l
1、sighub 重新加载配置
2、sigint 键盘终端ctrl+c
3、sigquit 键盘退出
9、sigkill 强制终止
15、sigterm 终止(正常结束),缺省信号
18、sigcont 继续
19、sigstop 停止
20、sigtstp 暂停ctrl+z
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。
许多程序设计语言都支持到用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。
正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。支持正则表达式的程序如: locate | find | vim| grep | sed | awk
元字符
指那些在正则表达式中具有特殊意义的专有字符,如点(.)、星(*)、问号(?)等
前导字符
位于元字符前面的字符 abc* aooo.
元字符 | 功能 | 备注 |
---|---|---|
. | 匹配除了换行符以外的任意单个字符前导字符出现0次或连续多次任意长度字符 | grep ‘g.’ 1.txt |
* | 前导字符出现0次或连续多次 | grep ‘g*’ 1.txt ,没有g的也会打印出来,因为是0次或者多次,如果是grep ‘gg*’ 1.txt,要匹配gg才可以,因为第一个g是固定死了(g后面有*), grep ‘gg.*’ 1.txt,匹配gg后面的的点星,后面啥都可以匹配 |
.* | 任意长度字符 | ab.* |
^ | 行首(以…开头) | grep ‘^g.’ 1.txt,匹配g开头的并且后面有一个字符 |
$ | 行尾(以…结尾) | grep ‘e$’ 1.txt |
^$ | 空行 | |
[] | 匹配括号里任意单个字符或一组单个字符 | grep ‘[dg]’ 1.txt,匹配d或者g |
[^] | 匹配不包含括号里任一单个字符或一组单个字符 | grep ‘【^gd】’ 1.txt,匹配不包含gd的行,区别在于内容和【gd】 |
1 | 匹配以括号里任意单个字符或一组单个字符开头 | grep ‘2’ 1.txt,匹配d或者g开头 |
[] | 匹配不以括号里任意单个字符或一组单个字符开头 | grep '【gd】'1.txt,匹配不以g或者d开头的行,区别在于开头 |
注意,这里有\杠,被隐藏了
元字符 | 功能 | 备注 |
---|---|---|
< | 取单词的头 | grep ‘ |
> | 取单词的尾 | |
< > | 精确匹配 | grep ‘ |
{n } | 匹配前导字符连续出现n次 | grep ‘g{3}’ 1.txt,匹配g连续出现3次 |
{n,} | 匹配前导字符至少出现n次 | |
{n,m} | 匹配前导字符出现n次与m次之间 | grep ‘[0-9]{3}’ 1.txt,匹配数字出现3次,grep ‘[0-9]{3}.[0-9]{3}.[0-9]{3}.[0-9]{3}’ 1.txt,匹配ip地址 |
( ) | 保存被匹配的字符 | |
\d | 匹配数字(grep -P) | grep -P ‘\d’ 1.txt |
\w | 匹配字母数字下划线(grep -P) | [a-zA-Z0-9],grep -P ‘\w’ 1.txt |
\s | 匹配空格、制表符、换页符(grep -P) | [\t\r\n] |
举例说明:
1、进入:模式,%s代表全文搜索(1)输入%s/192.168.178.130/192.168.178.129/g,实现替换ip地址(2)输入%s/\(192.168.178\).129/\1.666/g,保存192.168.178,替换129位666,这里的后面\1代表就是括号里的前三位地址(2)helloworld yourself替换为yourworld helloself,\1代表第一个保存被匹配的字符,\2代表第二个%s/hello\(world\) your\(self\)/your\1hello\2/g2、[root@localhost ~]# grep '\' passwd #精确匹配4、[root@localhost ~]# grep 'go\{2\}' 1.txt #匹配o出现2次googlegoogglegoooooglegooooooogle5、[root@localhost ~]# grep '[0-9]\{2\}' 1.txt #匹配数据出现过两次fdago2344oglegooggle532gooooooogl342355e6、grep -P '\d' 1.txt #匹配数字
扩展元字符 | 功能 | 备注 |
---|---|---|
+ | 匹配一个或多个前导字符 | bo+匹配boo、bo |
? | 匹配0个或一个前导字符 | bo?匹配b、bo |
| | 或 | 匹配a或者b |
() | 组字符(看成整体) | (my|your)self,表示匹配mysql或者匹配yourself |
{n} | 前导字符重复n次 | |
{n,} | 前导字符重复至少n次 | |
{n,m} | 前导字符重复n到m次 |
举例说明:
grep -E "g+" 1.txt #匹配g为1个或多个grep -E 'go?' 1.txt #匹配o为0次或多次,前面有g固定了,所有有g但没有o的也会打印grep -E 'g.?' 1.txt #g固定死了后面任意一个字符出现0次或多次grep -E '^e|^f' 1.txt #匹配e开头或者f开头的行grep -E '^(f|e)' 1.txt #匹配e开头或者f开头的行,()表示看成整体grep -E 'go{2}' 1.txt #匹配o重复出现至少2次,相当于不加-E的grep 'go\{2\}' 1.txt
表达式 | 功能 | 示例 |
---|---|---|
[:alnum:] | 字母与数字字符 | [[:alnum:]]+ |
[:alpha:] | 字母字符(包括大小写字母) | [[:alpha:]]{4} |
[:blank:] | 空格与制表符 | [[:blank:]]* |
[:digit:] | 数字 | [[:digit:]]? |
[:lower:] | 小写字母 | [[:lower:]]{4,} |
[:upper:] | 大写字母 | [[:upper:]]+ |
[:punct:] | 标点符号 | [[:punct:]] |
[:space:] | 包括换行符,回车等在内的所有空白 | [[:space:]]+ |
示例:
grep -E '[[:digit:]]?' 1.txt #匹配数字出现0次或1次grep -E '[[:alnum:]]{5}' 1.txt #匹配字母与数字出现5次,想当于grep -E '[a-z0-9A-Z]{5}' 1.txt
把握一个原则,让你轻松搞定可恶的正则符号
我要找什么?
我要如何找
我要找多少
实例:
1、匹配数字出现2次grep '[0-9]\{2\}' 1.txtgrep -E '[0-9]{2}' 1.txt grep '[0-9]\{3,5\}' 1.txt #匹配数字出现3到5次grep '[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.' 1.txt #匹配ip地址grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' 1.txt #匹配ip地址grep -E '([0-9]{1,3}\.){3}.[0-9]{1,3}' 1.txt #匹配ip地址,看成整体()用法grep -P '\d{1,3}\.\d{1,3}.\d{1,3}.\d{1,3}' 1.txt #匹配ip地址,-P和\d用法grep -P '\d+\.\d+\.\d+\.\d+' 1.txt #匹配ip地址,-P和\d用法2、匹配不以#开头的行grep '^[^#]' version-groups.conf
#1、查找不以大写字母开头的行(三种写法)。grep '^[^A-Z]' 1.txtgrep -v '^[A-Z]' 1.txtgrep '^[^[:upper:]]' 1.txt #2、查找有数字的行(两种写法)grep -P '\d' 1.txtgrep '[0-9]' 1.txt#3、查找一个数字和一个字母连起来的grep '[0-9][a-zA-Z]' 1.txtgrep -E '[0-9][a-zA-Z]|[a-zA-Z][0-9]' 1.txt #4、查找不以r开头的行grep '^[^r]' 1.txtgrep -v '^r' 1.txt #5、查找以数字开头的grep '^[0-9]' 1.txt#6、查找以大写字母开头的 grep '^[A-Z]' 1.txt #7、查找以小写字母开头的 grep '^[a-z]' 1.txt #8、查找以点结束的grep '\.$' 1.txt #9、去掉空行grep -v '^$' 1.txt#10、查找完全匹配abc的行 grep '\' 1.txt grep 'abc' 1.txt grep -w 'abc' 1.txt #11、查找A后有三个数字的行grep -E 'A[0-9]{3}' 1.txtgrep 'A[0-9]\{3\}' 1.txt #12、统计root在/etc/passwd里出现了几次grep -o 'root' 1.txt|wc -l#13、用正则表达式找出自己的IP地址、广播地址、子网掩码ifconfig ens33| grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}'ifconfig ens33|grep -o -P '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'ifconfig ens33|grep -o -P '(\d{1,3}\.){3}\d{1,3}'ifconfig ens33|grep -o -P '(\d{1,3}\.){3}\d+'#14、找出文件中的ip地址并打印替换成172.16.2.129ifconfig ens33|grep -o -P '(\d{1,3}\.){3}\d+'|sed -n 's/192.168.178.\(129\)/172.16.2.\1/p' #15、找出文件中的ip地址ifconfig ens33|grep -o -P '(\d{1,3}\.){3}\d+'#16、找出全部是数字的行grep -E '^[0-9]+$' 1.txt #17、找出邮箱地址grep -E '^[0-9]+@[a-z0-9]+\.[a-z]+$' 1.txt #匹配@前面只是数字的grep -E '^([0-9]|[a-z])+@[a-z0-9]+\.[a-z]+$' 1. #匹配@前面有数字和字母的grep -E '^[0-9a-zA-Z]+@[a-z0-9]+\.[a-z]+$' 1.txt #匹配@前面有数字和字母的
↩︎
dg ↩︎
abc ↩︎
尖号abc ↩︎