Shell编程

Shell编程

一、简介

作用:shell提供了用户与内核进行交互操作的一种接口

在这里插入图片描述

实际上shell就像语言翻译人员,它将用户输入的命令解释成二进制文件发送到内核中。同理从内核中将二进制文件解释的结果发送到应用程序并将显示结果呈现给用户。

学习shell脚本的目的

  1. 将重复性的工作用脚本代替
  2. 将较为复杂的操作流程脚本化,降低错误出现的概率

shell脚本的阶段

  1. 写脚本就是命令的堆叠
  2. 要求脚本能进行环境自适应、兼容性
  3. 包含着逻辑判断、流程控制等

脚本执行的两种方法

 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是三位八进制数
\xhhx十六进制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/stdin0标准输入
显示器/dev/stdout1标准正确输出
显示器/dev/stderr2标准错误输出
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/bash
    cat  << EOF
      wangxuance
    EOF
    [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 /etc
        find ./ | cpio -ocvB > /root/et.cpio
        恢复
        cd /root
        mkdir test
        cd test
        cpio -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 位置参数变量
位置参数变量作用
$nn为数字,$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 "$*"
do
    echo "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
echo

echo -n "请输入你的年龄:"
read -n 3 age
echo
echo

echo -n "请输入你的性别(m/w):"
read -n 1 gender
echo
echo

echo -n "请输入你的电话号码: "
read -s pn
echo
echo

echo -n "请输入你的地址:"
read addr

echo -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文件中定义了
	1PS1变量:也就是用户提示符
	2)umask:定义umask默认权限,在这个文件定义的是针对“没有登录过程”时生效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效
	3PATH变量:会给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     address
   1       ltz     23      langfang
   2       wxc     23      shenyang
   3       ygf     25      heilongjiang
   4       mxt     25      guangdong
   5       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     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' $(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 -rn
 425240 66.77.88.161
 353096 66.77.88.165
 297844 66.77.88.170
 256313 66.77.88.166
 238554 66.77.88.157
 142400 66.77.88.155
  64700 66.77.88.163
  37674 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成立,执行输出1
	elif [ 条件判断式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;do
	let sum++
	if [ $value -eq $num ];then
		echo "恭喜你输入正确"
		echo "循环总次数:$sum"
		exit 0
	elif [ $value -gt $num ];then
		read -p "你的数值猜小了请继续" num
		continue
	else
		read -p "你的数值猜大了请继续" num
		continue
	fi
done
--------------------------------------------------------------------------
2.九九乘法表
#!/BIN/bash
for((i=1;i<=9;++i))
do
    for((j=1;j<=i;++j))
    do
        echo -e -n "$j*$i=$(($j*$i))\t"
    done
    echo ""
done
----------------------------------------------------------------------------
3.累加求和
#!/bin/bash
sum=0
for i in $(seq 1 100)
do
        sum=$(($sum+$i))
done
echo "1到100的和为:$sum"
----------------------------------------------------------------------------
4.检测文件类型
#!/bin/bash
while true
do
	read -p "请输入你要测试文件名(绝对路径)" file

	if [ -z "$file" ];then
		echo "变量名未赋值,请重新输入变量"
	fi
	if [ ! -e "$file" ];then
		echo "文件名不存在,请重新输入"
	fi
	
	if [ -L "$file" ];then
		if [ -d "$file" ];then
			echo "$file""是一个软连接文件,源文件是目录"
			exit 0
		elif [ -b "$file"];then
			echo "$file是一个软连接文件,源文件是块设备"
			exit 0
		else
			echo "$file是一个其他类型文件"
			exit 0
		fi
	elif [ -b "$file" ];then
		echo "$file是一个块设备文件"
		exit 0
	elif [ -c "$file" ];then
		echo "$file是一个字符设备文件"
		exit 0
	elif [ -d "$file" ];then
		echo "$file是一个目录文件"
		exit 0
	elif [ -f "$file" ];then
		echo "$file是一个普通文件"
		exit 0
	else
		echo "$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 ];then
        echo $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]:" y
            if [ $y = 'y' ];then 
            # 将安装信息无论对错输出到伪设备
                yum -y install $j >& /dev/null
                #判断安装信息成功
                if [ $? -eq 0 ];then
                    echo "用户已安装成功"
                else
                    echo "未找到相关安装包,安装失败"
                fi
            # 输入n用户选择不安装
            elif [ "$y" = 'n' ];then
                echo "用户选择不安装"
            fi
        done
        # 每次循环将空字符串覆盖到/root/test1
        # echo "" > /root/test1
    fi
done
  • 24
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值