Shell编程
- 一、简介
- 学习shell脚本的目的
- shell脚本的阶段
- 脚本执行的两种方法
- shell分类
- 二、Bash基本功能
- 1. history (列出当前用户的当前终端的历史命令缓存信息)
- 2. echo命令 (输出结果)
- 2.1 -e选项支持的特殊符号列表
- 2.2 echo 显示颜色
- 3. alias命令别名
- 3.1 查看目前生效了的别名
- 3.2 临时取消当前生效的别名
- 3.3 别名永久存放的位置
- 3.4 别名编写规范
- 4. 命令与文件名的补全
- 命令的分类
- 执行命令的方式
- 不同类型的命令执行的优先级顺序
- 5. Bash常用快捷键
- 6.输入输出重定向
- 6.1 bash的标准输入输出
- 6.2 bash的输出重定向
- 6.3 wc(返回文件统计结果)
- 6.4 cpio 命令
- 7. 多命令顺序执行
- 8. grep命令
- 8.1 通用匹配符
- 8.2 find 、grep和locate各自的特点和区别
- 9. 管道符
- 三、Bash中特殊符号
- 重点:特殊符号
- 四、shell的变量
- 1. 变量叠加
- 2. 变量的分类
- 2.1 用户自定义变量
- 1)变量调用
- 2)变量查看
- 3)变量删除
- 2.2 环境变量
- 1)环境变量设置
- 2)环境变量查询
- 3)系统默认的环境变量
- 4)让脚本执行跟命令执行方式一样
- 5)PS1变量:命令提示符设置
- 6)LANG变量:系统语系变量
- 2.3 位置参数变量
- 2.4 预定义变量
- 3. read 接收键盘输入
- 4. shell声明运算符命令
- 4.1 数组型
- 4.2 整数型
- 4.3 环境变量
- 4.4 只读变量
- 4.5 查询变量
- 4.6 使用expr或let进行数值运算
- 4.7 使用 $ ( ( 运算式 ) ) 或 ((运算式)) 或 ((运算式))或$[运算式]格式进行运算
- 五、shell常用运算符
- 六、环境变量的配置
- 6.1 source 命令
- 6.2 文件调用的顺序
- 6.3 注销专用环境变量配置文件
- 6.4 shell登录信息
- 6.4.1 /etc/issue
- 6.4.2 /etc/motd
- 6.5 bash快捷键
- 七、正则表达式
- 7.1 基础正则表达式
- 7.2 扩展正则表达式
- 7.3 grep结合正则实现精确匹配
- 7.4 练习
- 八、字符截取和替换命令
- 1. cut 提取命令
- 2. awk命令
- 2.1 awk的格式和组成结构
- 2.2 扩展:动作{prinf}
- 2.3 awk条件
- BEGIN 开始,开头
- END 末尾,结束
- awk关系运算条件
- awk包含匹配条件
- awk内置变量
- awk数值运算
- 2.4 awk编程注意事项
- 2.5 awk的工作原理
- 3. sed命令
- 4. sort 字符排序
- 5. uniq 取消重复行
- 九、条件判断
- 1.按照文件类型进行判断
- 2.按照文件权限进行判断
- 3.两个文件之间进行比较
- 4.两个整数之间进行比较
- 5.字符串的判断
- 6.多重条件判断
- 十、流程控制
- 1.if条件判断
- 2.case分支语句
- 3.for循环
- 4.while循环
- 5.until循环
- 6.特殊流程控制语句
- 7.死循环
- 8.流程练习
- 扩展
- date 命令
- 实现命令检测工具
一、简介
作用:shell提供了用户与内核进行交互操作的一种接口
实际上shell就像语言翻译人员,它将用户输入的命令解释成二进制文件发送到内核中。同理从内核中将二进制文件解释的结果发送到应用程序并将显示结果呈现给用户。
学习shell脚本的目的
- 将重复性的工作用脚本代替
- 将较为复杂的操作流程脚本化,降低错误出现的概率
shell脚本的阶段
- 写脚本就是命令的堆叠
- 要求脚本能进行环境自适应、兼容性
- 包含着逻辑判断、流程控制等
脚本执行的两种方法
1.添加执行权限,然后相对路径或者绝对路径执行 -被动2.使用bash命令直接调用脚本执行 -主动
shell分类
shell类型 | 易学性 | 可移至性 | 编辑性 | 快捷性 |
---|---|---|---|---|
sh | 容易 | 好 | 较差 | 较差 |
bash | 难 | 较好 | 好 | 好 |
csh | 较难 | 差 | 较好 | 较好 |
tcsh | 难 | 差 | 好 | 好 |
[root@localhost ~]# cat /etc/shells #查看支持的shell类型 /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh /sbin/nologin #后续增加的shell类型
二、Bash基本功能
1. history (列出当前用户的当前终端的历史命令缓存信息)
history -w #强制将当前缓存中的命令保存到配置文件 #注意:不同终端执行时,会覆盖掉之前配置文件中的历史命令
~/.bash_history #是当前用户永久保存历史命令的配置文件 #必须是正常退出用户才能将缓存中的保存配置文件 #该配置文件默认最多保存1000条历史命令
历史命令调用
调用之前使用过的历史命令有以下几种办法:使用上、下光标键调用使用“!n”,重复执行第n条历史命令使用“!!”,重复执行上一条命令使用“!字符”,重复执行最近一条以此字符开头的命令 #查询当前所登录的用户身份:id、who、whoami
2. echo命令 (输出结果)
echo [选项] [输出内容] 选项 -e:支持\控制的字符转换 -n:取消换行符号
2.1 -e选项支持的特殊符号列表
控制字符 | 作用 |
---|---|
\\ | 输出本身 |
\a | 输出警告音 |
\b | 向左删除键 |
\c | 取消换行符,和-n选项一致 |
\e | 输出颜色,需要搭配相应的颜色代码 |
\f | 换页符 |
\n | 换行符 |
\r | 回车键 |
\t | 制表符 |
\v | 垂直制表符 |
\0nnn | 八进制ASCII码表输出字符,其中0是数字0,nnn是三位八进制数 |
\xhh | x十六进制ASCII输出字符,hh两位十六进制数 |
#注意:umask第一个位置其实是这个进制标识符,特殊情况是四位,平常是三位 umask 00644 #第一个位置:进制标识符。表示后续是八进制 #第二个位置:代表特殊权限:SUID、SGID、SBIT #第三个位置:代表所有者权限 #第四个位置:代表所属组权限 #第五个位置:代表其他人权限 chomod 00644 filename#这是执行之后的代码,很明显表示进制越界 [root@localhost ~]# umask 00022 [root@localhost ~]# umask 0022 [root@localhost ~]# umask 10022 bash: umask: 10022: 八进制数 越界
#新建一个文件,输入以下内容,然后保存执行 #!/bin/bash echo -e "student\tname\tphone\t\t address" echo -e "ltz \tltz \t18333661034 \t langfang " echo -e "ltz \tltz \t18333661034 \t langfang "
2.2 echo 显示颜色
格式:“\e[m” 代表颜色输入开始; “\e[m” 代表颜色结束文字颜色:30=黑色,31=红色,32=绿色,33=黄色,34=蓝色,35=紫色,36=天蓝,37=白色,39=结束 底纹颜色:40=黑色,41=红色,42=绿色,43=黄色,44=蓝色,45=紫色,46=天蓝,47=白色,49=结束
特殊的显示
\e[0m 关闭所有属性 \e[1m 设置高亮度 \e[4m 下划线 \e[5m 闪烁 \e[7m 反显 \e[8m 消隐注意:多个条件之间用分号(;)隔开,同时生效
#新建一个文件,输入以下内容,然后保存执行 #!/bin/bash echo -e "\e[35;1m helloworld \e[0m" echo -e "\e[35;4m helloworld \e[0m" echo -e "\e[35;5m helloworld \e[0m" echo -e "\e[35;7m helloworld \e[0m" echo -e "\e[35;8m helloworld \e[0m"
3. alias命令别名
3.1 查看目前生效了的别名
alias
3.2 临时取消当前生效的别名
unalias
3.3 别名永久存放的位置
1. ~/.bashrc #针对指定用户 2./etc/bashrc #针对所有用户
3.4 别名编写规范
1. 格式:alias 别名=“实际命令+选项” 2. 别名名称不能和已存在的命令发生冲突,改变已有的命令的功能 #别名含义和实际命令作用相同可以覆盖源命令
可以使用转义符来取消命令的别名,使用命令的本意。
find / -name hosts -exec cp {} /root/exam/files/hosts-bak \; #取消了cp的别名 cp -i
4. 命令与文件名的补全
使用tab按钮,提供了如命令补全、路径补齐等功能
注意:补齐功能有时候会将目录结尾处自动补上/符号,导致系统识别出现问题,从而报错
命令的分类
1. 相对或绝对路径 2. 安装软件包产生的命令 3. 别名命名
执行命令的方式
1. 相对或绝对路径 2. 查看环境变量,查看命令是否存在 #PATH的作用:将存放了命令的路径保存到当前变量,方便执行命令前进行查询 echo $PS1 #输出终端中“[yang@localhost ~]$格式 [\u@\h \W]\$
不同类型的命令执行的优先级顺序
first: 用绝对路径或相对的当时执行命令 second:别名命令 third: bash内置命令 forth: 根据环境变量定义的目录查询找到的命令
命令 & : 将命令放入后台继续执行
ctrl+z : 将命令放入后台暂停执行
[root@localhost ~]# ping 127.0.0.1 & [1] 103410 [root@localhost ~]# PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.025 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.100 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.099 ms ^Z [1]+ 已停止 ping 127.0.0.1
5. Bash常用快捷键
快捷键 | 作用 |
---|---|
ctrl+c | 强制终止当前命令 |
ctrl+l | 清屏, 相当于clear |
ctrl+u | 删除或剪切光标之前命令 |
ctrl+k | 删除或剪切光标之后的命令 |
ctrl+y | 粘贴ctrl+u或ctrl+k剪切的内容 |
ctrl+r | 按下快捷键,会出现搜索页面,搜索想要的命令范围是在执行过的历史命令 |
ctrl+d | 退出当前终端 |
6.输入输出重定向
6.1 bash的标准输入输出
设备 | 设备文件名 | 文件描述符 | 类型 |
---|---|---|---|
键盘 | /dev/stdin | 0 | 标准输入 |
显示器 | /dev/stdout | 1 | 标准正确输出 |
显示器 | /dev/stderr | 2 | 标准错误输出 |
6.2 bash的输出重定向
类型 | 符号 | 作用 |
---|---|---|
命令 > 文件 | 以覆盖的方式,将正确输出写入文件 | |
标准输出重定向 | 命令 >> 文件 | 以追加的方式,将正确输出写入文件 |
错误命令 2> 文件 | 以覆盖的方式,将错误输出写入文件 | |
标准错误输出重定向 | 错误命令 2>> 文件 | 以追加的方式,将错误输出写入文件 |
命令 > 文件 2>&1 | 以覆盖的方式,将正确输出错误输出写入文件 | |
命令 >> 文件 2>&1 | 以追加的方式,将正确输出错误输出写入文件 | |
命令 &> 文件 | 以覆盖的方式,将正确输出错误输出写入文件 | |
正确输出和错误输出同时保存 | 命令 &>> 文件 | 以追加的方式,将正确输出错误输出写入文件 |
正确输出和错误输出分开保存 | 命令>>文件1 2>>文件2 | 将正确的输出追加到文件1中,把错误的输出追加到文件2中。 |
伪设备/dev/zero 输出0/dev/null 类似黑洞#将命令结果丢弃 命令 &> /dev/null #判断命令是否执行成功 echo $? ---------------------------------------------------------------- ##输入重定向 : 用来将指定的字符串导入给命令<和<<[root@localhost ~]# vim yufeng.sh#!/bin/bashcat << EOFwangxuanceEOF[root@localhost ~]# ./yufeng.sh wangxuance#结果输出wangxuance#使用EOF非交互式向文件中写多行内容
6.3 wc(返回文件统计结果)
命令:wc [选项] [文件名]-c 统计字数-w 统计字符串数量-l 统计行数
[root@localhost ~]# wc logbak.sh 8 20 116 logbak.sh [root@localhost ~]# wc -c logbak.sh 116 logbak.sh [root@localhost ~]# wc -w logbak.sh 20 logbak.sh [root@localhost ~]# wc -l logbak.sh 8 logbak.sh
6.4 cpio 命令
#RPM包解压完之后,会显示以.cpio结尾的压缩包 1.cpio备份模式cpio -ocvB > [文件|设备]-o:进入copy-out模式(压缩)-v:显示过程-c:使用portble format存储方式-B:设定输入输出块为512bytes 2.cpio还原模式cpio -idvcu < [cpio文件]-i:进入copy-in模式(解压)-d:恢复到指定位置(看压缩方式恢复)-v:显示过程-c:使用portble format存储方式-u:替换所有文件
1.利用绝对路径备份&恢复备份:find /etc | cpio -ocvB > /root/et.cpio#利用find找出/etc然后备份到/root下面还原: cpio -idvcu < /root/etc/cpio#由于备份时备份的路径使用的是绝对路径,所有恢复时会按照绝对路径恢复回去,所以不会在/root下生成文件 2.利用相对路径备份&恢复备份步骤:cd /etcfind ./ | cpio -ocvB > /root/et.cpio恢复cd /rootmkdir testcd testcpio -idvcu < /root/etc/cpio #恢复以相对路径备份的etc.cpio文件,内容会被恢复到/root/test/目录下
7. 多命令顺序执行
多命令执行符 | 作用 |
---|---|
; | 多个命令顺序执行,命令之间没有任何逻辑关系 |
&& | 有逻辑判断的命令连接符号,符号前的命令执行成功,符号的命令才执行 |
|| | 符号前的命令执行失败,符号后的命令执行成功 符号前的命令执行成功,符号后的命令执行失败 |
cat hello.sh && cat yufeng.sh ##两个结果一起输出 cat hello.sh || cat yufeng.sh ##只输出第一个文件,因为第一个是正确输出
8. grep命令
命令: grep [选项] "关键词" filename-c:统计包含字符串的行一共多少行-i:忽略大小写-n:输出行号-v:反向查找
8.1 通用匹配符
* 匹配任意长度(数量)的任意字符
? 匹配一个任意字符
[] 匹配括号范围内的任意一个字符
[^] 取反匹配
[-] 匹配中括号内任意一个字符,-代表一个范围
两个要素:1.匹配数量、
2.匹配范围,字符类型
ls,cat,mv,cp,rm ## 只要命令的操作对象是文件名,就可以使用通配符来进行匹配
8.2 find 、grep和locate各自的特点和区别
find 遍历式查询优点:准、全缺点:慢 locate 数据库查询优点:快缺点:不全数据库存放位置:/var/lib/mlocate/mlocate.db配置文件:/etc/updatedb.conf更新数据库命令:updatedb grep 基于文件搜索符合条件的字符串
9. 管道符
格式:命令1 | 命令2 [root@localhost ~]# ls -l /etc/ | more格式:命令 |xargs 命令2 #将命令1的标准输出当做命令2的执行参数(执行对象),默认逐个处理 [root@localhost ~]# find /etc -name *.txt | cat /etc/pki/nssdb/pkcs11.txt [root@localhost ~]# find /etc -name *.txt | xargs cat
三、Bash中特殊符号
重点:特殊符号
‘ ’ #单引号‘字符串’ “” #双引号“字符串” 区别: ## 单引号:所有的被引用的字符没有特殊含义 ## 双引号:大部分被引用的字符没有特殊含义,除$ `` \ !`` #反引号,功能等同于$() $() #将命令的结果调用出来 () #在小括号内执行的命令是在一个全新的子shell中执行的,和当前shell不互通,变量等是无法传回当前shell环境的,可以用用作测试或预览 {} #相当于在当前shell中执行 [] #条件判断工具,等同于test命令文件是否存在和文件是否是某类型的判断-d(目录)、-b(块设备)、-c(字符设备)、-f(文件)、-s(套接字)、-p(管道符文件)、-L(软连接)
两者区别
()执行一串命令时,需要重新开一个子shell进行执行 {}执行一串命令时,是在当前shell执行()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开 ()最后一个命令可以不用分号结尾 {}最后一个命令要用分号结尾 {}的第一个命令和左括号之间必须要有一个空格 ()里的各命令不必和括号有空格
四、shell的变量
变量:可以由字母、数字和下划线组成,不能以数字开头,变量中间不能有空格。是临时存储计算结果或者表示值抽象,可以通过变量名访问
#在Bash中,变量默认类型都是字符串,想进行数值运算,必须改变变量类型为数值型 [root@localhost ~]# x=666 [root@localhost ~]# y=444 [root@localhost ~]# s=$x+$y [root@localhost ~]# echo $s 666+444##变量赋值时,等号两边不能由空格 [root@localhost ~]# name=yang [root@localhost ~]# name= yang -bash: shanchuan: command not found [root@localhost ~]# name =shanchuan -bash: name: command not found
1. 变量叠加
如果需要添加变量的值,那么可以进行变量值的叠加
#格式:变量名= "$变量名 新增值" 或 变量名= "${变量名} 新增值" [root@localhost ~]# name=yang [root@localhost ~]# echo $name yang [root@localhost ~]# name="$name yang" [root@localhost ~]# echo $name yang yang [root@localhost ~]# name="${name} yang" [root@localhost ~]# echo $name yang yang yang
2. 变量的分类
-
自定义变量:由用户自由定义变量名和变量的值
-
环境变量:保存的是和系统操作环境相关的路径。
-
位置参数变量:向脚本传递参数或数据,变量名不能自定义,变量作用是固定的
-
预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
2.1 用户自定义变量
1)变量调用
echo $变量名
2)变量查看
set [选项] #开启针对变量的某些特定功能 [root@localhost shcli]# echo $abc[root@localhost shcli]# [root@localhost shcli]# set -u #调用没有声明的变量时会报错 [root@localhost shcli]# [root@localhost shcli]# echo $abc bash: abc: 为绑定变量 ------------------------------------------------------------ [root@localhost ~]# set -x #命令执行前,会先把本身命令输出一次 [root@localhost ~]# ls + ls --color=auto anaconda-ks.cfg [root@localhost ~]# set +x + set +x [root@localhost ~]# ls anaconda-ks.cfg
3)变量删除
unset 变量名
2.2 环境变量
一般很少声明环境变量,一般都是对系统设置好的进行修改
1)环境变量设置
#export 声明的是环境变量 [root@localhost shcli]# export AGE=18 [root@localhost shcli]# echo "$AGE" 18
2)环境变量查询
#env命令和set命令的区别 # set命令查看所有变量 # env命令只能查看环境变量 --------------------------------------------------------- [root@localhost shcli]# export HFQT=hongfuqitian [root@localhost shcli]# BD=2001 [root@localhost shcli]# [root@localhost shcli]# set | grep HFQT HFQT=hongfuqitian [root@localhost shcli]# set | grep BD BD=2001 [root@localhost shcli]# env | grep HFQT HFQT=hongfuqitian [root@localhost shcli]# env | grep BD
3)系统默认的环境变量
#系统命令存放路径 [root@localhost shcli]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin## “:”用作分割路径,这些都是系统查找命令的路径。在执行命令的时候,在没有设置别名的时候,并且没有写相对或绝对路径的时候,系统会找到PATH变量定义的路径去查找,看是否执行成功
4)让脚本执行跟命令执行方式一样
方法一:把自己写的脚本放到已存在的系统环境目录下
方法二:修改PATH变量值,将脚本目录叠加到PATH变量中
#临时生效 [root@localhost ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/ [root@localhost ~]# PATH="$PATH:./ol" [root@localhost ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/:./ol--------------------------------------------------------------#永久生效 #修改配置文件 ./.bash_profile (当前用户生效) /etc/bashrc(第一优先级) 或 /etc/profile (所有用户生效) source 配置文件 ##刷新配置文件
5)PS1变量:命令提示符设置
PS1是用来定义命令行的提示符的,可以按照我们自己的需求来低能定义提示符
##输出默认格式 [root@localhost ~]# echo $PS1 [\u@\h \W]\$#定义PS1变量值时需要注意单引号 [root@localhost ~]# echo $PS1 [\u@\h \W]\$ [root@localhost ~]# PS1='[\u@\h \W]\$' [root@localhost ~]#cd /etc/sysconfig/ [root@localhost sysconfig]# PS1='[\e[35;1m\u\e[0m@\h \W]\$' [root@localhost sysconfig]#
6)LANG变量:系统语系变量
LANG设置的是Linux系统环境的语言
#第一次安装系统选择的语言是中文,所以默认是zh_CN.UTF-8 [root@localhost ~]# echo $LANG zh_CN.UTF-8 --------------------------------------------------------------- #查看Linux支持的语言 [root@localhost ~]# localectl list-locales | tail -5 zh_TW.euctw zh_TW.utf8 zu_ZA zu_ZA.iso88591 zu_ZA.utf8 [root@localhost ~]# localectl list-locales | wc -l 787 --------------------------------------------------------------- #永久修改操作系统语言 [root@localhost ~]# cat /etc/locale.conf LANG="zh_CN.UTF-8" [root@localhost ~]# localectl set-locale LANG=en_US.utf8 [root@localhost ~]# cat /etc/locale.conf LANG=en_US.utf8##注意:LANG变量的值会随着登录终端是否支持中文而改变
2.3 位置参数变量
位置参数变量 | 作用 |
---|---|
$n | n为数字,$1-$9指的是第一到第九个参数,十以上的参数需要{}包含 |
$* | 这个变量代表命令行中所有的参数,把所有的参数看成一个整体 |
$@ | 也是代表所有的参数,不过把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
[root@localhost ~]# cat shcli/test #!/bin/bash echo $0 # $0代表命令本身 echo $1 echo $2 echo $3 echo $4 [root@localhost ~]# bash shcli/test 1 2 3 4 shcli/test 1 2 3 4
练习脚本
#!/bin/bash echo "统计一共有多少个字符串;$#" ## $#显示参数个数 ## $*显示所有参数(作为整体接收并传递到脚本内) ## $@显示所有参数(分开接收,依次传递到脚本内) n=1 for i in "$*" doecho "value $n:$1:$2:$3"let n=n+1 done
2.4 预定义变量
预定义变量 | 作用 |
---|---|
$? | 最后一次执行命令的返回状态,如果为0,是上条命令正确执行;非0的话,是上条错误执行 |
$$ | 当前进程的进程号(PID) |
$! | 后台运行的最后一个进程的进程号 |
# $? 命令成功返回0,命令执行失败返回非0 [root@localhost ~]# ls anaconda-ks.cfg shcli 视频 音乐 check yum.sh 图片 桌面 check1.sh 公共 文档 initial-setup-ks.cfg 模板 下载 [root@localhost ~]# echo $? 0 [root@localhost ~]# lls bash: lls: 未找到命令... 相似命令是: 'ls' [root@localhost ~]# echo $? 127 --------------------------------------------------------- # $$ 显示当前进程PID [root@localhost ~]# echo $$ 11191 [root@localhost ~]# ps aux | grep 11191 | grep -v grep root 11191 0.0 0.2 116348 2888 pts/1 Ss 00:18 0:00 -bash ---------------------------------------------------------- # $! 最后一个放入后台执行的命令的进程 ## &放入后执行,通常只针对可持续执行的命令 [root@localhost ~]# dd if=/dev/zero of=/dev/null & [1] 16197 [root@localhost ~]# [root@localhost ~]# echo $! 16197 [root@localhost ~]# ps aux | grep 16197 | grep -v grep root 16197 98.3 0.0 107996 620 pts/1 R 04:00 1:36 dd if=/dev/zero of=/dev/null
3. read 接收键盘输入
作用:接收键盘输入,完成交互式操作
read [选项] [变量名]-p “提示信息”:在read等待时输入的信息-t 秒数 :read等待的秒数-n 字符数:read最多能接收的字符数(达标即执行)-s :隐藏输入信息
------------------------------------------------------
read变量名定义:
## 变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY
## 如果只提供一个变量名,则整个输入全部赋予该变量
## 如果提供一个以上的变量名,则输入行分为若干字,一个接一个赋予各变量,而命令行上的最后一个变量取得剩余的所有值
#!/bin/bash read -p "请输入你的名字:" name echoecho -n "请输入你的年龄:" read -n 3 age echo echoecho -n "请输入你的性别(m/w):" read -n 1 gender echo echoecho -n "请输入你的电话号码: " read -s pn echo echoecho -n "请输入你的地址:" read addrecho -e "*****你的详细信息*****" echo "名字 "$name echo "年龄 "$age echo "性别 "$gender echo "电话号码 "$pn echo "地址 "$addr --------------------------------------------------------- #注意:因为某些特殊选项会出现不自动换行的bug,请使用echo 来设置换行。
4. shell声明运算符命令
数值运算的方法:使用declare声明变量类型命令:declare [+/-] [选项] 变量- : 给变量设定类型+ : 取消变量的类型-a : 将变量声明成数组型-i : 将变量声明成整数型-r : 将变量声明成只读(变量值不能修改,也不能删除,更不能取消只读选项)-x : 将变量声明成环境变量-p : 显示指定变量的类型及内容
4.1 数组型
数组:多个相同类型的元素的集合,数组下标从0开始
不使用declare 声明变量类型为数组的话,使用“变量名[下标]=值”,自动识别成数组,数组的名字及变量,变量名后面加上下标编号来区分变量中的每一个值,因此数组变量又称下标变量
[root@localhost ~]# student[0]=liu [root@localhost ~]# student[1]=yu [root@localhost ~]# student[2]=wang [root@localhost ~]# echo $student liu [root@localhost ~]# echo ${student[@]} liu yu wang [root@localhost ~]# echo ${student[1]} yu
4.2 整数型
-i : 将变量声明成整数型,可以进行数值运算
[root@localhost ~]# declare -i a=120 [root@localhost ~]# declare -i b=400 [root@localhost ~]# declare -i s=$a+$b [root@localhost ~]# echo $s 520
4.3 环境变量
-x : 将变量声明成环境变量和export是同样的效果
[root@localhost ~]# declare -x yg="yang yang" [root@localhost ~]# env | grep yg XBZ=yang yang
4.4 只读变量
对变量设置只读属性,这个变量只能进行调用,不能进行修改和删除,也不能取消只读选项。在命令行下设置只读属性,退出终端就会消失,在该模式下设置变量是临时的
[root@localhost ~]# declare -r test=100m [root@localhost ~]# echo $test 100m [root@localhost ~]# test=200m bash: test: 只读变量 [root@localhost ~]# unset test bash: unset: test: 无法反设定: 只读 variable [root@localhost ~]# declare +r test bash: declare: test: 只读变量
4.5 查询变量
-p变量属性查询,会列出设置时使用的参数
[root@localhost ~]# declare -p test declare -r test="100m" [root@localhost ~]# declare -p yg declare -x yg="yang yang"
4.6 使用expr或let进行数值运算
这两个命令是直接声明运算过程是数值运算,不是通过声明变量的类型,expr注意运算符两边要有空格,否则不会正常运算
#expr运算 [root@localhost ~]# x=450 [root@localhost ~]# y=134 [root@localhost ~]# expr $x + $y 584 -------------------------------------------------------- #let运算 [root@localhost ~]# let s=$x+$y [root@localhost ~]# echo $s 584 -------------------------------------------------------- #实现自增自减 [root@localhost ~]# n=1 [root@localhost ~]# let n++ [root@localhost ~]# echo $n 2 [root@localhost ~]# let n++ [root@localhost ~]# echo $n 3 [root@localhost ~]# let n-- [root@localhost ~]# echo $n 2 ---------------------------------------------------------- #指定增减量 [root@localhost ~]# n=1 [root@localhost ~]# let n=n+5 [root@localhost ~]# echo $n 6 [root@localhost ~]# let n+=5 [root@localhost ~]# echo $n 11 [root@localhost ~]# let n-=3 [root@localhost ~]# echo $n 8 [root@localhost ~]# let n-=6 [root@localhost ~]# echo $n 2
4.7 使用 $ ( ( 运算式 ) ) 或 ((运算式)) 或 ((运算式))或$[运算式]格式进行运算
同样两种格式都能实现数值运算,格式和expr、let不同
[root@localhost ~]# xx=123 [root@localhost ~]# yy=333 [root@localhost ~]# echo $(($xx+$yy)) 456 [root@localhost ~]# echo $[$xx+$yy] 456
五、shell常用运算符
优先级 | 运算符 | 功能描述 |
---|---|---|
1 | + - | 正负 |
2 | * / % | 乘、除、取余 |
3 | + - | 加、减 |
4 | += -= … | 自增、自减 … |
[root@localhost ~]# aa=$(((90-23)*23/12)) [root@localhost ~]# echo $aa 128 [root@localhost ~]# #乘除的优先级比加减排的更靠前,但是加减被()调用,所以括号的优先级高于乘除 ------------------------------------------------------------- #取余运算 [root@localhost ~]# echo $((15%3)) 0 [root@localhost ~]# echo $((16%3)) 1 *************************************************************** #扩展知识点 #类似于取余的运算,叫取模运算 # 1.求整数商 c=a/b # 2.计算模或者余数 r=a-c*b # 两者之间的区别:a和b符一致时,求模运算和求余运算所得的c的值一致,因此结果一致。但是符号不一致的时候,结果不一样。 # 这样的话,求模运算结果的符号和b一致,求余运算结果的符号和a一致。 -------------------------------------------------------------- #逻辑与(必须两方值都一样才会输出正确结果) [root@localhost ~]# echo $((0&&0)) 0 [root@localhost ~]# echo $((1&&0)) 0 [root@localhost ~]# echo $((1&&1)) 1 [root@localhost ~]# echo $((0&&1)) 0 [root@localhost ~]# echo $((2&2)) 2
六、环境变量的配置
6.1 source 命令
刷新修改过的配置文件使其生效
[root@localhost ~]# source /etc/profile [root@localhost ~]# . /etc/bashrc #注意这方式生效配置文件需要注意格式
环境变量配置文件,登录系统时生效的环境变量配置文件
/etc/profile ~/.bash_profile ~/.bashrc /etc/bashrc
6.2 文件调用的顺序
/etc/profile --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc -------------------------------------------------------------- 1.首先调用了/etc/profile文件在这个环境变量配置文件会定义这些默认环境变量USER变量 :根据登录的用户,给这个变量进行赋值(保存当前用户名)LOGNAME变量 :根据USER变量的值,给这个变量赋值MAIL变量:根据登录的用户名,定义用户的邮箱为/var/spool/mail/用户名PATH变量:根据登录用户的身份,决定PATH变量是否包含专属目录(/root/sh)HOSTNAME变量 :修改主机名,给这变量赋值HISTSIZE变量 :定义历史命令的保存条数 2.调用了~/.bash_profile,实现了1)调用/.bashrc文件2)在PATH变量后面加上“:$HOME/bin”这个目录。我们可以把要执行的脚本目录加入到后面,就可以直接执行脚本 3.在/.bashrc主要实现了1)定义默认别名2)调用/etc/bashrc 4.在/etc/bashrc文件中定义了1)PS1变量:也就是用户提示符2)umask:定义umask默认权限,在这个文件定义的是针对“没有登录过程”时生效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效3)PATH变量:会给PATH变量追加值,当然也是在“没有登录过程”才生效4)调用/etc/profile.d/*.sh文件
6.3 注销专用环境变量配置文件
## 用户退出登陆时,只调用一个环境变量配置文件,~/.bash_logout这个文件默认没写入任何内容,但是退出登录执行一些操作,可以写入该文件中,例:清除历史命令,备份数据等
6.4 shell登录信息
6.4.1 /etc/issue
## 登录6个本地终端会出现几行提示信息,这些提示信息保存在/etc/issue [root@localhost ~]# cat /etc/issue \S Kernel \r on an \m ---------------------------------------------------------- 查询组合可用man agetty \d 显示当前系统日期 \s 显示操作系统名称 \l 显示登录的终端号 \m 显示硬件体系结构 \n 显示主机名 \o 显示域名 \r 显示内核版本 \t 显示当前系统时间 \u 显示当前登录用户的序列号
6.4.2 /etc/motd
# 该文件中显示欢迎信息,它是在用户输入用户名和密码,正确登录显示欢迎信息。
6.5 bash快捷键
##查看存在的快捷键 [root@localhost ~]# stty -a speed 38400 baud; rows 25; columns 61; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts ------------------------------------------------------- ##修改快捷键 [root@localhost ~]# stty intr ^p [root@localhost ~]# ^P [root@localhost ~]# stty -a speed 38400 baud; rows 24; columns 133; line = 0; intr = ^P; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = #了解即可,最好不要修改
七、正则表达式
- 之前提到过的通配符它是结合系统命令(find、cat等)对文件名进行模糊查找
- 正则表达式配合grep实现对文件中字符串精确查找
- 扩展表达式是在基础正则表达式做的补充
- 使用扩展表达式必须使用grep -E或者egrep命令才能生效
7.1 基础正则表达式
元字符 作用 * 匹配前一个符号出现的次数,任意次数
匹配前一个字符出现的次数-任意次数. 匹配任意一个任意字符,相当于通配符的? ^ 行首 $ 行尾 [] 匹配括号范围内的任意一个字符 [^] 匹配括号以外的任意一个字符 \ 转义符,用于取消特殊符号的含义取消 \{n,m\} 表示对前一个字符进行定义次数的搜索
7.2 扩展正则表达式
扩展元字符 作用 + 前一个字符匹配1次或任意多次。 ? 前一个字符匹配0次或1次 | 分支匹配,逻辑或,一般结合()使用 () 将字符串当作整体进行匹配 {n,} 表示前面的字符最少出现n次 {,m} 表示后面的字符最少出现m次 {n,m} 表示该字母最少出现n次,最多出现m次
7.3 grep结合正则实现精确匹配
*: 匹配前一个 字符出现的次数-任意次数
[root@localhost ~]# grep "ooo*" anaconda-ks.cfg # Run the Setup Agent on first boot firstboot --enable network --bootproto=dhcp --device=ens33 --ipv6=auto --activate # Root password rootpw --iscrypted......
+:匹配前一个字符出现至少一次
[root@localhost ~]# egrep "oo+" anaconda-ks.cfg # Run the Setup Agent on first boot firstboot --enable network --bootproto=dhcp --device=ens33 --ipv6=auto --activate # Root password
?:匹配前一个字符出现指定范围的次数
[root@localhost ~]# egrep "ooo?" anaconda-ks.cfg # Run the Setup Agent on first boot firstboot --enable network --bootproto=dhcp --device=ens33 --ipv6=auto --activate # Root password
{n,m} :匹配前字符出现指定范围的次数
# oooo{,1}最多出现一次 [root@localhost ~]# egrep "oooo{,1}" anaconda-ks.cfg roooot ------------------------------------------------------------ # ooo{3,}最少出现3次 [root@localhost ~]# egrep "o{3,}" anaconda-ks.cfg roooot rooot ooo ooo ------------------------------------------------------------ #oo{2,3}最少出现两次,最多出现三次 [root@localhost ~]# egrep "oo{2,3}" anaconda-ks.cfg roooot rooot ooo ooooooo
. :匹配任意一个任意字符,相当于通配符的?
#输出前后任意字母 [root@localhost ~]# egrep ".b." anaconda-ks.cfg auth --enableshadow --passalgo=sha512 # Run the Setup Agent on first boot firstboot --enable # Keyboard layouts
.*:匹配任意多个任意字符,相当于通配符的*
#匹配ro到t范围内所有的字符 [root@localhost ~]# egrep "ro.*t" anaconda-ks.cfg network --bootproto=dhcp --device=ens33 --ipv6=auto --activate rootpw --iscrypted $6$hy7q7D5p9/R.K7qN$la3RlSzxy0FJfauKmKYRpjY0jpBCi1oH5aAxwtMd8o6BpA1nGigAOI3FNOGMZ1nO55TVS6vqaSuAN5LUTrMZb. volgroup centos --pesize=4096 pv.253 logvol / --fstype="xfs" --size=18939 --name=root --vgname=centos pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty rootroot roooot rooot root toot
[] :匹配括号范围内的任意一个字符
[root@localhost ~]# egrep "[total]" anaconda-ks.cfg #version=DEVEL # System authorization information auth --enableshadow --passalgo=sha512 # Use CDROM installation media cdrom # Use graphical install graphical
^ :行首
root@localhost ~]# egrep -n "^a" anaconda-ks.cfg 3:auth --enableshadow --passalgo=sha512
$:行尾
[root@localhost ~]# egrep -n "d$" anaconda-ks.cfg 20:# Root password 44:%end 48:%end 54:%end ------------------------------------------------------------- #使用逻辑或查找a开头或者d结尾的 [root@localhost ~]# egrep -n "^a|d$" anaconda-ks.cfg 3:auth --enableshadow --passalgo=sha512 20:# Root password 44:%end 48:%end 54:%end
^$:匹配空行
[root@localhost ~]# egrep -n "^$" anaconda-ks.cfg 15: 19: 37: 43: 45:
():将字符串当作整体进行匹配
[root@localhost ~]# egrep -n "(root)" anaconda-ks.cfg 21:rootpw --iscrypted $6$hy7q7D5p9/R.K7qN$la3RlSzxy0FJfauKmKYRpjY0jpBCi1oH5aAxwtMd8o6BpA1nGigAOI3FNOGMZ1nO55TVS6vqaSuAN5LUTrMZb. 35:logvol / --fstype="xfs" --size=18939 --name=root --vgname=centos 51:pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty 55:rootroot 58:root toot
|:分支匹配,逻辑或,一般结合()使用
[root@localhost ~]# egrep -n "(root|toot)" anaconda-ks.cfg 21:rootpw --iscrypted $6$hy7q7D5p9/R.K7qN$la3RlSzxy0FJfauKmKYRpjY0jpBCi1oH5aAxwtMd8o6BpA1nGigAOI3FNOGMZ1nO55TVS6vqaSuAN5LUTrMZb. 35:logvol / --fstype="xfs" --size=18939 --name=root --vgname=centos 51:pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty 55:rootroot 58:root toot
7.4 练习
手机号
[root@localhost ~]# egrep "1[0-9]{10}" phone.txt 12443543523456 12435436576856
ip地址
[root@localhost ~]# egrep "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|"5[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}" phone.txt 192.168.11.125 192.168.115.125 192.168.167.125 192.168.123.125 192.168.255.255
邮箱账号
-P、 --perl-regexp 将PATTERN解释为Perl正则表达式 -o、 --仅匹配 仅打印匹配项的匹配(非空)部分 线,每个这样的部分在单独的输出线上。 [root@localhost ~]# grep -oP '(?:[a-zA-Z0-9]*)@([a-zA-Z0-9]*)\.(?:[a-z ]*)' phone.txt ltz340565@163.com 2905372217@qq.com
八、字符截取和替换命令
1. cut 提取命令
格式:cut [选项] 文件名 -f:提取第几列,默认识别制表符分割出来的列 -d:分隔符:按照指定的分割符进行分割,然后结合-f提取指定列 -c:字符范围,不依赖分割符来分割,而是通过字符范围进行提取n-m表示从第n提取到第m个字符n-表示从n提取到结尾-m表示从第一个字符提取到第m个
-f:提取某列内容(在visual code编辑器中使用该工具打开的文件不识别该模式下的tab键,不管是什么编辑器,只要用vim编辑的准没错)
[root@localhost ~]# vim shcli/sqlchar.txt #添加以下内容id name age address1 ltz 23 langfang2 wxc 23 shenyang3 ygf 25 heilongjiang4 mxt 25 guangdong5 cxc 23 beijing --------------------------------------------------------------------------- #提取第2列,和第四列 [root@localhost ~]# cut -f 2,4 shcli/sqlchar.txt name address ltz langfang wxc shenyang ygf heilongjiang mxt guangdong cxc beijing --------------------------------------------------------------------------- #提取第二列到第四列 [root@localhost ~]# cut -f 2-4 shcli/sqlchar.txt name age address ltz 23 langfang wxc 23 shenyang ygf 25 heilongjiang mxt 25 guangdong cxc 23 beijing
-d:分隔符:按照指定的分割符进行分割,然后结合-f提取指定列
#按照指定的分隔符提取第三列到第五列 [root@localhost ~]# cut -d: -f3-5 /etc/passwd 0:0:root 1:1:bin 2:2:daemon
-c:字符范围,不依赖分割符来分割,而是通过字符范围进行提取(太麻烦了,还得一个个数大概字符,最后挨个试试出的范围)
#截取查看当前磁盘空间中的/做结尾,并截取8这个数字,按照指定的分割符进行分割 [root@localhost ~]# df -h | grep "/$" | cut -c 46-48 | cut -d% -f1 8 [root@localhost ~]# df -h | grep "/$" | cut -c 46-47 | cut -d% -f1 8
shell字符处理三剑客:grep、awk、sed
2. awk命令
awk可以说是一门编程语言,在Linux/unix中可以实现对文本和数据进行处理,可以对文件的行和列进行提取
2.1 awk的格式和组成结构
格式:awk '条件1{动作1}' 文件名 条件:通过关系表达式进行判断筛选出符合条件的行 动作:将符合条件的条件内容进行格式化输出到命令行,在输出的时候可以选择哪些列进行输出
输出文件sqlchar中的第二列和第三列(列之间加上制表符,并且换行)
#不指定任何条件、直接执行动作,并选择输出那些列 [root@localhost ~]# awk '{printf $2"\t"$3"\n"}' shcli/sqlchar.txt name age ltz 23 wxc 23 ygf 25 mxt 25 cxc 23 cl 27
2.2 扩展:动作{prinf}
作用:取消所有的默认格式,手动按照指定输出内容的类型和格式输出
printf输出格式printf '类型/格式' 字符串使用cat、head、tail等将文本中的字符串取出,交给printf处理 输出类型 %s:按字符串类型输出%i:按整数类型输出%f:按照浮点数类型输出 输出格式\t:tab键 用作提取列分割\n:enter键 用作换行分割 print输出原有格式
实验过程
#输出以下内容id name age address1 ltz 23 langfang2 wxc 23 shenyang3 ygf 25 heilongjiang4 mxt 25 guangdong5 cxc 23 beijing6 cl 27 jiangsu #没有任何格式输出 [root@localhost ~]# printf '%s' $(cat shcli/sqlchar.txt) idnameageaddress1ltz23langfang2wxc23shenyang3ygf25heilongjiang4mxt25guangdong5cxc23beijing6cl27jiangsu #输出有格式的表格 [root@localhost ~]# printf '%s\t%s\t%s\t%s\n' $(cat shcli/sqlchar.txt) or [root@localhost ~]# printf '%s\t%s\t%s\t%s\n' `cat shcli/sqlchar.txt` id name age address 1 ltz 23 langfang 2 wxc 23 shenyang 3 ygf 25 heilongjiang 4 mxt 25 guangdong 5 cxc 23 beijing 6 cl 27 jiangsu --------------------------------------------------------------------------- 按照浮点类型输出 [root@localhost ~]# printf '%s\t%s\t%.2f\t%.2f\t%.2f\n' `cat score` bash: printf: Linux: 无效数字 bash: printf: Java: 无效数字 bash: printf: K8S: 无效数字 id name 0.00 0.00 0.00 1 ltz 90.00 100.00 90.00 2 mxt 90.00 90.00 90.00 3 ygf 70.00 70.00 70.00 4 wcl 90.00 90.00 90.00 #筛选出除id以外的行 [root@localhost ~]# printf '%i\t%s\t%.2f\t%.2f\t%.2f\n' `cat score | grep -v id` 1 ltz 90.00 100.00 90.00 2 mxt 90.00 90.00 90.00 3 ygf 70.00 70.00 70.00 4 wcl 90.00 90.00 90.00 -------------------------------------------------------------------------- #print输出原有格式 [root@localhost ~]# awk '{print}' score id name Linux Java K8S 1 ltz 90 100 90 2 mxt 90 90 90 3 ygf 70 70 70 4 wcl 90 90 90 [root@localhost ~]# awk '{print $2}' score name ltz mxt ygf wcl [root@localhost ~]# awk '{print $2,$4}' score name Java ltz 100 mxt 90 ygf 70 wcl 90
2.3 awk条件
预定义条件(保留字)是系统预定义好的特殊条件(必须大写)
BEGIN 开始,开头
在awk未读取数据前声明的动作,该条件后的动作仅在开始时执行一次,不会重复执行
[root@localhost ~]# awk 'BEGIN{printf "K8S成绩单:\n"}{printf $2"\t"$5"\n"}' score K8S成绩单: name K8S ltz 90 mxt 90 ygf 70 wcl 90 [root@localhost ~]# awk 'BEGIN{FS=":"}{printf $2"\t"$6"\n"}' /etc/passwd x /root x /bin x /sbin x /var/adm x /var/spool/lpd
END 末尾,结束
在awk处理完所有数据后声明的条件,在该条件后的程序仅在程序结束前执行一次
[root@localhost ~]# awk '{printf $2"\t"$3"\n"}END{printf"以上是所有人的Linux成绩\n"}' score
name Linux
ltz 90
mxt 90
ygf 70
wcl 90
以上是所有人的Linux成绩
awk关系运算条件
>、<、>=、<=、==、!=
用来判断左右两侧的关系,一般左侧未变量,右侧为参考值
##列出即k8s成绩大于75 [root@localhost ~]# awk 'BEGIN{printf"列出K8S成绩大于75分\n"} $3>=75{printf $2"\t"$5"\n"}' score 列出K8S成绩大于75分 name K8S ltz 90 mxt 90 wcl 90 ##列出k8s成绩不等于90分 [root@localhost ~]# awk 'BEGIN{printf"列出K8S成绩不等于90分\n "}$3!=90{printf $2"\t"$5"\n"}' score 列出K8S成绩不等于90分 name K8S ygf 70
awk包含匹配条件
~、!~、~//、!~//
用来进行匹配包含关系的,判断左侧变量是否包含右侧的字符串,当右侧字符串包含一些特殊服啊后时,需要使用//然后在里面使用\转义符将符号转义为普通字符
#查询第二列是否包含c字符然后输出他所在的行 [root@localhost ~]# awk '$2~/c/{printf $0"\n"}' score 4 wcl 90 90 90 #查询全文是否包含g字符然后输出他所在的行 [root@localhost ~]# awk '/g/{printf $0"\n"}' score 3 ygf 70 70 70 4 wgl 90 90 90 #查询开头为3并且输出所在的行 [root@localhost ~]# awk '$0~/^3/{printf $0"\n"}' score 3 ygf 70 70 70 #根据正则表达式查询设备名称和空间已用情况 [root@localhost ~]# df -h | awk '/(sd|sr)[a-z]?[0-9]/{printf $1"\t"$5"\n"}' /dev/sda1 25% /dev/sr0 100%
awk内置变量
awk内置变量 | 作用 |
---|---|
$0 | 代表awk读入当前行的整行数据 |
$n | 读入当前行的第n列数据 |
NR | 代表当前awk正在处理的行的行号 |
NF | 代表当前awk读取数据总字段数(总列数) |
FS | 用来声明awk的分隔符,如BEGIN{FS=“:”} |
#输出行号大于3
[root@localhost ~]# awk 'NR>3{printf $0"\n"}' score
3 ygf 70 70 70
4 wgl 90 90 90
------------------------------------------------------
#输出当前文件总列数
[root@localhost ~]# awk 'END{printf "当前文件的总列数为:"NF"\n"}' score
当前文件的总列数为:5
-------------------------------------------------------
#将斜杠作为分隔符输出统计好的最后一个目录
[root@localhost ~]# cd /etc/yum.repos.d/bak/
[root@localhost bak]# echo $PWD | awk -F / '{printf $NF"\n"}'
bak
----------------------------------------------------
#将:分隔符声明输出第三列和第五列
[root@localhost ~]# awk 'FS=":"{printf $3"\t"$5"\n"}' /etc/passwd
1 bin
2 daemon
3 adm
4 lp
5 sync
awk数值运算
默认支持数值运算,整数和浮点数都支持
#计算每个人的各科平均成绩
[root@localhost ~]# awk 'NR>1{printf $2"的平均分是\t"($3+$4+$5)/3"\n"}'score
ltz的平均分是 93.3333
mxt的平均分是 90
ygf的平均分是 70
wgl的平均分是 90
---------------------------------------------------------
#按照浮点数格式输出
[root@localhost ~]# printf '%s\t%.2f\n' $(awk 'NR>1{printf $2"的平均分是\t"($3+$4+$5)/3"\n"}' score)
ltz的平均分是 93.33
mxt的平均分是 90.00
ygf的平均分是 70.00
wgl的平均分是 90.00
[root@localhost ~]# printf '%s\t%.2f\n' `awk 'NR>1{printf $2"的平均分是\t"($3+$4+$5)/3"\n"}' score`
ltz的平均分是 93.33
mxt的平均分是 90.00
ygf的平均分是 70.00
wgl的平均分是 90.00
##计算浮点数
[root@localhost ~]# c=$(awk 'BEGIN{printf 8.65*3.45-4.89}')
[root@localhost ~]# echo $c
24.9525
2.4 awk编程注意事项
在awk编程中,通常命令语句很长,输入格式要注意4点内容
1.多个条件或动作可以用空格分割
2.在一个动作中,如果需要执行多个命令,用;分割
3.在awk中,变量的赋值与调用都不需要使用$
4.判断两个值是否相同,使用==,以便和变量赋值去区分
2.5 awk的工作原理
1.先查看是否有BEGIN条件,有先执行BEGIN后面定义动作
2.如果没有BEGIN条件,先读入第一行数据,把第一行的数据使用分隔符分割之后依次赋值给变量$0 $1 $2....$0代表整行数据,依次类推
3.第一行内容赋值完成后,进行条件判断,按照符合条件的动作执行
4.处理完第一行之后,进行第二行赋值,然后重复第一行步骤,直到处理完整个文本
5.检查是否有END声明的条件,有则执行,没有结束
3. sed命令
sed实现数据选取、替换、删除、新增等操作命令,实现非交互式文件内容修改
sed [选项] 修改字符 被修改字符 文件名 选项:-i: 修改文件内容-n:将经过sed命令处理过的输出到命令行 --------------------------------------------------------- 动作:p:输出指定的行a:在当前行后追加一行或多行。追加多行时,除了最后1行,行尾要使用\强制换行符i:在当前行前插入一行或多行。同上c:整行替换d:删除s:字符串替换,格式 行范围s/旧字符串/新字符串/g
p:输出第二行
[root@localhost ~]# sed '2p' score id name Linux Java K8S 1 ltz 90 100 90 1 ltz 90 100 90 2 mxt 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90 [root@localhost ~]# sed -n '2p' score 1 ltz 90 100 90
d:删除第二行和第三行
[root@localhost ~]# sed '2,3d' score
id name Linux Java K8S
3 ygf 70 70 70
4 wgl 90 90 90
a:在当前行后追加一行或多行。
i:在当前行前插入一行或多行.
#在第2行后面追加数据 [root@localhost ~]# sed '2a hello' score id name Linux Java K8S 1 ltz 90 100 90 hello 2 mxt 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90 #在第二行前插入数据 [root@localhost ~]# sed '2i hello' score id name Linux Java K8S hello 1 ltz 90 100 90 2 mxt 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90
c:整行替换
#将第二行数据进行替换 [root@localhost ~]# sed '2c xinniankuaile' score id name Linux Java K8S xinniankuaile 2 mxt 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90
s:字符串替换,格式 行范围s/旧字符串/新字符串/g
[root@localhost ~]# sed '3s/mxt/lcy/g' score id name Linux Java K8S 1 ltz 90 100 90 2 lcy 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90 [root@localhost ~]# sed '3s/mxt//g' score id name Linux Java K8S 1 ltz 90 100 90 2 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90 [root@localhost ~]# sed '3s/^/#/;3s/mxt//g' score id name Linux Java K8S 1 ltz 90 100 90 #2 90 90 90 3 ygf 70 70 70 4 wgl 90 90 90
4. sort 字符排序
格式:sort 选项 文件名 -f:忽略大小写 -n:按照数值类型排序 -r:反向排序 -u:删除重复行 -t:指定分隔符,默认是制表符 -k n :指定使用第几列的内容进行排序,一般结合-t使用
5. uniq 取消重复行
和sort -u功能类似
格式:uniq 选项 文件名 -i 忽略大小写 -c 在关键词旁显示关键词出现的次数(一般针对行) 重复行不连续时,uniq是不生效的,需要先排序,在执行
将原有格式输出第一列的结果排序、去重并统计出现的次数,然后以以倒序的方式查看访问次数最多
[root@localhost ~]# awk '{print $1}' shcli/access.log | sort |uniq -c |sort -rn425240 66.77.88.161353096 66.77.88.165297844 66.77.88.170256313 66.77.88.166238554 66.77.88.157142400 66.77.88.15564700 66.77.88.16337674 66.77.88.151
九、条件判断
1.按照文件类型进行判断
选项 | 作用 |
---|---|
-b | 判断是否为块设备文件 |
-c | 判断是否为字符设备文件 |
-d | 判断是否为目录文件 |
-e | 判断文件是否存在,存在为真 |
-f | 判断是否为普通文件 |
-L | 判断是否为软连接文件 |
-p | 判断是否为管道文件 |
-s | 判断是否为非空(非空为真) |
-S | 判断是否为套接字文件 |
2.按照文件权限进行判断
选项 | 作用 |
---|---|
-r | 判断文件是否拥有读权限 |
-w | 判断文件是否有写权限 |
-x | 判断文件是否有执行权限 |
-u | 判断文件是否有SUID权限 |
-g | 判断文件是否有SGID权限 |
-k | 判断文件是否有SBIT权限 |
3.两个文件之间进行比较
选项 | 作用 |
---|---|
文件1 -nt 文件2 | 判断文件1的修改时间是否比文件2的新 |
文件1 -ot 文件2 | 判断文件1的修改时间是否比文件2的旧 |
文件1 -ef 文件2 | 判断文件1是否和文件2的inode号一致, 即两个文件是否同一个文件,用于判断硬链接是很棒的方法 |
4.两个整数之间进行比较
选项 | 作用 |
---|---|
1 -eq 2 | 判断整数1是否整数2相等 |
1 -ne 2 | 判断1是否和2不相等 |
1 -gt 2 | 判断1是否大于2 |
1 -lt 2 | 判断1是否小于2 |
1 -ge 2 | 判断1是否大于等于2 |
1 -le 2 | 判断1是否小于等于2 |
5.字符串的判断
选项 | 作用 |
---|---|
-z 字符串 | 判断字符串是否为空 |
-n 字符串 | 判断字符串是否为非空 |
字符串1 == 字符串2 | 判断字符串1是否和字符串2相等 |
字符串1 != 字符串2 | 判断字符串1是否和字符串2不相等 |
6.多重条件判断
选项 | 作用 |
---|---|
判断1 -a 判断2 | 逻辑与,两个判断都成立,最后的结果才为真 |
判断1 -o 判断2 | 逻辑或 任意一个判断成立,最后的结果就是真 |
!判断 | 逻辑非,使原始的判断式取反 |
十、流程控制
需要结合之前的条件判断进行流程控制
1.if条件判断
单分支if条件判断
格式1 if [ 条件判断式 ];then命令 fi 格式2: if [ 条件判断式 ] then命令 fi
双分支if条件语句
if [ 条件判断式 ];then条件成立,执行输出 else条件不成立,不输出 fi
多分支if分支语句
if [ 条件判断式1 ];then条件1成立,执行输出1elif [ 条件判断式2 ];then......else条件不成立 else条件不成立,不输出 fi
2.case分支语句
和if类似,case只能判断一种条件关系,而if语句可以判断多种条件关系
case语法
case $变量名 in 值1)变量的值等于值1,则执行程序1 ;; 值2)变量的值等于2,则执行程序2 ;;省略多个分支………… *)变量的值都不匹配上面的值,则执行此程序 ;; esac
3.for循环
固定循环也叫计数循环,循环的次数是有限的
语法一
for 变量 in 值1 值2 值3 …… do程序 done
语法二
for ((初始值;循环控制条件;变量变化)) do程序 done
语法三
for 变量 in $(seq 10) do程序 done
4.while循环
条件判断成立就会一直循环下去,直到条件不成立,循环就会终止
while [ 条件判断式 ] do程序 done
5.until循环
until循环和while循环相反,只要条件判断式不成立,则一直循环,什么时候条件成立,什么时候结束循环
until [ 条件判断式 ] do程序 done
6.特殊流程控制语句
exit:退出当前脚本
exit 值 退出时如果定义好了返回值,通过$?来查看
break:结束当前循环执行循环程序后面的程序
当break处在多层循环中时,使用break n的方式选择跳出的层数
continue:结束当前的循环的本次循环
continue n可以选择跳出当前循环中的n次
7.死循环
for (( i=1; ; i++ ))
while true
while :
8.流程练习
1.猜数字
#!/bin/bash
sum=0
value=$(($RANDOM%10+1))
read -p "欢迎你参加猜数字游戏(1-10,请输入数字)" num
while true;dolet sum++if [ $value -eq $num ];thenecho "恭喜你输入正确"echo "循环总次数:$sum"exit 0elif [ $value -gt $num ];thenread -p "你的数值猜小了请继续" numcontinueelseread -p "你的数值猜大了请继续" numcontinuefi
done
--------------------------------------------------------------------------
2.九九乘法表
#!/BIN/bash
for((i=1;i<=9;++i))
dofor((j=1;j<=i;++j))doecho -e -n "$j*$i=$(($j*$i))\t"doneecho ""
done
----------------------------------------------------------------------------
3.累加求和
#!/bin/bash
sum=0
for i in $(seq 1 100)
dosum=$(($sum+$i))
done
echo "1到100的和为:$sum"
----------------------------------------------------------------------------
4.检测文件类型
#!/bin/bash
while true
doread -p "请输入你要测试文件名(绝对路径)" fileif [ -z "$file" ];thenecho "变量名未赋值,请重新输入变量"fiif [ ! -e "$file" ];thenecho "文件名不存在,请重新输入"fiif [ -L "$file" ];thenif [ -d "$file" ];thenecho "$file""是一个软连接文件,源文件是目录"exit 0elif [ -b "$file"];thenecho "$file是一个软连接文件,源文件是块设备"exit 0elseecho "$file是一个其他类型文件"exit 0fielif [ -b "$file" ];thenecho "$file是一个块设备文件"exit 0elif [ -c "$file" ];thenecho "$file是一个字符设备文件"exit 0elif [ -d "$file" ];thenecho "$file是一个目录文件"exit 0elif [ -f "$file" ];thenecho "$file是一个普通文件"exit 0elseecho "$file是一个套接字或管道符文件"exit 0 fi
done
扩展
date 命令
#系统时间 [root@localhost ~]# date ##查看当前系统日期和时间 2024年 05月 30日 星期四 20:10:07 CST##date -s 修改系统时间 date -s yyyy-mm-dd date -s HH:MM:SS [root@localhost ~]# date -s 2024-05-30 2024年 05月 30日 星期四 00:00:00 CST [root@localhost ~]# date -s 20:11:00 2024年 05月 30日 星期四 20:11:00 CST##按照指定格式显示日期和时间 [root@localhost ~]# date +%Y-%m-%d 2024-05-30 [root@localhost ~]# date +%Y:%m:%d 2024:05:30 [root@localhost ~]# date +%H:%M:%S 20:18:14 [root@localhost ~]# date +%H-%M-%S 20-18-22
#硬件时间 [root@localhost ~]# clock #查看硬件时间 2024年05月30日 星期四 20时15分46秒 -0.896749 秒 [root@localhost ~]# clock -w #将系统时间同步给硬件时间 [root@localhost ~]# clock -s #将硬件时间同步给系统时间
实现命令检测工具
#!/bin/bash echo -e "==========软件检测工具==========" echo -e "||*声明:该工具检测系统是否缺少||" # 自增 n=0 let n++ read -p"请输入想要检测的命令名称:" package[$n] echo -e "==========检测中......=========" # 通过自增让数组中的下标值是可变化的 for i in ${package[n]} do # 判断usr/bin目录下文件是否存在,存在即输出if [ -f /usr/bin/$i ];thenecho $i"工具已安装"else# 未安装根据x86_64来yum搜索软件包,调整格式覆盖到/root/test1文件中yum search $i | grep "x86_64" | awk '{print $1}' > /root/test1# 遍历/root/test1文件中的软件包名for j in $(cat /root/test1)do# 判断是否安装read -p "命令"$j"未安装,是否安装[y/n]:" yif [ $y = 'y' ];then # 将安装信息无论对错输出到伪设备yum -y install $j >& /dev/null#判断安装信息成功if [ $? -eq 0 ];thenecho "用户已安装成功"elseecho "未找到相关安装包,安装失败"fi# 输入n用户选择不安装elif [ "$y" = 'n' ];thenecho "用户选择不安装"fidone# 每次循环将空字符串覆盖到/root/test1# echo "" > /root/test1fi done