Shell 编程学习笔记

Shell 编程学习笔记

Shell 编程

1.简单脚本 “hello world 输出”

  1. 写入脚本

cd /root		#切换至root目录下
vim hello.sh	#新建一个名为“hello”的shell文件,并进入编写

编写内容如下:

#!/bin/bash					#声明!! 此程序运用/bin/bash为编译
echo "hello word"			#使用echo输出: hello world 


:wq							#末行模式	保存并退出
  1. 执行命令

方法一:

bash /root/hello.sh #使用文件全称执行

[root@localhost ~]# bash /root/hello.sh
hello world
[root@localhost ~]#

方法二:

bash hello.sh #使用 .sh 文件文件名执行

[root@localhost ~]# bash hello.sh
hello world
[root@localhost ~]# 

方法三:

给 /root/hello.sh 文件加 “执行” 权限,并使用文件路径直接执行

chmod +x ./hello.sh 		
#给文件加入可执行权限(由于当前在目录/root下,所以使用‘./’开头)
./hello.sh					
#执行文件路径
[root@localhost ~]# chmod +x ./hello.sh 
[root@localhost ~]# ll -d /root/hello.sh 
-rwxr-xr-x 1 root root 32 11月 11 14:14 /root/hello.sh
[root@localhost ~]# ./hello.sh 
hello world
[root@localhost ~]#

echo 命令 *

echo 命令是 Linux 中最基本和最常用的命令之一:

传递给 echo 的参数被打印到标准输出中; echo 通常用于 shell 脚本中,用于显示消息或输出其他命令的结果, 语法:

echo [选项] [输出内容]

[root@localhost ~]# echo "123"
123

选项: -n: 取消输出内容后的换行符

[root@localhost ~]# echo -n "123"
123[root@localhost ~]# 

选项: -e:支持反斜线控制字符的转换

控制字符作用
\输出 \
\a输出系统警告音
\b退格键 ,向左删除一个字符
\f换页符,换行但是换行后开头连接上一行的尾行
\n换行符
\t制表符,即 TAB 键
\e输出颜色 ,需要搭配颜色代码
\ 输出 \
[root@localhost ~]# echo "\\"
\									#输出结果
\b 退格键
[root@localhost ~]# echo -e "abc\b "
ab 
\a 输出系统警告音
[root@localhost ~]# echo -e "\a"
									#此时会发出系统提示音			
\t 制表符
[root@localhost ~]# echo -e "a\tb"
a	b								#输出结果

[root@localhost ~]# echo -e "a\tbm\tc \tf"
a	bm	c 	f						#输出结果
\n 换行符
[root@localhost ~]# echo -e "a\nb"
a
b
\f 换页符
[root@localhost ~]# echo -e "a\fb\fc\fd\fe"
a
 b
  c
   d
    e
\e 输出颜色

格式:

echo -e "\e[颜色代码m			\e[0m"
		#代表颜色输出开始		#代表颜色输出结束

##其中,\e 是转义起始符,定义一个转义序列:[表示开始定义颜色,后加颜色色代码:

##m 是转义终止符:#可以进行的设置,多个设置之间用分号(;)分割开,同时生效: 字体颜色: 30-37,

30 = 黑色,31 = 红色,32 = 绿色,33 = 黄色,34 = 蓝色,35 = 紫色,36 = 青色,37 = 白色

字背景颜色: 以上颜色数字+10 就会变成底色

40 = 黑色,41 = 红色,42 = 绿色,43 = 黄色,44 = 蓝色,45 = 紫色,46 = 青色,47 = 白色,

特殊的显示:

1 设置高亮,4 设置下划线,5 设置闪烁,7 设置反显,8 设置消隐

[root@localhost ~]# echo -e "\e[30mhellow\e[0m"			#输出黑色“hellow”字体	
[root@localhost ~]# echo -e "\e[31mhellow\e[0m"			#输出红色“hellow”字体
[root@localhost ~]# echo -e "\e[32mhellow\e[0m"			#输出绿色“hellow”字体	
[root@localhost ~]# echo -e "\e[33mhellow\e[0m"			#输出黄色“hellow”字体
[root@localhost ~]# echo -e "\e[34mhellow\e[0m"			#输出蓝色“hellow”字体	
[root@localhost ~]# echo -e "\e[35mhellow\e[0m"			#输出紫色“hellow”字体
[root@localhost ~]# echo -e "\e[36mhellow\e[0m"			#输出青色“hellow”字体	
[root@localhost ~]# echo -e "\e[37mhellow\e[0m"			#输出白色“hellow”字体
[root@localhost ~]# echo -e "\e[40mhellow\e[0m"			#输出黑色背景
[root@localhost ~]# echo -e "\e[41mhellow\e[0m"			#输出红色背景
[root@localhost ~]# echo -e "\e[42mhellow\e[0m"			#输出绿色背景
[root@localhost ~]# echo -e "\e[43mhellow\e[0m"			#输出黄色背景
[root@localhost ~]# echo -e "\e[44mhellow\e[0m"			#输出蓝色背景	
[root@localhost ~]# echo -e "\e[45mhellow\e[0m"			#输出紫色背景
[root@localhost ~]# echo -e "\e[46mhellow\e[0m"			#输出青色背景
[root@localhost ~]# echo -e "\e[47mhellow\e[0m"			#输出白色背景

多个情况下用 “;” 隔开 例如:

[root@localhost ~]# echo -e "\e[5;45;34mhellow\e[0m"  5 设置闪烁;45=紫色背景;34=蓝色字体
实现多色字体输出。

新建 .sh 文件

vim 8colors.sh

源代码

#!/bin/bash
echo -e "\e[30mhellow\e[0m"     
echo -e "\e[31mhellow\e[0m"     
echo -e "\e[32mhellow\e[0m"     
echo -e "\e[33mhellow\e[0m"     
echo -e "\e[34mhellow\e[0m"     
echo -e "\e[35mhellow\e[0m"     
echo -e "\e[36mhellow\e[0m"     
echo -e "\e[37mhellow\e[0m"     

执行 8colors.sh 脚本

[root@localhost ~]# vim 8colors.sh						#新建并写入 .sh文件
[root@localhost ~]# chmod +x ./8colors.sh 				 #给 .sh 文件增加可执行权限
[root@localhost ~]# ./8colors.sh 						#执行
hellow							
hellow
hellow
hellow
hellow
hellow
hellow
hellow													#输出结果
[root@localhost ~]# 

for 循环

for 循环使用方法:

[root@localhost ~]# vim 8c.sh			#新建 .sh 文件

vim 中写入:

for i in {1..5}				#for循环设定一个 ‘替代值 i’定义 i 在1~5之间依次循环一次
do							#循环开始
	echo $i					#循环执行命令
done						#循环结束

实验截图:

[root@localhost ~]# vim 8c.sh			#新建 .sh 文件
[root@localhost ~]# bash 8c.sh			#执行
1
2
3	
4
5									#输出结果(依次输出1~5)
[root@localhost ~]# 

数值测试

参数和说明如下:

-eq 等于则为真 -ne 不等于则为真 -gt 大于则为真 -ge 大于等于则为真 -lt 小于则为真 -le 小于等于则为真

测试选项作用
整数 1 -eq 整数 2判断整数 1 是否和整数 2 相等(equal )
整数 1 -ne 整数 2判断整数 1 是否和整数 2 不相等(not equal)
整数 1 -gt 整数 2判断整数 1 是否大于整数 2(greater than)
整数 1 -lt 整数 2判断整数 1 是否小于整数 2(less than)
整数 1 -ge 整数 2判断整数 1 是否大于等于整数 2(greater than or equal to)
整数 1 -le 整数 2判断整数 1 是否小于等于整数 2(less than or equal to)

for 循环实现多色字体输出。

新建 .sh 文件

vim 8colors.sh

源代码:

#!/bin/bash
for i in {30..37}
do
        echo -e "\e[${i}mhellow\e[0m"
done              

写入内容解析

#!/bin/bash									 #解释shell类型	
for i in {30..37}							  #定义 i 在30 到37之间依次循环1次
do											 #开始
        echo -e "\e[${i}mhellow\e[0m"			#i需要加 {}来与命令内容做区分
done              							   #结束

输出结果:

[root@localhost ~]# vim 8colors.sh 
[root@localhost ~]# ./8colors.sh 					#执行(需要给 .sh 文件加入执行权限)
hellow
hellow
hellow
hellow
hellow
hellow
hellow
hellow											#输出结果:输出不同颜色的文字
[root@localhost ~]# 

2. Bash 的基本功能

1. 历史命令 (history)

历史命令查看方法:

history

选项: -c #清空历史命令 -w #把缓存中的历史命令保存到历史命令文件(默认在~/.bash history) 当我们正常退出(1ogout、exit、ctr1+d)操作系统时,系统会自动将缓存中的历史命令保存到文件里

历史命令的调用 使用上、下光标键调用 使用“!!”,重复执行上一条命令 使用“! n”,重复执行第 n 条历史命令 使用“! 字符”,重复执行最近一条以此字符开头的命令

[root@localhost ~]# !!					#重复执行上一条命令
[root@localhost ~]# !173				#重复执行第173条历史命令(可从history中查看编号)
[root@localhost ~]# !vim				#重复执行最近一条以vim开头的命令

2. Tab 键补全:

可以自动补全文件名、目录名、命令、命令选项(ls --help)、服务名等;

自动补全之前,输入的字符越多补齐的范围越小,就越精确; 使用的软件包: bash-completion;

注: 补齐功能会在目录结尾处自动补上/符号,有时会导致系统识别出现问题,从而报错,如: xfsdump

3. alias

1.查看系统中已生效的别名

alias

[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

2.临时设置新别名

alias 别名 =‘原命令 [选项]’

[root@localhost ~]# alias sys='systemctl start'		#设置别名
[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias sys='systemctl start'						#命令中设置的域名
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

尝试使用设置的别名启动 httpd

sys httpd
ss -anpt |grep 80

执行结果:

[root@localhost yum.repos.d]# sys httpd
[root@localhost yum.repos.d]# ss -anpt |grep 80
LISTEN     0      128         :::80                      :::*                   users:(("httpd",pid=11979,fd=4),("httpd",pid=11978,fd=4),("httpd",pid=11977,fd=4),("httpd",pid=11976,fd=4),("httpd",pid=11975,fd=4),("httpd",pid=11974,fd=4))

#用命令 alias 设置的别名是临时的,退出当前终端则不再生效#

当执行一条命令是命令被从系统中调用的优先级

执行顺序: NO.1 用绝对路径或相对的方式执行命令 NO.2 别名命令 N0.3 bash 内置命令,如 cd 等,可用 type 区分 NO.4 根据环境变量(PATH)定义的目录顺序找到的第一个命令 PATH : /usr/local/sbin: > /usr/local/bin: > /usr/sbin: > /usr/bin: > /root/bin

[root@localhost ~]# echo $PATH 
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

因此可以在/root/bin 下直接写入 .sh 文件并附加执行权限。

#PATH 变量决定了 she11 将到哪些目录中寻找命令或程序。如果要执行的命令的目录在 $PATH 中,您就不必输入这个命令的完整路径,直接输入命令就可以了。一些第三方软件没有将可执行文件放到Linux 的标准目录中。因此,将这些非标准的安装目录添加到 $ PATH 是一种解决的办法。

PATH生效规则:定义两个脚本分别以相同的名字复制到不同的文件夹里,执行命令时,在前面的一个文件夹里的命令生效
vim /root/tt1.sh
	#!/bin/bash
	echo "welcome to 2307~"
chmod +x /root/tt1.sh

vim /root/tt2.sh
	#!/bin/bash
	echo "welcome to 2309~"
chmod +x /root/tt2.sh

echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

cp -a /root/tt2.sh /usr/local/bin/ttcp 
cp -a /root/tt1.sh /usr/local/sbin/tt

执行tt=》welcome to 2307~

再调整时退出终端,或执行export PATH

3.永久设置别名

设置在配置文件中,生效后自动加载, 使用 alias 命令可查看#系统中部分配置文件用 souce 或.命令调用可生效

单个用户生效,写入:~/.bashrc

[root@localhost ~]# vim ~/.bashrc

文件内内容:

# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'								
							#<=================在此处写入想要设置的域名
# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi                                          

修改在此文件中写入并保存即可永久写入。

所有用户生效,写入:/etc/bashrc

[root@localhost ~]# vim /etc/bashrc

####

4.删除别名

unalias [别名]

[root@localhost ~]# unalias sys						#将刚刚创建的sys别名删除
[root@localhost ~]# alias							#查看结果
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
5 删除永久设置的别名
  1. 在设置的配置文件中删除后

  2. 使用 source 或 . +配置文件 #重新加载配置文件

[root@localhost ~]#. ./.bashrc 

root@localhost ~]# source ./.bashrc 
  1. unalias 别名 #删除以缓存的目标域名

即可删除永久设置的别名

4.source 加载文本内容

source 或 . [配置文件] #将脚本内容重新加载至系统

[root@localhost ~]#. 文件名 
[root@localhost ~]# source 文件名 

导出环境变量 作用:(让其他 shell 脚本识别该变量,设为全局变量) source 脚本文件

source 命令用法: source FileName 作用: 在当前 bash 环境下读取并执行 FileName 中的命令。 注: 该命令通常用命令“.”来替代。

如: source .bash_rc 与 . .bash_rc 是等效的。

注意: source 命令与 shell scripts 的区别是: source 在当前 bash 环境下执行命令,而 scripts 是启动一个子 shell 来执行命令。这样如果把设置环境变量(或 alias 等等)的命令写进 scripts 中,就只会影响子 shell, 无法改变当前的 BASH, 所以通过文件(命令列)设置环境变量时,要用 source 命令。

#!/bin/bash
expor DATA=250

source 使文件生效

使用 env 可以查看到环境变量中已经有 DATA

3. Bash 中常用快捷键

查看快捷键方式

stty -a
[root@localhost ~]# stty -a
speed 38400 baud; rows 30; columns 85; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
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
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc
-ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl
echoke
[root@localhost ~]# 

修改快捷键:

stty [关键词] [快捷键]

举例:定义 CTRL+p 快捷键为强制终止

stty intr ^p						# intr为强制终止关键词(见上图↑)“ ^ ” 为手打尖角号 
[root@localhost ~]# stty intr ^p
[root@localhost ~]# stty -a
speed 38400 baud; rows 61; columns 99; line = 0;
intr = ^P; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
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
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
[root@localhost ~]# 

注意:修改快捷键为个人习惯,尽量不要在常规多人服务器内修改快捷键。

Bash 中常用快捷键

快捷键作用
CTRL+a(action)把光标移动到开头
CTRL+e(end)把光标移动到行尾
CTRL+c强制终止当前命令
CTRL+l清空屏幕
CTRL+u光标之前,删除或剪切
CTRL+k光标之后,删除或剪切
CTRL+y粘贴
CTRL+r在历史命令中搜索关键词,弹出最近一次使用的命令,按“→”,即可调出
CTRL+d推出当前终端
CTRL+z暂停放入后台(使用 jobs 命令查看,fg 调出后台任务并继续运行)
CTRL+s暂停屏幕输出,仍能但输入指令
CTRL+q回复屏幕输出

4. 输入输出重定向

设备设备名文件描述符号类型
键盘/dev/stdin0标准输入
显示器/dev/stdout1标准正确输出
显示器/dev/stderr2标准错误输出

1. 重定向符号 > >>

标准输出重定向

即把命令的正确输出,输出到文件或者设备中 错误信息还会被输出到控制台上

格式: 命令 > 文件 #覆盖方式 命令 >> 文件 #追加方式

echo “hello” > 1.txt						#覆盖方式
echo “hello” >> 1.txt						#追加方式
标准错误输出重定向

即把命令的错误输出,输出到文件或者设备中 正确信息还会被输出到控制台上

格式: 命令 2 > 文件 #覆盖方式 命令 2 >> 文件 #追加方式

ls /root/error 2> 1.txt							#覆盖方式
ls /root/error 2>> 1.txt						#追加方式
正确输出和错误输出同時重定向

输出内容(无论对错)写入指定设备或文件中。

格式: 命令 &> 文件 #覆盖方式 命令 &>> 文件 #追加方式

ls /root/error &> 1.txt							#覆盖方式
ls /root/error &>> 1.txt						#追加方式

输出内容写入不同设备或文件中。

格式: 命令 > 文件 1 2 > 文件 2 #覆盖方式 命令 &>> 文件 2 >> 文件 2 #追加方式

ls /root/error > 1.txt 2> 2.txt						#覆盖方式
ls /root/error >> 1.txt	2>> 2.txt					#追加方式
#原始root目錄下沒有/root/error文件,推測實驗結果正確輸出文件中,應該爲空
[root@localhost ~]# ls 							#查看原始的root目錄内容
8colors.sh  anaconda-ks.cfg  initial-setup-ks.cfg  模板  图片  下载  桌面
8c.sh       hello.sh         公共                  视频  文档  音乐
[root@localhost ~]# ls /root/error > 1.txt 2> 2.txt		#執行命令,重定向會新建未識別文件
[root@localhost ~]# ls							#再次查看root目錄
1.txt  8colors.sh  anaconda-ks.cfg  initial-setup-ks.cfg  模板  图片  下载  桌面
2.txt  8c.sh       hello.sh         公共                  视频  文档  音乐
[root@localhost ~]# cat ./1.txt 				 #查看正確輸出文件内容
[root@localhost ~]# cat ./2.txt 				 #查看錯誤輸出文件内容
ls: 无法访问/root/error: 没有那个文件或目录
[root@localhost ~]# 

EFO

自定义结束符: #EOF 是 END Of File 的缩写,表示自定义终止符; 即 EOF 不是固定的, 可以随意设置别名。

语法:

cat << EFO
echo -e "\e[31m nihaoya \e[0m"
echo "ok"
EFO
[root@localhost ~]# cat << EFO
> echo -e "\e[31m nihaoya \e[0m"
> echo "ok"
> EFO
echo -e "\e[31m nihaoya \e[0m"
echo "ok"
[root@localhost ~]# 

EFO 配合 cat 完成多行文本重定向到文件中

语法:

cat << EFO > test.sh
123
abc
789
EFO

cat > test.sh << EFO
123
abc
789
EFO

示例:

[root@localhost ~]# cat << EFO > test.sh		#使用EFO 非交互式写入多行数据重定向到test.sh文件中
> 123
> abc
> 789
> EFO										  #结束
[root@localhost ~]# cat ./test.sh 				#查看是否写入成功
123
abc
789
[root@localhost ~]# 

2. Bash 的标准输出重定向

tee

作用: 会从标准输入设备读取数据,将其内容 以覆盖形式输出到标准输出设备,同时保存在给定文件中;

语法: tee [选项] [文件] 选项: -a 内容追加到给定的文件,默认是覆盖 --help 查看帮助信息 --version 查看版本信息

将就按盘输入内容存在文件中:

tee	t1.txt
Are you ok?
ye i'm ok
# CTRL+c结束

示例:

[root@localhost ~]# tee t1.txt
Are you ok?								#输入内容
Are you ok?								#Enter后输出到标准设备上的内容
ye i'm ok
ye i'm ok
^C										#结束
[root@localhost ~]# cat ./t1.txt 
Are you ok?								#输出到文件内的内容
ye i'm ok
[root@localhost ~]# 

实验: #将文件系统使用的信息追加到文件(追加可以使用来记录日志

df -h |tee -a disk.log

示例:

[root@localhost ~]# df -h |tee -a disk.log
文件系统        容量  已用  可用 已用% 挂载点			#在标准输出设备(终端)输出一次
/dev/sda3        18G  3.6G   14G   21% /
devtmpfs        471M     0  471M    0% /dev
tmpfs           487M     0  487M    0% /dev/shm
tmpfs           487M  8.6M  478M    2% /run
tmpfs           487M     0  487M    0% /sys/fs/cgroup
/dev/sda1       509M  157M  353M   31% /boot
tmpfs            98M  4.0K   98M    1% /run/user/42
tmpfs            98M   32K   98M    1% /run/user/0
/dev/sr0        4.3G  4.3G     0  100% /mnt
[root@localhost ~]# cat ./disk.log 					#在目标文件内在输入一次
文件系统        容量  已用  可用 已用% 挂载点
/dev/sda3        18G  3.6G   14G   21% /
devtmpfs        471M     0  471M    0% /dev
tmpfs           487M     0  487M    0% /dev/shm
tmpfs           487M  8.6M  478M    2% /run
tmpfs           487M     0  487M    0% /sys/fs/cgroup
/dev/sda1       509M  157M  353M   31% /boot
tmpfs            98M  4.0K   98M    1% /run/user/42
tmpfs            98M   32K   98M    1% /run/user/0
/dev/sr0        4.3G  4.3G     0  100% /mnt
[root@localhost ~]# 

wc

作用:统计指定文件的行数、单词数、字数,并输出统计结果

语法: wc [选项] [文件名]

选项 -c #统计字符个数 -w #统计单词数 -l #统计行数

wc anaconda-ks.cfg 

示例:

[root@localhost ~]# wc anaconda-ks.cfg 
  64  156 1633 anaconda-ks.cfg
[root@localhost ~]# wc -c anaconda-ks.cfg 
1633 anaconda-ks.cfg
[root@localhost ~]# wc -w anaconda-ks.cfg 
156 anaconda-ks.cfg
[root@localhost ~]# wc -l anaconda-ks.cfg 
64 anaconda-ks.cfg

3.多命令的执行顺序

格式作用
命令; 命令多个命令顺序执行,无逻辑关系
命令 && 命令当前一个命令正确执行时,才执行下一条命令
命令 || 命令当前一个命令执行不正确的时候,才执行下一条命令

test 判断命令(相当于 if)

格式: test ”DMA“ == ”DMA“ #判断前一条字符是否雨后一条字符一致

test "root" == "root" && echo "true" || echo "fault"

判断前一条命令是否一致:

若一致(命令执行正确)则输出 && 后命令 #由于 || 前命令执行所以 || 后命令不会执行 若不一致(命令执行不正确)则输出 || 后命令 #由于 test 执行不正确,则&&后不执行, #由于&&后不执行,所以 || 后将被执行 示例:

[root@localhost ~]# test "root" == "root" && echo "true" || echo "fault"
true
[root@localhost ~]# 

通配符

通配符作用
匹配任意一个字符
*匹配 0 个 或者 多个 任意字符
[ ]匹配 [ ] 内任意一个字符,
[ - ]匹配 [ ] 区间内任意一个字符
[ ^ ]逻辑非, 匹配除去括号内任意一个字符

示例:

[root@localhost ~]# mkdir ./number
[root@localhost ~]# cd ./number/
[root@localhost number]# touch 123 ABC 0abc abc abcd
[root@localhost number]# ls
0abc  123  abc  ABC  abcd									#准备工作

实验

[root@localhost number]# ls ?abc
0abc

[root@localhost number]# ls *abc
0abc  abc

[root@localhost number]# ls ?[ab]*		#表示列出第一个字符随机,第二个字符取ab任意值的文件
0abc  abc  abcd

[root@localhost number]# ls ?[a-c]*	     #表示列出第一个字符随机,第二个字符取a到c之间任意值的文件
0abc  abc  ABC  abcd					#文件ABC出现的原因是由编码方式决定的
编码方式:

字符集 | 同一个字符集下字母排序很多种 (与 locale 有关)

[root@localhost ~]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"				#当前语境下的排序方式为 aAbBcB……zZ
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=
[root@localhost ~]# 

修改字符集方式

export LC_COLLATE=C							#将当前编码方式改为 C 编码 
[root@localhost ~]# export LC_COLLATE=C
[root@localhost ~]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE=C							# C的编码方式为abcd……zABCD……Z
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=
[root@localhost ~]# 

4. grep

grep (行提取工具) #使用 ”正则表达式“

作用: 过滤一个文件中的指定字符串,是行提取命令(只要包含关键词的行都被显示)格式: grep 选项”关键词“文件名

选项: -A 数字 #列出符合条件的行,并连续列出后续 n 行 -B 数字 #列出符合条件的行,并连续列出前面 n 行。 -C #统计符合条件的字符串行数 -i #忽略大小写 -n #输出行号 -v #反向查找(取反) -o #只列出关键字 --color = auto #搜索出的关键词高亮显示

[root@localhost ~]# grep "root" /etc/passwd		  #输出在/etc/passwd文件中含有root字符的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# 
[root@localhost ~]# grep -A 2 "root" /etc/passwd	#输出在/etc/passwd 文件中含有 root 字符的行,并连续列出后续 2 行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@localhost ~]# 
[root@localhost ~]# grep -c "root" /etc/passwd		#统计在/etc/passwd 文件中含有 root 字符的行数
2
[root@localhost ~]# grep -n "root" /etc/passwd		#输出在/etc/passwd 文件中含有 root 字符的行,并标出所在行号
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]
[root@localhost ~]# grep -o "root" /etc/passwd		#只输出在/etc/passwd 文件中含有 root 字符
root
root
root
root
[root@localhost ~]# grep -v "root" /etc/passwd			#输出在/etc/passwd 文件中不含有 root 字符的行
bin:x:1:1:bin:/bin:/sbin/nologin
...
tcpdump:x:72:72::/:/sbin/nologin
user1:x:1000:1000:user1:/home/user1:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
[root@localhost ~]# 

5. Bash中的其他特殊符号

符号作用
#在shell脚本中,#开头的行代表注释
\转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符
$用于调用变量的值
''单引号,在单引号中所有的符号都是普通字符,即所有的特殊字符都没有特殊含义
""双引号,在双引号中除了特殊符号($、\、``)外,所有符号都是普通字符
``反引号,反引号括起来的内容是系统命令,在bash中会先执行它
$()和反引号作用一样,用来引用系统命令,使用较多、不易与其他符号混淆
()用于一串命令执行时,()中的命令会在子shell中运行
{}用于一串命令执行时,{}中的命令会在当前shell中执行;也可以用于变量变形与替换等
[]用于变量测试,同test命令

单引号和双引号

单引号当中的符号都没有特殊含义; 双引号里绝大多数符号也没有特殊含义,但这 3 个符号保留含义:$ (调用变量的值) 和 ``(反引号,相当于$()执行命令) 和 \ (转义符, 用于取消特殊含义) 。

[root@localhost ~]# echo '$PATH'
$PATH										#由于单引号内说有字符都无特殊意义
[root@localhost ~]# 
[root@localhost ~]# echo "$PATH "
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# 							#双引号内$被定义为调用变量

反引号 ` 和$()

执行 反引号内 或 括号内 命令

[root@localhost ~]# echo $(date)
2024 年 11 月 13 日 星期三 15:54:18 CST
[root@localhost ~]# echo `date`
2024 年 11 月 13 日 星期三 15:54:29 CST
[root@localhost ~]# 

中括号 [ ]

同 test 命令,对表达式作比较,判断是否正确

[root@localhost ~]# [ 3 > 2 ] && echo "T" || echo "F"
T
[root@localhost ~]# test 3 > 2 && echo "T" || echo "F"
T
[root@localhost ~]# 

#注:[ 表达式 ] ,中括号的表达式所有格前后应有一个空格; #注:表达式目前未具体涉及,了解此语法格式即可;

大括号,小括号

()小括号新建子bash运行命令,有父子传递值关系 (父子传值关系:父传子,子不传父)

{}大括号等同于直接运行命令

#使用bash命令可以打开一个新的bash,查看pstree结果中的sshd部分;

#结合父shell和子shell我们来解释花括号和小括号的区别:

相同: ()和{}都是把一串命令放在括号里,并且命令之间用;号隔开 不同: ()执行一串命令时,需要重新开一个子shell进行执行 {}执行一串命令时,在当前shell执行 ()在命令最后可以不加分号 {}在命令最后要加分号 ()里的各命令和括号之间可以没有空格 {}的第一个命令和左括号之间必须要有一个空格

[root@localhost ~]# name = zhangsan 						#在当前 bash 解释器下定义变量
[root@localhost ~]# (name = lisi; echo $name)				#使用小括号重新定义变量并输出
lisi													#输出结果
[root@localhost ~]# echo $name							#在当前 bash 解释器下查看变量是否被更改
zhangsan												#输出结果,发现变量没被更改
[root@localhost ~]# 						#说明小括号在运行命令时是新建子 bash 来运行命令
[root@localhost ~]# name = zhangsan 	
[root@localhost ~]# { name = lisi; echo $name;}
lisi
[root@localhost ~]# echo $name
lisi
[root@localhost ~]# 

5. Shell的变量

1. 变量定义和调用

变量即可变化的量,为了能描述变量,一般用某个特定字符串来代表,称其为变量名;

声明变量: 变量名=值 #赋值

调用变量:echo $变量名 #赋值调用

[root@localhost ~]# number = 12						#定义变量 number 为 12
[root@localhost ~]# echo $number 					#输出变量 number
12													#输出结果
[root@localhost ~]# 

变量命名规则:

1,定义变量时,=左右两边不能有空格 ​ 2,变量名可以由字母、数字和下划线组成,(但是不能以数字开头)3,变量值中若有空格则需要用单引号 ’ 或双引号 “ 引起来

4,可以把一个现有变量的值作为变量值赋给变量

5, 可以把一个命令的结果作为变量值赋给变量

6,调用变量值时,为了保证不与后面的字符(字母、数字、下划线)被误判成新的变量名,需要加花括号进行分隔

7,变量是有类型的,默认是字符串类型 ​ 8,变量是可以叠加的

注:单引号中任何字符都是普通字符,不具备任何特殊含义;而双引号“ ”内的 $、\(转义字符)、``(反引号) 仍然具有特殊含义

公式调用符$

$变量名

$(命名)

$((运算表达式)) 或 $[ ]

$( ) 也可以执行命令,并赋值

[root@localhost ~]# echo $(cat /etc/issue)
\S Kernel \r on an \m
[root@localhost ~]# m =$(cat /etc/issue)						#将执行结果赋值给 m
[root@localhost ~]# echo $m			 					 	#输出变量 m 的值
\S Kernel \r on an \m     

2. 变量分类

自定义变量:由用户自由定义变量名和变量的值,这种变量是最常见的变量;

环境变量:保存的值是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令的提示符等。环境变量的变量名可以自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的;

预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的;

位置参数变量:用来向脚本中传递参数或数据的,变量名不能自定义,变量作用是固定的;

1. 自定义变量:

增 变量名=值 #赋值

删 unset [变量名] #删除变量值

改 变量名=值 #重新定义变量即可

查 set #查看所有变量

set(查看全部变量)

变量查看

格式: set [选项]

选项: -u #调用没有声明的变量时会报错 等同于bash -u +u 表示结束 -x #命令执行前,会先把命令输出一次 等同于bash -x +x 表示结束

[root@localhost ~]# set -u; echo $number
12
[root@localhost ~]# set -u; echo $numbershell				#变量中未设置 numbershell 变量
-bash: numbershell: 为绑定变量
[root@localhost ~]# 
[root@localhost ~]# set -x; echo $number
+ echo 12
12
++ printf '\033]0;%s@%s:%s\007' root localhost '~'
[root@localhost ~]# 

删除变量

格式:

unset [选项]

[root@localhost ~]# unset number								#删除变量
[root@localhost ~]# echo $number								#再次调用变量
-bash: number: 为绑定变量
[root@localhost ~]# 

2. 环境变量

增 export 变量名=值 #声明环境变量

删 unset [变量名] #删除变量值

改 export 变量名=值 #重新定义变量即可

查 env #查看所有变量

export (定义环境变量)

定义环境变量

格式: export 变量名=值

[root@localhost ~]# env |grep size							#查找环境变量中是否有 size 变量
[root@localhost ~]# export size = 1000						#创建环变 size
[root@localhost ~]# env |grep size							#再此查找
size = 1000													#输出结果
[root@localhost ~]# 

#环境变量名一般都大写,但一般很少自定义环境变量,都是使用系统设置好的

env(查看环境变量)

env

执行截图

[root@localhost ~]# env
XDG_SESSION_ID = 1
HOSTNAME = localhost.localdomain
TERM = xterm
SHELL =/bin/bash
HISTSIZE = 1000
SSH_CLIENT = 192.168.59.1 64751 22
SSH_TTY =/dev/pts/0
QT_GRAPHICSSYSTEM_CHECKED = 1
USER = root
LS_COLORS = rs = 0: di = 01; 34: ln = 01; 36: mh = 00: pi = 40; 33: so = 01; 35: do = 01; 35: bd = 40; 33; 01: cd = 40; 33; 01: or = 40; 31; 01: mi = 01; 05; 37; 41: su = 37; 41: sg = 30; 43: ca = 30; 41: tw = 30; 42: ow = 34; 42: st = 37; 44: ex = 01; 32: *.tar = 01; 31:*.tgz = 01; 31: *.arc = 01; 31:*.arj = 01; 31: *.taz = 01; 31:*.lha = 01; 31: *.lz4 = 01; 31:*.lzh = 01; 31: *.lzma = 01; 31:*.tlz = 01; 31: *.txz = 01; 31:*.tzo = 01; 31: *.t7z = 01; 31:*.zip = 01; 31: *.z = 01; 31:*.Z = 01; 31: *.dz = 01; 31:*.gz = 01; 31: *.lrz = 01; 31:*.lz = 01; 31: *.lzo = 01; 31:*.xz = 01; 31: *.bz2 = 01; 31:*.bz = 01; 31: *.tbz = 01; 31:*.tbz2 = 01; 31: *.tz = 01; 31:*.deb = 01; 31: *.rpm = 01; 31:*.jar = 01; 31: *.war = 01; 31:*.ear = 01; 31: *.sar = 01; 31:*.rar = 01; 31: *.alz = 01; 31:*.ace = 01; 31: *.zoo = 01; 31:*.cpio = 01; 31: *.7z = 01; 31:*.rz = 01; 31: *.cab = 01; 31:*.jpg = 01; 35: *.jpeg = 01; 35:*.gif = 01; 35: *.bmp = 01; 35:*.pbm = 01; 35: *.pgm = 01; 35:*.ppm = 01; 35: *.tga = 01; 35:*.xbm = 01; 35: *.xpm = 01; 35:*.tif = 01; 35: *.tiff = 01; 35:*.png = 01; 35: *.svg = 01; 35:*.svgz = 01; 35: *.mng = 01; 35:*.pcx = 01; 35: *.mov = 01; 35:*.mpg = 01; 35: *.mpeg = 01; 35:*.m2v = 01; 35: *.mkv = 01; 35:*.webm = 01; 35: *.ogm = 01; 35:*.mp4 = 01; 35: *.m4v = 01; 35:*.mp4v = 01; 35: *.vob = 01; 35:*.qt = 01; 35: *.nuv = 01; 35:*.wmv = 01; 35: *.asf = 01; 35:*.rm = 01; 35: *.rmvb = 01; 35:*.flc = 01; 35: *.avi = 01; 35:*.fli = 01; 35: *.flv = 01; 35:*.gl = 01; 35: *.dl = 01; 35:*.xcf = 01; 35: *.xwd = 01; 35:*.yuv = 01; 35: *.cgm = 01; 35:*.emf = 01; 35: *.axv = 01; 35:*.anx = 01; 35: *.ogv = 01; 35:*.ogx = 01; 35: *.aac = 01; 36:*.au = 01; 36: *.flac = 01; 36:*.mid = 01; 36: *.midi = 01; 36:*.mka = 01; 36: *.mp3 = 01; 36:*.mpc = 01; 36: *.ogg = 01; 36:*.ra = 01; 36: *.wav = 01; 36:*.axa = 01; 36: *.oga = 01; 36:*.spx = 01; 36:*.xspf = 01; 36:
MAIL =/var/spool/mail/root
PATH =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD =/root
LANG = zh_CN.UTF-8
HISTCONTROL = ignoredups
SHLVL = 1
HOME =/root
LOGNAME = root
XDG_DATA_DIRS =/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
SSH_CONNECTION = 192.168.59.1 64751 192.168.59.144 22
LESSOPEN =||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR =/run/user/0
DISPLAY = localhost: 10.0
_=/usr/bin/env

系统中的环境变量

PATH变量

PATH变量:系统命令存放路径

[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

如果想要追加目录可以直接重新定义

说明:PATH变量的值是用“:”分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入了一个命令时,命令没有设置别名,并且也没有写命令的相对或绝对路径时,系统就会到PATH变量定义的路径中去寻找,是否有可以执行的程序。如果找到则执行,否则会报“命令没有发现”的错误。 让脚本像执行命令一样简单

方法一:可以考虑把自己写的脚本放入PATH对应的目录内 or 方法二:修改PATH变量的值,将我们存放脚本的目录叠加到PATH变量中

[root@localhost ~]# echo $PATH								#查看原始 PATH 环变参数
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# mkdir /root/sh							#新建 root 下 sh 目录
[root@localhost ~]# PATH =$PATH:/root/sh						#对 PATH 环境变量重新定义并新增 sh 目录
[root@localhost ~]# echo $PATH								#再次查看查看 PATH 环变参数
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/sh

#永久设置PATH变量: 单用户生效:~/.bash_profile 所有用户生效:/etc/profile

#相关的配置文件: /etc/profile => ~/.bash_profile => ~/.bashrc => /etc/bashrc #修改/etc路径下的配置文件将会应用到整个系统,属于系统级的配置 #修改用户目录下的.bashrc则只是限制在用户应用上,属于用户级设置

PS1变量

PS1变量:命令提示符设置

[root@localhost ~]# echo $PS1
[\u@\h \W]\$

可用选项:

	\u:	 显示当前用户名
	\h:	 显示简写主机名。如默认主机名“localhost”
	\W:	显示当前所在目录的最后一个目录
	\$:	   提示符。如果是 root 提示符为“#”,如果是普通用户提示符为“$”
	\H:	 显示完整的主机名。如默认主机名“localhost.localdomain”
	\d:	 显示日期,格式为“星期月日”Ø
	\t:	  显示 24 小时制时间,格式为“HH: MM: SS”
	\T:	 显示 12 小时制时间,格式为“HH: MM: SS”
	\A:	 显示 24 小时制时间,格式为“HH: MM”
	\@:	显示 12 小时制时间,格式为“HH: MM am/pm”
	\v:	 显示 Bash 的版本信息 
	\w:	显示当前所在目录的完整名称
	\#:	  执行的第几个命令
[root@localhost ~]# PS1 ='[\u@\d\t\w]'			#自定义 PS1 变量值时需要使用单引号,否则不生效
[root@三 11 月 1318:53:29~]

#永久设置PS1变量:

修改 /etc/bashrc 文件

LANG变量

LANG变量:系统语系变量

[root@localhost ~]# echo $LANG
zh_CN.UTF-8
[root@localhost ~]# 

#Linux安装时,选择的是中文安装,所以默认的主语系变量是“zh_CN.UTF-8”

查看当前使用语系

localectl status #查看当前使用语系

[root@localhost ~]# localectl status
   System Locale: LANG = zh_CN.UTF-8					#当前使用 zh_CN.UTF-8
       VC Keymap: cn
      X11 Layout: cn

查看Linux中支持的所有语系:

localectl list-locales #查看Linux中支持的所有语系:

[root@localhost ~]# localectl list-locales
aa_DJ
aa_DJ.iso88591
aa_DJ.utf8
aa_ER
aa_ER.utf8
aa_ER.utf8@saaho
aa_ER@saaho
aa_ET
...
zh_SG.utf8
zh_TW
zh_TW.big5
zh_TW.euctw
zh_TW.utf8
zu_ZA
zu_ZA.iso88591
zu_ZA.utf8
lines 777-787/787 (END)

修改操作系统语言环境(永久修改操作系统语言环境)

[root@localhost ~]# cat /etc/locale.conf						  #查看操作系统语言配置文件
LANG = "zh_CN.UTF-8"
[root@localhost ~]# localectl set-locale LANG = en_US 			  #该命令直接修改配置文件
[root@localhost ~]# cat /etc/locale.conf						  #再次查看操作系统语言配置文件
LANG = en_US
[root@localhost ~]# 

3.预定义变量

预定义变量作用
$?最后一次执行命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0,则证明上一个命令不正确执行
$$当前进程的进程号(PID)
$!后台运行的最后一个进程的进程号(PID)

$? #最后一次执行命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0,则证明上一个命令不正确执行

[root@localhost ~]# ls /home/
user1
[root@localhost ~]# echo $?
0
[root@localhost ~]# lls /home/
bash: lls: 未找到命令...
相似命令是: 'ls'
[root@localhost ~]# echo $?
127

$$ #当前进程的进程号(PID)

[root@localhost ~]# echo $$								#查看当前进程号
22138
[root@localhost ~]# pstree -p |grep 22138				#查找
           |-sshd(7018)---sshd(22124)---bash(22138)-+-grep(22631)
[root@localhost ~]# 									#进程为当前 bash

$! #后台运行的最后一个进程的进程号(PID)

root@localhost ~]# dd if =/dev/zero of =/dev/null &			#使用白洞文件向黑洞文件内传输,并放入后台
[1] 23568
[root@localhost ~]# echo $!					
23568
[root@localhost ~]# 

4位置参数变量

位置参数变量:根据调用脚本时传入参数值的位置,进行变量赋值和取值

位置参数变量作用
$nn为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数要用大括号包含例 ${10}
$*这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
$@这个变量代表命令行中所有参数,不过$@把每个参数区分对待
$#这个变量代表命令行中所有参数的个数

$n #n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数要用大括号包含例 ${10}

示例

[root@localhost ~]# vim n.sh						#打开并编辑.sh 文件

文件内写入

#!/bin/bash

echo "$0 "
echo "$1 "
echo "$2 "

执行

[root@localhost ~]# vim n.sh
[root@localhost ~]# bash n.sh 1 2 3							#变量之间用空格隔开
n.sh														#将接收到的参数作为变量的赋值输出
1
2
[root@localhost ~]# bash n.sh a b c d 						#不会接受多余变量
n.sh
a
b
[root@localhost ~]# 

优化:

#!/bin/bash

echo " 执行命令:$0 "
echo " 您的年龄:$1 "
echo " 你的性别:$2 "

执行结果

[root@localhost ~]# bash n.sh 18 男						  #提前在命令行后输入$n 参数,用空格隔开
执行命令:n.sh											  #输出结果
您的年龄:18
你的性别:男

$* #这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体

示例

[root@localhost ~]# vim n.sh						#打开并编辑.sh 文件

文件内写入

#!/bin/bash

echo " 执行命令:$0 "
echo " 您的年龄:$1 "
echo " 你的性别:$2 "

echo $*

执行

[root@localhost ~]# vim n.sh
[root@localhost ~]# bash n.sh 18 男
执行命令:n.sh									#echo $0	输出结果
您的年龄:18										#echo $1	输出结果
你的性别:男									  #echo $2	  输出结果
18 男											#echo $*	输出结果,此结果为一个整体。
[root@localhost ~]# 

$@ #这个变量代表命令行中所有参数,不过$@把每个参数区分对待

示例

[root@localhost ~]# vim n.sh						#打开并编辑.sh 文件

文件内写入

#!/bin/bash

echo " 执行命令:$0 "
echo " 您的年龄:$1 "
echo " 你的性别:$2 "


echo $*
echo $@               

执行

[root@localhost ~]# bash n.sh 18 男
执行命令:n.sh
您的年龄:18
你的性别:男
18 男										#echo $*	输出结果,此结果为一个整体。
18 男										#echo $@	输出结果,此结果分别为输入变量是的个体。
[root@localhost ~]# 

$*与 $@ 区别验证

$*与 $@ 区别验证 #遍历变量

验证方法及思路: 使用 for 循环,对$* 和$@ 变量进行重复输出执行,查看两者输出结果区别。

源代码如下:

vim duibi.sh
#!/bin/bash

echo " 变量\$1 的值为:$1 "
echo " 变量\$2 的值为:$2 "
echo " 变量\$3 的值为:$3 "
echo " 变量\$*的值为:$*"
echo " 变量\$@的值为:$@"


for i in "$*"
do
        echo " 验证\$*的值为$i "
done
for i in "$@"
do
        echo " 验证\$@的值为$i "
done         

代码解释

#!/bin/bash

echo " 变量\$1 的值为:$1"								#输出$ 1 变量的值
echo " 变量\$2 的值为:$2"								#输出$ 2 变量的值
echo " 变量\$3 的值为:$3"								#输出$ 3 变量的值
echo " 变量\$*的值为:$*"								#输出$* 变量的值
echo " 变量\$@的值为:$@"								#输出$@变量的值


for i in " $*"								#启用for循环,将$*输出结果赋值给局部变量 i,并进入循环
do
        echo " 验证\$*的值为$i "			#循环输出变量 i 的值
done
for i in " $@"								#启用for循环,将$@输出结果赋值给局部变量 i,并进入循环
do
        echo " 验证\$@的值为$i "			#循环输出变量 i 的值
done       

执行结果

[root@localhost ~]# vim duibi.sh
[root@localhost ~]# bash duibi.sh 1 2 3				#执行.sh 脚本并给 $1 2 3 赋值
变量$1 的值为:1
变量$2 的值为:2
变量$3 的值为:3
变量$*的值为:1 2 3
变量$@的值为:1 2 3
验证 $*的值为1 2 3					#echo $*	输出结果,此结果为一个整体。
验证 $@的值为1						#echo $@	输出结果,此结果分别为输入变量是的个体。
验证$@的值为 2
验证$@的值为 3
[root@localhost ~]# 

$# #这个变量代表命令行中所有参数的个数

示例

#!/bin/bash

echo " 执行命令:$0 "
echo " 您的年龄:$1 "
echo " 你的性别:$2 "

echo $*
echo $@
echo $#

执行

[root@localhost ~]# vim n.sh
[root@localhost ~]# bash n.sh 18 男
执行命令:n.sh
您的年龄:18
你的性别:男
18 男
18 男
2									#echo $# 输出结果,输出命令行中所有参数的个数
[root@localhost ~]# 

read(交互式键盘输入)

read #接收键盘输入,完成交互式操作

语法:

read [选项] [变量名]

选项: -p “提示信息” 在read等待时输入的信息

-t 秒数 read等待的秒数 (只在该选项存在的行开始等待。) ​ -s 隐藏输入信息 ​ -n 字符数 read最多能接收的字符数(达标即执行)

read -p	""	name			=				echo -n ""
											read	name

写入root用户登录选项:

需求:验证root用户,密码123456,密码要求隐藏输入,正确则输出绿色登陆成功,错误则输出闪烁红色登陆失败。

源代码如下:

vim denglu.sh
#!/bin/bash

read -p "请输入用户名:" nam
read -sp "请输入密码:" passwd
echo
test $nam == root && test $ passwd == 123456 \
&& echo -e "\e[32m 登陆成功\e[0m " || echo -e "\e[31:5m 登陆失败\e[0m "    

代码解析

#!/bin/bash

read -p "请输入用户名:" nam								 #使用 read -p 附加提示信息,并对 nam 赋值
read -sp "请输入密码:" passwd							  #使用-s 选项隐藏输入值 并用-p 附加提示信息,并对 passwd 赋值
echo														 #由于 read 的 bug 问题,-s 选项不会换行,此 echo 为换行符
test $nam == root && test $ passwd == 123456 \				 #对比输入变量值是否正确	"\" 表示命令未写完,强制换行符。
&& echo -e "\e[32m 登陆成功\e[0m " || echo -e "\e[31:5m 登陆失败\e[0m "   		#输出信息

执行结果

[root@localhost ~]# bash denglu.sh						#错误执行
请输入用户名:root
请输入密码:												#密码被隐藏
登陆失败
[root@localhost ~]# bash denglu.sh						#正确执行
请输入用户名:root  
请输入密码:												#密码被隐藏
登陆成功

注意:因为某些特殊选项会出现不自动换行的bug,请使用echo 来设置换行。

read变量名定义:

  • 变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY

  • 如果只提供了一个变量名,则整个输入全部赋予该变量

  • 如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有值

5. Shell的常用运算符

声明指定类型的变量

数值运算需要使用 declare 声明变量类型;

类型分类:

整数型、数组型、环境变量、只读变量

类型:字符串 --、 数值 -i int 、数组 -a array

declare(声明变量类型)

格式:

declare [+|-] [选项] 变量

选项:

- 给变量设置类型(-- 表示字符串类型) ​ + 取消变量类型 ​ -i 将变量声明成整数型 ​ -a 将变量声明成数组型 ​ -x 将变量声明成环境变量,数组不行 ​ -r 将变量声明成只读 ​ -p 显示指定变量的类型和内容

declare	-p					#查看指定变量类型
[root@localhost ~]# declare -p PATH
declare -x PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin"		# -x 表示 PATH 为环境变量
[root@localhost ~]# 

整数型(int)

shell中的变量默认类型是字符串,两个字符串变量相加效果是字符串拼接

[root@localhost ~]# declare -i number = 100					#新建整数型变量 并查看
[root@localhost ~]# declare -p number
declare -i number = "100"
[root@localhost ~]# 

整数型变量可以直接进行运算处理

[root@localhost ~]# declare -i a1 = 100 b1 = 300
[root@localhost ~]# declare -p a1 b1
declare -i a1 = "100"
declare -i b1 = "300"

#直接进行数值运算:
[root@localhost ~]# number = $a1+$ b1 ; echo $number
400

被赋值的变量为整数型,即使是字符串直接作做运算也会被赋值运算结果,不会赋值字符串叠加

[root@localhost ~]# a2 = 100 b2 = 200						#给 a2 b2 赋值并查看类型
[root@localhost ~]# declare -p a2 b2				
declare -- a2 = "100"										#均为字符串类型
declare -- b2 = "200"
[root@localhost ~]# declare -i number = 0					#设置 int 类型,并查看
[root@localhost ~]# declare -p number
declare -i number = "0"									#为 int 类型
[root@localhost ~]# number = $a2+$ b2						#直接运算
[root@localhost ~]# echo $number 					
300														#输出结果
数组型(array)

特点:

一组数,有顺序。 下标,从0开始

#数组是多个相同类型的元素组成的,是有序的,可以通过下标进行操作;

#数组的定义及赋值,数组下标是从0开始的,范围是[0,数组长度-1]

增 只要有[ ] 就会自动生成数组类型([]内写入数组对应位置编号)

删 unset

改 变量值[数组编号]=[值]

查 set ,declare

新增数组变量

[root@localhost ~]# declare -a nam
[root@localhost ~]# nam =(xi mi ji pi ki)
[root@localhost ~]# declare -p nam
declare -a nam ='([0] = "xi" [1] = "mi" [2] = "ji" [3] = "pi" [4] = "ki")'
[root@localhost ~]# 

直接添加数组([]内写入数组对应位置编号)

[root@localhost ~]# bae [2] = iso
[root@localhost ~]# declare -p bae
declare -a bae ='([2] = "iso")'
[root@localhost ~]#

改变数组内数值:

[root@localhost ~]# declare -p nam
declare -a nam ='([0] = "xi" [1] = "mi" [2] = "xx" [3] = "pi" [4] = "ki")'
[root@localhost ~]# 

调取数组内的值:

echo echo ${nam[1]}
[root@localhost ~]# declare -p nam					#查看变量 nam 变量类型
declare -a nam ='([0] = "xi" [1] = "mi" [2] = "ji" [3] = "pi" [4] = "ki")'
[root@localhost ~]# echo ${nam[1]}					#调用数组 nam 编号为 1 的变量值
mi													#输出结果
[root@localhost ~]# 

#获取数组所有的值,*将所有值作为一个整体:

echo ${nam[*]}

[root@localhost ~]# echo ${nam[*]}
xi mi xx pi ki

#获取数组所有的值,@可以将所有值分开:

echo ${nam[@]}

[root@localhost ~]# echo ${nam[@]}
xi mi xx pi ki

#获取数组长度: echo ${#nam[@]} 或 echo ${#nam[*]}

[root@localhost ~]# echo ${#nam[@]}
5
[root@localhost ~]# echo ${#nam[*]}
5

#获取所有值时,*和@的区别,同位置参数变量

#!/bin/bash

tianqis =(a b c d)
echo ${tianqis[2]}

for i in "${tianqis[@]}"
do
	echo "@:"$i
done

for i in "${tianqis[*]}"
do
	echo "*:"$i
done

执行结果

[root@localhost ~]# bash for1.sh
c
@: a
@: b
@: c
@: d
*: a b c d

总结:

遍历数组的值 a 长度: ${#a[*]} ${#a[@]} 取所有值: ${a[*]} ${a[@]} 取某个值: ${a[index]} ,index=0~(${#a[@]} -1)

${#a[index]} 这个值的字符的个数 #index角标

环境变量

用declare -x命令 声明环境变量 和export命令作用一样

#与普通变量不同,环境变量也被称为全局变量,可以传到子shell中,但传子不传父

只读属性

只要对变量设置了只读属性,这个变量只能进行调用,不能进行修改和删除,甚至不能进行取消只读选项

[root@localhost ~]# declare -r salary = 10w					#设置只读属性变量
[root@localhost ~]# echo $salary							#输出变量
10w
[root@localhost ~]# salary = 12w 								#尝试修改
-bash: salary: 只读变量
[root@localhost ~]# declare +r salary						#删除制度属性
-bash: declare: salary: 只读变量
[root@localhost ~]# unset salary 							#删除变量
-bash: unset: salary: 无法反设定: 只读 variable
[root@localhost ~]# 

#退出终端只读变量就没有了

常用运算符号

优先级运算符功能描述
1+ -正、负
2()小括号
3* / %乘、除、取余
4+ -加、减
5+= -=自增、自减

#表格中的优先级是乘除优先于加减,但是若加减被()调用,则括号内的优先级高于乘除

expr 进行数值运算

格式:

expr [运算步骤]

注意 :在运算符两边要有空格,否则不会正常运算

[root@localhost ~]# declare -p a2 b2
declare -- a2 = "100"
declare -- b2 = "200"
[root@localhost ~]# expr $a2 + $ b2
300

let 进行数值运算

格式:

let [新变量]=[运算步骤]

注意 :运算符左右不需要空格,但是需要声明一个新变量用于接收计算结果

[root@localhost ~]# x = 100
[root@localhost ~]# y =-200
[root@localhost ~]# let h = $x+$ y; echo $h
-100
[root@localhost ~]# 

使用 let 命令实现自增自减

格式:

let [变量值]+=[增长值] #自增 let [变量值]-=[减少值] #自减

自增值为1时: 自减值为1时:

let [变量值]++ let [变量值]--

自增

[root@localhost ~]# declare -i num = 100
[root@localhost ~]# let num+= 15
[root@localhost ~]# echo $num
115
------------------------------------------------------------------------------
[root@localhost ~]# declare -i num = 100
[root@localhost ~]# let num++
[root@localhost ~]# echo $num
101

自减

[root@localhost ~]# declare -i num = 100
[root@localhost ~]# let num-= 15
[root@localhost ~]# echo $num
85
------------------------------------------------------------------------------------
[root@localhost ~]# declare -i num = 100
[root@localhost ~]# let num--
[root@localhost ~]# echo $num
99

运算符号

数值运算:+ - * / % ()

除法 “/” 商的符号 除数和被除数 同号为正、异号为负

[root@localhost ~]# expr 10 / 3
3
[root@localhost ~]# expr 12 / 3
4
[root@localhost ~]# expr 12 / 7
1
[root@localhost ~]# expr 459 / 7
65

取余 “%” 余数可能出现的数字数量 和被除数符号一致

[root@localhost ~]# expr 9 % 7
2
[root@localhost ~]# expr 10 % 3
1

随机变量 $RANDOM

[root@localhost ~]# echo $RANDOM 
14706
[root@localhost ~]# echo $RANDOM 
14492

需求:随即输出10个随机数字

源代码:

vim suiji.sh
#!/bin/bash
for ((i = 0; i <= 9; i++))				#i 为 0 每循环一次 i 加一 	i 大于 9 时停止	
do
        echo "$RANDOM "
done       

取模:余数符号 和除数符号一致

使用 $(( )) 或 $[ ] 进行数值运算

格式:

$((运算表达式)) $[运算表达式]

[root@localhost ~]# x = 100
[root@localhost ~]# y = 200
[root@localhost ~]# echo $(($ x+$y))
300
[root@localhost ~]# x = 100
[root@localhost ~]# y = 200
[root@localhost ~]# echo $[$ x+$y]
300
|bc 小数运算
[root@localhost ~]# echo "4.6+2.5"
4.6+2.5
[root@localhost ~]# echo "4.6+2.5"|bc
7.1
[root@localhost ~]# echo " 4.6*2.5 "|bc
11.5
[root@localhost ~]# 

登陆环境变量的配置文件

用户登录系统时涉及到的环境变量配置文件及调用顺序:

/etc/profile => ~/.bash_profile => ~/.bashrc => /etc/bashrc #修改/etc路径下的配置文件将会应用到整个系统,属于系统级的配置 #修改用户目录下的.bashrc则只是限制在用户应用上,属于用户级设置

/etc/profile 配置文件:

vim /etc/profile

#先调用/etc/profile文件在这个环境变量配置文件中会定义这些默认环境变量 1,USER变量 根据登录用户,给这个变量赋值(就是让USER变量的值保存当前用户名) 2,LOGNAME变量 根据USER变量的值,给这个变量赋值 3,MAIL变量 根据登录的用户,定义用户的邮箱为/var/spool/mail/用户名 4,PATH变量 根据登录用户的身份,决定PATH变量是否包含专属目录(/root/sh) 5,HOSTNAME变量 更改主机名,给这个变量赋值 6,HISTSIZE变量 定义历史命令的保存条数

~/.bash_profile配置文件

vim ~/.bash_profile

#.bash_profile文件就没有那么复杂了,这个文件主要实现了两个功能,调用了~/.bashrc文件,在PATH变量后面加入了“:$HOME/bin”这个目录

1,调用了~/.bashrc文件 2,在PATH变量后面加入了“:$HOME/bin”这个目录。那也就是说,如果我们在自己的家目录中建立bin目录,然后把自己的脚本放入“~/bin”目录,就可以直接执行脚本,而不用通过目录执行了

~/.bashrc 配置文件

vim ~/.bashrc 

定义默认别名,调用/etc/bashrc

1,定义默认别名,所以我们把自己定义的别名也放入了这个文件 2,调用/etc/bashrc

vim /etc/bashrc配置文件

vim /etc/bashrc

1,PS1变量:即用户的提示符,如果我们想要永久修改提示符,就要在这个文件中修改 2,umask:定义umask默认权限。这个文件中定义的umask是针对“没有登录过程(也就是不需要输入用户名和密码时,比如从一个终端切换到另一个终端,或进入子Shell)”时生效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效 3,PATH变量:会给PATH变量追加值,当然也是在“没有登录过程”时才生效 4,调用/etc/profile.d/*.sh文件:q

#修改的配置文件及生效:

方法一:使用该配置文件被系统调用的时机

#/etc/profile 和 ~/.bash_profile 在用户登录时调用 #~/.bashrc 和 /etc/bashrc 在每次打开shell时被调用

方法二:执行souce或点命令立即生效

source 文件名 或 . 文件名

#永久给所有用户设置alias cc='clear'

vim /etc/bashrc
	alias cc ='clear'
source /etc/bashrc
cc

文件的执行顺序为:

当登录Linux时,首先启动/etc/profile,然后启动当前用户目录下的/.bash_profile,执行此文件时会调用/.bashrc文件,而执行/.bashrc时会调用/etc/bashrc,最后退出shell时,执行/.bash_logout。

注销专用环境变量配置文件

在用户退出登录时,只会调用一个环境变量配置文件:~/.bash_logout

$ vim .bash_logout
#这个文件默认没有写入任何内容,可是如果我们希望再退出登录时执行一些操作,比如清除历史命令,备份某些数据,就可以把命令写入这个文件

$ vim .bash_logout
mkdir /root/beifen
mv /root/*.sh /root/beifen
echo "byebye~"

$ exit
shell登录信息

#查看一个机器的用户登录情况

w

#登录类型

1,本地登录:ttyn,其中n从1-6 2,远程登录:pts/n,其中n从0开始

#查看当前登录的终端

tty

#本地终端上默认的登录信息

cat /etc/issue

#查询组合作用可用

man agetty

\d 显示当前系统时间 \s 显示操作系统名称 \l 显示登录的终端号 \m 显示硬件体系结构 \n 显示主机名 \o 显示域名 \r 显示内核版本 \t 显示当前系统时间 \u 显示当前登录用户的序列号

登录提示信息(欢迎与或警告信息),保存即生效 1,只针对本地登录的终端;虚拟机打开就可以看见

vim /etc/issue
welcome from the local~

2,对本地登录和远程登录的终端都生效;用户名密码验证成功后可以看到

vim /etc/motd
please use it safety~

练习:软件安装辅助

观察下图,请使用你目前所掌握的shell语法,实现该效果。

需求如下:

  1. 输出下图的样式,作为工具的交互界面。

  2. 当执行该脚本后,检测当前系统是否安装了tree命令:工具,若安装,则输出tree工具已安装;若未安装,则输出tree工具未安装。

  3. 最后的检测结束行,要闪烁,提示用户检测已经结束。 ===========软件测试工具========= ||*声明:该工具检测系统是否缺少 || ||运维工具命令,并帮助暗示装饰用.*|| ===========检测中......=========== 请输入你想检查的软件:ifconfig ifconfig工具已安装 ===========检测结束.....==========

实操代码如下:

#!/bin/bash
echo -e "\e[32m ==== ==== === 软件测试工具== ==== ==== = 
||*声明:该工具检测系统是否缺少  ||
||运维工具命令, 并帮助暗示装饰用.*||
==== ==== === 检测中......== ==== ==== =\e[0m "
echo 0 > cheak
read -p "请输入你想检查的软件:" num
$num &> /dev/null && echo -e "\e[36m${num}工具已安装\e[0m " || yum search $num |grep "\." > cheak
m =$(cat cheak)
if [ $m == 0 ] 2 > /dev/null
then
        echo -e "\e[32:5m ==== ==== === 检测结束.....== ==== ==== =\e[0m " 
else
        cut -d ":" -f 1 cheak
        read -p "请选择安装版本或组件包" bao
        yum -y install $bao
fi
rm -rf cheak

代码解析

#!/bin/bash
echo -e "\e[32m ==== ==== === 软件测试工具== ==== ==== = 													
||*声明:该工具检测系统是否缺少  ||
||运维工具命令, 并帮助暗示装饰用.*||
==== ==== === 检测中......== ==== ==== =\e[0m "																#基础框架
echo 0 > cheak																						#新建一个 cheak 文件并输出一个 0 进行覆盖
read -p "请输入你想检查的软件:" num																	#读取用户输入指令
$num &> /dev/null && echo -e "\e[36m${num}工具已安装\e[0m " || yum search $num |grep "\." > cheak			#执行并将正反向结果全部输入黑洞中,判断执行是否成功。
																										#成功显示“安装成功”
																										#失败则执行 yum 查询并以覆盖形式输入到 cheak 文件中

m =$(cat cheak)																							#将 cheak 文件结果赋值给 变量 m

if [ $m == 0 ] 2 > /dev/null				#if 循环判断 m 变量是否等于 0,如果等于 0 说明没有执行 yum 查找命令。(这里由于会出现语法错误【多个字符串与 0 做对比】导致需要将错误输出结果,输出到黑洞中,但不影响正常工作)
then
        echo -e "\e[32:5m ==== ==== === 检测结束.....== ==== ==== =\e[0m " 									#正确则输出结束语句
else			
        cut -d ":" -f 1 cheak																		#反之输出 cheak 文件中以“:”为分割的第一列数据
        read -p "请选择安装版本或组件包" bao															#提示用户需要安装的包名
        yum -y install $bao																			#安装包名
fi																										#循环结束


rm -rf cheak																							#删除 cheak 文件(此处可能会产生 bug,解决方案:在终端执行此命令)

shell进阶

1. 正则表达式

  • 上一章说过通配符的功能,结合系统命令进行模糊查询,跟find结合用来查询指定名称的文件名;

  • 而正则表达式是在文件中匹配符合条件的字符串,常跟grep命令结合进行精确匹配

  • 扩展正则是对基础正则的补充,结合grep时需要用-E选项,或直接用egrep命令

    正则: 匹配字符:. 任意一个字符; - 指定范围一个字符 a* .* []*

    匹配次数:* 任意次(0-任意多次) ? 次数(0-1次),匹配前一个字符至少最多出现一次 [ -]?

    次数 (>1),匹配前一个字符至少出现一次 ​ {n,} {n}

    匹配位置:^ 开头 $ 行尾 整体:() 单个字符为一个搜索项时 或: | 多字符为一个搜索项时

    单字符 [abc] = (a|b|c) 多字符 (ad|bc)

基础正则表达式

元字符作用
.匹配除换行符以外的任意一个字符
*前一个字符匹配0或任意多次
^匹配行首
$匹配行尾
[]匹配中括号中指定的任意一个字符
[^]匹配除中括号的字符以外的任意一个字符
\转义符,用于取消特殊符号的含义

扩展正则表达式 (egrep)

扩展元字符作用
+前一个字符匹配1次或任意多次
前一个字符匹配0次或1次
{n}表示其前面一个字符恰好出现n次
{n,}表示其前面一个字符出现不小于n次
{n,m}表示前面的一个字符至少出现n次,最多出现m次
|匹配两个或多个分支选择
()匹配()内的整体,可以理解为由多个单个字符组成的大字符

grep(复习)

跳转至,基础阶段第4标题,第4子标题

grep #功能:在指定文件中过滤包含指定字符串的行

格式:

grep [选项] ”关键词“ 文件名

选项:

-A 数字 #列出符合条件的行,并连续列出后续n行。 ​ -B 数字 #列出符合条件的行,并连续列出前面n行。 ​ -c #统计符合条件的字符串行数 ​ -i #忽略大小写 ​ -n #输出行号 ​ -v #反向查找(取反) ​ -o #只列出关键字 ​ -w #强制匹配和字符串一样的 ​ -E #使用扩展正则表达式

注意:

#选项是直接对目标行,进行筛选(符合要求字符的行比列出)

#而正则表达式是对目标字符串进行筛选(符合要求的字符串被标红)

grep结合正则表达式实现关键信息行级截取

vim test.txt

#准备测试数据

ni
hao
ma?
123
abc123
123abc

a
bb
ccc
bbbddd

ni hao ma?
ni hen hao
ni bu hao
bu bu hao

测试内容:

字符匹配

#匹配字符串,h开头、o结尾,中间穿插任意一个字符。

grep "h.o" test.txt	

#匹配有a或s或d的字符

grep "[asd]" test.txt
区别于:
grep -v [asd] test.txt

#[]含义是匹配中括号中任意一个字符,注意只能匹配一个字符 #[^]含义是匹配不含有中括号里任意一个字符的行,注意也是一个一个字符匹配 [0-9] [a-z] [A-Z] [a-Z] 类似这样的都可以,指定匹配的范围 [^0-9]匹配除了数字以外的任意一个字符

次数匹配

#表达式*含义是匹配其前一个字符任意多次

grep " a*" test.txt

#查看a*的结果行数和文件的行数相同,即所有行都被搜出来了 #则a*代表过滤a出现任意次的,即零次或任意次数,即把所有行拿出来,没太大意义

.*相当于通配符的*功能 a*匹配所有 aa*至少匹配包含一个a的行 a.*匹配以a开始的后面任意内容的行

? 表示前面字符出现0次或者1次

+ 表示前面字符出现1次或任意次 {n} 表示前面的字符恰好出现n次 {n,} 表示其前面的字符出现不小于n次 {n,m} 匹配其前面的字符出现不小于n次,最多出现m次

匹配b出现0次或者一次的行

grep "b\?" test.txt
或:
grep -E "b?" test.txt
或:
egrep "b?" test.txt

匹配含有b的行

egrep "b+" test.txt

{n} 表示前面的字符恰好出现n次

egrep "b{2}" test.txt

{n,} 表示其前面的字符出现不小于n次

egrep "b{2,}" test.txt

{n,m} 匹配其前面的字符出现不小于n次,最多出现m次

egrep "b{1,2}" test.txt

位置匹配

^ 匹配行首,$ 匹配行尾 #用“^$”匹配空白行

grep "^$" test.txt

#匹配以b开始的行

egrep "^b+" test.txt

#匹配不是以字母开头的行

grep "^[^a-z]" test.txt

分支和整体匹配

#分支匹配

#同时匹配ni hen hao和ni bu hao

egrep "ni (hen|bu)" test.txt
egrep "ni hen|ni bu" test.txt

#可以匹配一个整体的个数,类似匹配字符个数

egrep "(bu)+" test.txt

正则表达式练习:

匹配电话号码:

  • 以区号025开头

  • 号码是5或8开头的八位数

  • 区号和号码间可以是空格、-或没有

#测试数据 02588888888 025-5555555555 025 12345678 025 54321678 025ABC88888 025-85432109 028-85643210 0251-52765421

实验准备:

[root@localhost ~]# cat << efo > tel.sh					#新建 tel.sh 文件并写入测试数据
02588888888
025-5555555555
025 12345678
025 54321678
025ABC88888
025-85432109
028-85643210
0251-52765421
efo

可以的正则表达式:

egrep "^(025)[ -]?[58][0-9]{7}$" tel.sh

手机号匹配需求: 长度11位, 第一位是1, 第二三位是:130、131、132、145、155、156、185、186, 剩余位:不限制

egrep "^1(3 [012]|[45] 5|56|8 [5|6])[0-9](8)$"

#以 1 开头,第二三位数字为(30,31,32 或者 45,55,或者 56,或者 85,86)仅限 8 位 0-9 的数字结束 

匹配邮箱

  • 邮箱格式:用户名@二级域名.顶级域名

  • 用户名:字符长度在5-17位,是除了@和空格以外的任意字符,开头只能是字母或者_

  • 二级域名:长度不限,符号为数字、小写字母、中横线-(不能连续、不在行尾)

  • 顶级域:域名后缀范围在.com、.cn、.com.cn中

实验数据

zhangsan123@qq.com
li si@163.com
wang@wu@sina.com
zhao liu@126.com
qianqi@sina.com.cn
tester_ni@-sina.com.cn
wangwu@sina.2com.cn
_user1@@jd-1.com

写入实验数据

[root@localhost ~]# cat << efo > mail.txt
> zhangsan123@qq.com
> li si@163.com
> wang@wu@sina.com
> zhao liu@126.com
> qianqi@sina.com.cn
> tester_ni@-sina.com.cn
> wangwu@sina.2com.cn
> _user1@@jd-1.com
> efo

使用以下正则表达式查询

 
匹ip地址

([0-9]{1,3}.){3}[0-9]{1,3}

0-255

1位: ​ 粗略:[0-9]{1,3} ​ 细致:[0-9]|1-9|10-9|20-4|25[0-5]

egrep "[0-9]{1,3}\.){3}[0-9]{1,3}"
egrep "([0-9]|[1-9][0-9]|1 [0-9][0-9]|2 [0-4][0-9]|25 [0-5]\.){3}([0-9]|[1-9][0-9]|1 [0-9][0-9]|2 [0-4][0-9]|25 [0-5])"

2. 字符截取和替换命令

cut命令

功能:用于从文件或标准输入中提取指定字段或列

语法:

cut [选项] 文件名

选项:

-f 列号 提取第几列,默认识别制表符分割出来的列 ​ -d 分隔符 按照指定的分割符进行分割,然后结合-f提取指定列 ​ -c 字符范围 不依赖分割符来分割,而是通过字符范围进行提取 ​ n-m 表示从第n提取到第m个字符 ​ n- 表示从第n个字符开始提取到结尾 ​ -m 表示从第一个字符提取到第m个

#准备测试数据:添加以下内容,列之间用制表符分割(tab)

$ cat cut.txt
1    	2  		 3    	 4     	5
ID     NAME    LINUX   MYSQL   DOCKER
0      xzhao   95     59     78
1      xqian   83     75     93
2      xsun  	74     96     63

-f 列号 提取第几列,默认识别制表符分割出来的列

[root@localhost ~]# cut -f 2,3 cut.txt 
2		3
NAME	LINUX
xzhao	95
xqian	83
xsun	74

-d 分隔符 按照指定的分割符进行分割,然后结合-f提取指定列

[root@localhost ~]# cut -d : -f 1,4,6 /etc/passwd			#passwd 文件内以“:”为分割,查看第 1(用户名),4(GID),6(用户家目录)列
root:0:/root
bin:1:/bin													#输出结果
daemon:2:/sbin
adm:4:/var/adm
lp:7:/var/spool/lpd
sync:0:/sbin
shutdown:0:/sbin
halt:0:/sbin
mail:12:/var/spool/mail
operator:0:/root
games:100:/usr/games
ftp:50:/var/ftp
nobody:99:/
systemd-network:192:/
dbus:81:/
polkitd:998:/
sshd:74:/var/empty/sshd
postfix:89:/var/spool/postfix
[root@localhost ~]# 

-c 字符范围 字符范围可以按照字符数量进行截取,按照对应格式可以取到对应位置的字符 截取多个范围的字符时用,隔开

格式:[n-m]、[n-]、[-m]

[root@localhost ~]# head -5 anaconda-ks.cfg
#version = DEVEL
# System authorization information
auth --enableshadow --passalgo = sha512
# Use CDROM installation media
cdrom
[root@localhost ~]# head -5 anaconda-ks.cfg | cut -c 1-5
#vers
# Sys
auth 
# Use
cdrom
[root@localhost ~]# head -5 anaconda-ks.cfg | cut -c 1-5,30-35
#vers
# Sysation
auth o = sha5
# Usea
cdrom
#练习:使用cut将磁盘的使用率截取出来
df -h | cut -d "%" -f1 | cut -c 1-24,44-46

步骤:

[root@localhost ~]# df -h
文件系统                 容量  已用  可用 已用% 挂载点
/dev/mapper/centos-root   18G  1.4G   17G    8% /
devtmpfs                 475M     0  475M    0% /dev
tmpfs                    487M     0  487M    0% /dev/shm
tmpfs                    487M  7.7M  479M    2% /run
tmpfs                    487M     0  487M    0% /sys/fs/cgroup
/dev/sda1                509M  126M  383M   25% /boot
tmpfs                     98M     0   98M    0% /run/user/0
[root@localhost ~]# echo "/dev/mapper/centos-root   18G  1.4G   17G  "|wc -c
44
[root@localhost ~]# df -h | cut -d "%" -f1 | cut -c 1-24,44-46
文件系统                 容量 
/dev/mapper/centos-root  		  8
devtmpfs                  0
tmpfs                     0
tmpfs                     2
tmpfs                     0
/dev/sda1               	 25
tmpfs                     0

awk命令(列级截取工具)

功能:awk是一种编程语言,用于在linux/unix中对文本和数据进行处理,awk既可以实现对文件的行提取,也可以实现对文件的列提取,是一个很全面的工具,此处我们只讲在Linux中如何利用awk进行字符串过滤,不讲过多关于awk编程的内容。

格式:

awk '条件{动作}' 文件名

1,条件的作用:通过指定条件过滤出符合条件的行,没有指定则是操作所有行 2,动作的作用:通过动作将符合条件的行打印出来,并且在打印时我们可以选择打印该行中的哪些列

#不指定任何条件,直接执行动作,并选择输出哪些列,常用printf来打印(printf自身认为输出的字段为一个整体所以需要在每列 ($)后加分割符 \t(tab)\n(换行)来完整格式)

[root@localhost ~]#  cut -f 2,5 cut.txt
2	5
NAME	DOCKER
xzhao	78
xqian	93
xsun	63
[root@localhost ~]# awk '{printf $2"\t"$ 5 "\n"}' cut.txt
2	5
NAME	DOCKER
xzhao	78
xqian	93
xsun	63
#由此可知这两条命令等价

awk的内置参数

内置变量 作用 $0 代表awk读入当前行的整行数据 $n 代表awk读入当前行的第n列数据 NR 代表当前awk正在处理的行的行号 NF 代表当前awk读取数据总字段数(总列数) FS 用来声明awk的分隔符,如BEGIN {FS=":"}

awk生命周期

  1. grep,sed和awk都是读一行处理一行,直到处理完成

  2. 接收一行作为输入

  3. 把刚刚读入进来得到文本进行分解

  4. 使用处理规则处理文本

  5. 输入一行,赋值给$0,直至处理完成

  6. 把处理完成之后的所有数据交给END{}来再次处理

awk的工作原理

  • 先查看是否有BEGIN条件,有则先执行BEGIN后面定义动作

  • 如果没有BEGIN条件,则先读入第一行,把第一行的数据使用分隔符分隔好之后依次依次赋值给变量$0 $1 $2 $3 ...等变量,$0 代表整行数据,$1 则为第一个字段,依次类推(有点类似于未知参数变量)

  • 第一行将所有内容赋值完成后,进行条件判断,按照符合条件的动作执行

  • 处理完第一行之后,将第二行赋值,重复第一行的所有步骤即可,依次直到处理完整个文本

统计每行的总字段数(每行有多少 字段 ,默认以空格为分割)

awk '{print NF}'
[root@localhost ~]# awk '{print NF}' cut.txt
5
5
5
5
5

$0 : 代表当前行(相当于匹配所有)

$0 : 代表当前行(相当于匹配所有)

awk -F: '{print $0, "---"}' /etc/passwd

$n : 代表第n列

案例 1:(以: 为分隔符)
	awk -F: '{print $1}' /etc/passwd

案例 2:(默认空格为分隔符)
	awk '{print $1}' /etc/passwd

NF : 记录当前统计总字段数

案例 1:(以: 为分隔符 统计文件内每行内的行数)
	awk -F: '{print NF}' /etc/passwd
案例 2:(以: 为分隔符 统计文件内每行总字段 并打印每行统计行数)
	awk -F: '{print $NF}' /etc/passwd

NR : 用来记录行号

案例 1:

	awk -F: '{print NR}' /etc/passwd

FS : 指定文本内容分隔符(默认是空格)

案例 1:
	awk 'FS = ":"{print $NF,$ 1}' /etc/passwd
	或
	awk -F: '{print $NF, $ 1}' /etc/passwd
	或
	awk 'BEGIN{FS = ":"}{print $NF, $ 1}' /etc/passwd

解析: BEGIN{FS=":"} 相当于指定以 : 为分隔符 $NF 存储以 : 分隔符的最后一列 $1 存储以 : 分隔符的第一列 print 打印

OFS : 指定打印分隔符(默认空格)

案例 1:(输出的意思 分隔符会打印出来)
	awk -F: 'BEGIN{OFS = " >>> "}{print $NF, $ 1}' /etc/passwd

FS的优先级要高于 -F 解析: BEGIN{OFS=" >>> "} 指定打印分隔符 $NF 存储以 >>> 分隔符的最后一列 $1 存储以 >>> 分隔符的第一列 print 打印

#awk的条件 1,自定义条件

关系运算条件(>、<、>=、<=、==、!=),用来判断左右两侧的关系

包含匹配条件(~、!~、//、!//),用来进行匹配包含关系的

2,预定义条件(保留字)

BEGIN:在awk未读取数据前声明的条件,该条件后的动作仅在程序开始时执行一次,不会重复执行

END:类似于BEGIN,在awk处理完所有数据后声明的条件,在该条件后的程序仅在程序结束前执行一次

注:若有多个 条件{动作} 可以用空格分割

自定义条件

关系运算

关系运算条件(>、<、>=、<=、==、!=),用来判断左右两侧的关系

#提取行数大于1(NR>1)的字段

[root@localhost ~]# awk 'NR > 1{printf $0 "\n "}' cut.txt
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
1	xqian	83	75	93
2	xsun	74	96	63

#提取行数大于2(NR>2)的字段

[root@localhost ~]# awk 'NR > 2{printf $0 "\n "}' cut.txt
0	xzhao	95	59	78
1	xqian	83	75	93
2	xsun	74	96	63
[root@localhost ~]# 

#列出学号为2号($1==2)的各科成绩单

[root@localhost ~]# awk '$1==2{printf $ 0 "\n"}' cut.txt				#第一列等于 2 的行
2	xsun	74	96	63

#列出Linux成绩大于等于80分($3>=80)的成绩单

[root@localhost ~]# awk '$3>=80{printf $ 2 "\t"$3 "\n "}' cut.txt
NAME	LINUX										#由于算法不同所以输出此内容	
xzhao	95
xqian	83

#只取DOCKER成绩在80以上的,姓名和分数

[root@localhost ~]# awk 'NR > 2, $5>80 {print $ 2 "\t"$5}' cut.txt 
xzhao	78
xqian	93
xsun	63
[root@localhost ~]# 

注意:在awk命令中取行(NR)条件写在取列条件前

包含匹配

包含匹配条件(~、!~、//、!//),用来进行匹配包含关系的

~ 表示含有某些字符 格式: ~ “字符串

!~ 表示不含有某些字符 格式: !~ “字符串

// 表示其中含有正则表达式 格式: /某些字符(其中含有正则表达式)/

!~// 表示其中不含有正则表达式 格式: !~/某些字符(其中含有正则表达式)/

#查找第二列含有xsun的数据

[root@localhost ~]# awk '$2~"xsun"{printf $ 0 "\n"}' cut.txt 			#列出第二列中,含有 xsun 的行
2	xsun	74	96	63
或者
[root@localhost ~]# awk '/xsun/{printf $0 "\n "}' cut.txt 		#列出 xsun 所在行数据
2	xsun	74	96	63

#列出包含以.com为结尾的数据

提前向文件内加入新数据(使用sed追加)

[root@localhost ~]# sed -i '5a 3 \txzhang \t37.com\t77 \t80' cut.txt 
[root@localhost ~]# awk '/\.com/{printf $0 "\n "}' cut.txt 
3 	xzhang 	37.com	77 	80

列出磁盘使用率

[root@localhost ~]# df -h |awk '/(sd|sr)[a-z]?[0-9]/{printf $1"\t"$ 5 "\n"}' 
/dev/sda3	22%
/dev/sda1	31%

#引用外部变量时:

awk '/'''$name'''/{printf $0"\n"}' #固定格式

awk '/'$name’/{printf $0"\n"}' #固定格式

使用外部变量:

[root@localhost ~]# name = xsun						#定义外部变量
[root@localhost ~]# declare -p name
declare -- name = "xsun"
[root@localhost ~]# awk '/'$name'/{printf $ 0 "\n"}' cut.txt 	#使用外部变量查找(注意单引号使用方式)
2	xsun	74	96	63
或者
[root@localhost ~]# awk '/'''$name'''/{printf $ 0 "\n"}' cut.txt 			#固定格式
2	xsun	74	96	63

预定义条件(保留字):

BEGIN:

在awk未读取数据前声明的条件,该条件后的动作仅在程序开始时执行一次,不会重复执行

END:

类似于BEGIN,在awk处理完所有数据后声明的条件,在该条件后的程序仅在程序结束前执行一次

#在处理数据前执行BEGIN动作,若有多个 条件{动作} 可以用空格分割

#列出每位学生的成绩平均值并输出标题为“平均成绩为:”保留2位小数

[root@localhost ~]# awk 'BEGIN{print "平均成绩为:"}NR > 2{printf "%s\t%.2f\n", $2,($ 3+$4+$ 5)/3}' cut.txt		#这里需要注意 printf 写在 awk 或其他公式内时 格式 与 数据变量中间需要用“,”逗号隔开
平均成绩为:
xzhao	77.33
xqian	83.67
xsun	77.67
xzhang	64.67
  1. BEGIN{} : 最开始执行

  2. // : 正则

  3. {} : 循环体

  4. END{} : 最后执行

  5. 这里面最少有一个,最多有四个!

动作{printf}

格式:

printf '类型/格式' 字符串

输出类型:

%s 将内容按照字符串类型输出,默认类型 (如:ns:代表输出宽度是n,默认右对齐,-ns左对齐)

%i 将内容按照整数类型输出 (如:ni:代表输出宽度是n,默认右对齐,-ns左对齐)

%f 将内容按浮点数类型输出 (如:%.2f:代表输出小数点数值时保留两位小数点,会进行四舍五入)

输出格式:

\t:字符之间用制表符分割,即tab键\n:字符之间用换行符分割,即enter键 ​ 注:输出格式需要加双引号

printf输出是是没有格式的,会将所有识别到的字符串合并输出,需要手动添加

[root@localhost ~]# printf '%s' $(cat cut.txt)
12345IDNAMELINUXMYSQLDOCKER0xzhao9559781xqian8375932xsun7496633xzhang377780 [root@localhost ~]# 

这也构成了printf的基本输出格式: “printf '类型/格式' 字符串”

\t 字符之间用制表符分割,即tab键 \n 字符之间用换行符分割,即enter键

[root@localhost ~]# printf '%s\t%s\t%s\t%s\t%s\n' $(cat cut.txt)
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
1	xqian	83	75	93
2	xsun	74	96	63
3	xzhang	37	77	80
[root@localhost ~]# 

在原有基础上可以实现对固定格式内的数据进行类型定于:

%f 将内容按浮点数类型输出(默认保留小数点后6位,%.2f 代表输出小数点数值时保留两位小数点,会进行四舍五入)

%i 将内容按照整数类型输出

%s 将内容按照字符串类型输出,默认类型

[root@localhost ~]# printf '%i\t%s\t%i\t%f\t%.2f\n' $(cat cut.txt|grep -v ID)		#对 cut.txt 文件进行格式化输出,并使用 grep 反向提取到,除去 ID 一行的信息
1	2		3	4.000000	5.00
0	xzhao	95	59.000000	78.00
1	xqian	83	75.000000	93.00
2	xsun	74	96.000000	63.00
3	xzhang	37	77.000000	80.00
[root@localhost ~]# 

#指定数字的输出长度及对齐方式

特殊指定条件在输出类型中加入

例如:

%30.2f %-30s %30i

(右对齐并且保留两位小数) (左对齐30个字符) (右对齐30个字符)

MYSQL成绩左对齐 DOCKER成绩右对齐

[root@localhost ~]# printf '%-20s\t%20s\n' $(awk 'NR>1{printf $ 4 "\t"$5 "\n "}' cut.txt) 
MYSQL               	              DOCKER
59                  	                  78
75                  	                  93
96                  	                  63
77                  	                  80

MYSQL/DOCKER成绩都左对齐

[root@localhost ~]# printf '%-20s\t%-20s\n' $(awk 'NR>1{printf $ 4 "\t"$5 "\n "}' cut.txt) 
MYSQL               	DOCKER              
59                  	78                  
75                  	93                  
96                  	63                  
77                  	80   

#awk中默认支持数值运算,并且整数、浮点数运算都支持 #计算每个人的平均值

[root@localhost ~]#  awk 'NR > 2{printf $2"的平均分是\t"($ 3+$4+$ 5)/3 "\n"}' cut.txt
xzhao 的平均分是	77.3333
xqian 的平均分是	83.6667
xsun 的平均分是	77.6667
xzhan 的平均分是	64.6667

在awk中使用printf取值时的两种方法

printf ‘格式’ $(awk公式) #$()的作用时执行命令,以获取所需要的值

例子:printf '%s\t%.2f\n' $(awk 'NR>1{printf $2"的平均分是\t"($3+$4+$5)/3"\n"}' cut.txt)

或者

awk '条件{printf “格式” ,取值,变量等}' #格式与取值之间用 “,”隔开

例子:awk 'BEGIN{print "平均成绩为:"}NR>2{printf "%s\t%.2f\n",$2,($3+$4+$5)/3}' cut.txt

#浮点型截取指定位数

[root@localhost ~]# printf '%-30s\t%.2f\n' $(awk 'NR>2{printf $ 2 "的平均分是\t"($3+$ 4+$5)/3 "\n "}' cut.txt)
xzhao 的平均分是          	77.33
xqian 的平均分是          	83.67
xsun 的平均分是           	77.67
xzhang 的平均分是         	64.67

awk函数

  1. print : 打印

  2. printf : 格式化打印

  3. %s : 字符串

  4. %d : 数字

  5. - : 左对齐

  6. + : 右对齐(默认通常不写入)

  7. 15 : 至少占用15字符

sed命令

功能:

实现非交互式对文件数据进行选取、替换、删除、新增等操作的命令,即不进入文本内对其内容进行修改;主要包括读取、执行和显示三个过程

格式:

sed [选项] '动作' 文件名

选项:

-n 将经过处理后的数据输出到控制台上;不加-n输出全文+指定行 ​ -i 直接修改文件内容;默认下sed不会对文件直接进行修改,而是在内存中修改并将结果效果显示在控制台上

动作: p 打印,输出指定的行 a 追加,在当前行后追加一行或多行 i 插入,在当前行前插入一行或多行 d 删除,删除指定的一行或多行 c 整行替换,用c后面的字符串替换原数据指定行的数据 s 字串替换,用一个字符串替换另外一个字符串,格式“行范围s/旧字串/新字串/g”

注意事项:

1.在不加 -n 选项的时候会将原数据在输出一遍,并在原有基础上最更改。

2.在不加 -i 选项的情况下,不会对文本(原数据)进行修改,只会在终端上演示修改结果。

3.不同动作可以用“;”分号隔开

4.统一动作对不同行执行 行号之间用 “,”逗号隔开

将经过处理后的数据输出到控制台上;不加-n输出全文+指定行

打印指定的第3行

[root@localhost ~]# sed '3p' cut.txt
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
0	xzhao	95	59	78								#此处发现第三行被重复打印两次
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80
[root@localhost ~]# sed -n '3p' cut.txt
0	xzhao	95	59	78

#a在指定行后面追加

-添加行的数据间用空格

[root@localhost ~]# sed '3a 12 xli 80 90 100' cut.txt			#在第三行后追加(3a)数据
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12 xli 80 90 100
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

-添加行的数据间用tab(\t)

[root@localhost ~]# sed '3a 12\txli\t80\t90\t100\t' cut.txt
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12	xli	80	90	100	
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

增加原数据(-i)

[root@localhost ~]# sed -i '3a 12\txli\t80\t90\t100\t' cut.txt
[root@localhost ~]# cat cut.txt 
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12	xli	80	90	100	
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

#d删除原数据(与上述“增加源数据作对别”)

[root@localhost ~]# sed '1,4d' cut.txt
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80
seb命令内的数据替换##

c 整行替换,用c后面的字符串替换原数据指定行的数据 s 字串替换,用一个字符串替换另外一个字符串,格式“行范围s/旧字串/新字串/g”

格式:

sed [选项] $行号s/被更改数据/更改数据/g’ [文件]

注意:

1.被更改数据框内支持正则表达式筛选

2.如果引号内不加“g”则代表只更改本行第一个出现的可被更改数据,如果加“g”则代表更改本行所有可被更改的数据

替换整行内容

[root@localhost ~]# sed '1,4c "查无此人"' cut.txt 	#替换 1-4 行所有内容
"查无此人"
1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

字符串替换:将cut.txt中第5行的'x'换成'xiao'

[root@localhost ~]# sed '5s/x/xiao/g' cut.txt 
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12	xli	80	90	100	
1	xiaoqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

将第五行内数字替换成w

[root@localhost ~]# sed '5s/[0-9]\+/w/g' cut.txt 
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12	xli	80	90	100	
w	xqian	w	w	w	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

加入注释:

sed ‘行号s/^/#/g’ [文件]

[root@localhost ~]# sed '5s/^/#/g' cut.txt 				#注释掉第 5 行
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
12	xli	80	90	100	
#1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

[root@localhost ~]# sed 's/^/#/g' cut.txt 				#注释掉全部
#1	2	3	4	5
#ID	NAME	LINUX	MYSQL	DOCKER
#0	xzhao	95	59	78
#12	xli	80	90	100	
#1	xqian	83	75	93	
#2	xsun	74	96	63
#3 	xzhang 	37	77 	80
[root@localhost ~]# 

[root@localhost ~]# sed '4,5s/^/#/g' cut.txt 				#注释掉 4,5 行
1	2	3	4	5
ID	NAME	LINUX	MYSQL	DOCKER
0	xzhao	95	59	78
#12	xli	80	90	100	
#1	xqian	83	75	93	
2	xsun	74	96	63
3 	xzhang 	37	77 	80

注意:-i 才会修改源文件

#练习:修改SELinux状态位开

修改SELinux状态位开

源代码:

cat -n /etc/selinux/config 
sed -i '7s/disabled/enforcing/' /etc/selinux/config

执行结果:

[root@localhost ~]# cat -n /etc/selinux/config 
     1	
     2	# This file controls the state of SELinux on the system.
     3	# SELINUX = can take one of these three values:
     4	#     enforcing - SELinux security policy is enforced.
     5	#     permissive - SELinux prints warnings instead of enforcing.
     6	#     disabled - No SELinux policy is loaded.
     7	SELINUX = disabled
     8	# SELINUXTYPE = can take one of three values:
     9	#     targeted - Targeted processes are protected,
    10	#     minimum - Modification of targeted policy. Only selected processes are protected. 
    11	#     mls - Multi Level Security protection.
    12	SELINUXTYPE = targeted 
    13	
    14	
[root@localhost ~]# sed -i '7s/disabled/enforcing/' /etc/selinux/config 
[root@localhost ~]# cat -n /etc/selinux/config
     1	
     2	# This file controls the state of SELinux on the system.
     3	# SELINUX = can take one of these three values:
     4	#     enforcing - SELinux security policy is enforced.
     5	#     permissive - SELinux prints warnings instead of enforcing.
     6	#     disabled - No SELinux policy is loaded.
     7	SELINUX = enforcing
     8	# SELINUXTYPE = can take one of three values:
     9	#     targeted - Targeted processes are protected,
    10	#     minimum - Modification of targeted policy. Only selected processes are protected. 
    11	#     mls - Multi Level Security protection.
    12	SELINUXTYPE = targeted 
    13	
    14	
#练习:用sed命令修改网卡配置文件

需求:用sed命令修改网卡配置文件,进行IP地址获取方式的切换

#获取当前使用的网卡名

源代码:

#!/bin/bash
inte =$(ip addr|grep LOWER_UP|grep -v lo|cut -d: -f 2|tr -d " ")
cfg ="/etc/sysconfig/network-scripts/ifcfg-$inte "
sed -i '4s/none/dhcp/g; 5,8d' $cfg

代码解释:

#!/bin/bash
inte =$(ip addr|grep LOWER_UP|grep -v lo|cut -d: -f 2|tr -d " ")			#捕获正在使用的网卡,排除自我环路
cfg ="/etc/sysconfig/network-scripts/ifcfg-$inte "		#给网卡路径赋值
sed -i '4s/none/dhcp/g; 5,8d' $cfg						#修改第 4 行位 dhcp,删除 5 到 8 行内容。

执行

[root@localhost ~]# bash wk.sh 
[root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE = "Ethernet"
PROXY_METHOD = "none"
BROWSER_ONLY = "no"
BOOTPROTO = "dhcp"								#网络状态被更改
DEFROUTE = "yes"
IPV4_FAILURE_FATAL = "no"
IPV6INIT = "yes"
IPV6_AUTOCONF = "yes"
IPV6_DEFROUTE = "yes"
IPV6_FAILURE_FATAL = "no"
IPV6_ADDR_GEN_MODE = "stable-privacy"
NAME = "ens33"
UUID = "018f31bc-98e3-42c1-aca3-fc6081ab5bcc"
DEVICE = "ens33"
ONBOOT = "yes"
[root@localhost ~]# 

注意:大部分代码在使某些脚本生效时采用的方法为加注释“sed n,ms/^/#/g [文件]”,删除为少部分操作,不推荐在对步骤无影响的情况下采用。

sort命令

功能:

对指定文件里的行进行排序,默认使用每行开头第一个字符进行排序(Asckll码排序)

语法:

sort [选项] 文件名

选项:

-f 忽略大小写

-b 忽略每行前的空白部分 ​ -n 以数值型进行排序,默认使用字符串类型排序 ​ -r 反向排序 ​ -u 删除重复行(=下面的uniq) ​ -t 指定分隔符,默认分割符是制表符 ​ -k n 指定使用第几列的内容进行排序,一般和-t结合使用 ​

测试数据:

Cdm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
   daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

忽略大小写排序(-f)

[root@localhost ~]# sort -f sort.txt 
   daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

忽略大小写(-f),并且忽略空白排序(-b)

[root@localhost ~]# sort -bf sort.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
   daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

删除重复行(-u|uniq) # -u 可以删除不相连的重复行。

[root@localhost ~]# sort -u sort.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
   daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

uniq命令

功能:

用来取消重复行,与sort -u 功能是一样的

格式:

uniq [选项] 文件名

选项: -i 忽略大小写 -c 在关键词旁显示该关键词出现的次数(一般针对行)

实验数据:

linux 30
unix 20
windows 50
windows 50
Windows 50
Linux 30
windows 50

去重操作 #注意:当重复行不连续时,uniq是不生效的,需要先排序,再执行

[root@localhost ~]# cat uniq.txt 
linux 30
unix 20
windows 50
windows 50
Windows 50
Linux 30
windows 50
[root@localhost ~]# uniq uniq.txt 
linux 30
unix 20
windows 50									#此行重复被删除
Windows 50
Linux 30
windows 50
[root@localhost ~]# 

#想去除所有重复行,需要先排序

[root@localhost ~]# sort uniq.txt|uniq
linux 30
Linux 30
unix 20
windows 50
Windows 50
[root@localhost ~]# 

#去重并标出重复次数 (-c)

[root@localhost ~]# sort uniq.txt|uniq -c
      1 linux 30
      1 Linux 30
      1 unix 20
      3 windows 50
      1 Windows 50
[root@localhost ~]# 

#忽略大小写去重并标出重复次数 (-ci)

[root@localhost ~]# sort uniq.txt | uniq -ci | sort -rn
      4 windows 50
      2 linux 30
      1 unix 20
[root@localhost ~]# 
练习:查看永不登录的系统用户个数

需求:查看系统中,系统用户的数量并将其全部显示在终端上

源代码:

vim syser.sh
#!/bin/bash


num = $(cat /etc/passwd|cut -d: -f7|sort|uniq -c|sort -r|awk -F/ '/\/sbin\/nologin/{print $ 1}')

echo " 系统用户个数为:$num "
echo "系统用户分别为:"
cat  /etc/passwd|cut -d: -f1,7|sort|awk -F: '/\/sbin\/nologin/{printf "%-30s\t%s\n", $1,$ 2}'	

解析:

#!/bin/bash


num = $(cat /etc/passwd|cut -d: -f7|sort|uniq -c|sort -r|awk -F/ '/\/sbin\/nologin/{print $ 1}')
#查看 shell 类型为/sbin/nolgin 的用户个数

echo " 系统用户个数为:$num "					
#输出个数
echo "系统用户分别为:"

cat /etc/passwd|cut -d: -f1,7|sort|awk -F: '/\/sbin\/nologin/{printf "%-20s\t%s\n", $1,$ 2}'		
#查看 shell 类型为/sbin/nolgin 的用户并筛选用户名

执行结果

[root@localhost ~]# vim syser.sh
[root@localhost ~]# bash syser.sh
系统用户个数为:     40 
系统用户分别为:
abrt                          	/sbin/nologin
adm                           	/sbin/nologin
apache                        	/sbin/nologin
avahi                         	/sbin/nologin
bin                           	/sbin/nologin
chrony                        	/sbin/nologin
colord                        	/sbin/nologin
daemon                        	/sbin/nologin
dbus                          	/sbin/nologin
ftp                           	/sbin/nologin
games                         	/sbin/nologin
gdm                           	/sbin/nologin
geoclue                       	/sbin/nologin
gluster                       	/sbin/nologin
gnome-initial-setup           	/sbin/nologin
libstoragemgmt                	/sbin/nologin
lp                            	/sbin/nologin
mail                          	/sbin/nologin
nfsnobody                     	/sbin/nologin
nobody                        	/sbin/nologin
ntp                           	/sbin/nologin
operator                      	/sbin/nologin
pcp                           	/sbin/nologin
polkitd                       	/sbin/nologin
postfix                       	/sbin/nologin
pulse                         	/sbin/nologin
qemu                          	/sbin/nologin
radvd                         	/sbin/nologin
rpc                           	/sbin/nologin
rpcuser                       	/sbin/nologin
rtkit                         	/sbin/nologin
saned                         	/sbin/nologin
saslauth                      	/sbin/nologin
setroubleshoot                	/sbin/nologin
sshd                          	/sbin/nologin
systemd-network               	/sbin/nologin
tcpdump                       	/sbin/nologin
tss                           	/sbin/nologin
unbound                       	/sbin/nologin
usbmuxd                       	/sbin/nologin

3. 条件判断 [判断条件]

提示:当判断完成后需要在同一层执行多个任务时可以用“()”包裹整体,使多条命令为同一层。

条件判断工具: test [ ] && || if

1. 按照文件类型进行判断

文件类型: d s p l c b

测试选项作用
-b 文件判断该文件是否存在、且为块设备文件(b)
-c 文件判断该文件是否存在、且为字符设备文件(c)
-d 文件判断该文件是否存在、且为目录(d)
-e 文件判断该文件是否存在
-f 文件判断该文件是否存在、且为普通文件(-)
-L 文件判断该文件是否存在、且为符号链接文件(l)
-p 文件判断该文件是否存在、且为管道文件(p)
-s 文件判断该文件是否存在、且内容非空(有内容为真)
-S 文件判断该文件是否存在、且为套接字文件(s)

使用方法:

[ -d 文件 ] 需要执行的命令

同系统命令ll(ls -l)

- 普通文件 d 目录文件 b 块设备文件 c 字符设备文件 l 链接文件 p 管道文件套接字文件 s 套接字文件

练习:判断文件类型

判断输入文件属于什么文件类型(脚本运行)

源代码:

vim file.txt
#!/bin/bash

read -p "请输入你想查看的文件路径:" file
[ -e $file ] || echo "$ file 文件不存在 "
for i in b c d f L p  S
do
if [ -$i $ file ]
then
        if [ $i == b ]
        then
                echo "$file 的文件类型为: 块设备文件 "
        elif [ $i == c ]
        then
                echo "$file 的文件类型为: 字符设备文件 "
        elif [ $i == d ]
        then
                echo "$file 的文件类型为: 目录 "
        elif [ $i == f ]
        then
                echo "$file 的文件类型为: 普通文件 "
        elif [ $i == L  ]
        then
                echo "$file 的文件类型为: 符号链接文件 "
        elif [ $i == p ]
        then
                echo "$file 的文件类型为: 管道文件 "
        elif [ $i == S ]
        then
                echo "$file 的文件类型为: 套接字文件 "
        elif [ ! -e $file ]
        then
                echo "$file 文件不存在 "
        fi

fi
done

解析:

#!/bin/bash

read -p "请输入你想查看的文件路径:" file			#获取数输入文件路径
[ -e $file ] || echo "$ file 文件不存在 "				#检查文件是否存在
for i in b c d f L p  S								#对比文件类型
do
if [ -$i $ file ]
then
        if [ $i == b ]
        then
                echo "$file 的文件类型为: 块设备文件 "
        elif [ $i == c ]
        then
                echo "$file 的文件类型为: 字符设备文件 "
        elif [ $i == d ]
        then
                echo "$file 的文件类型为: 目录 "
        elif [ $i == f ]
        then
                echo "$file 的文件类型为: 普通文件 "
        elif [ $i == L  ]
        then
                echo "$file 的文件类型为: 符号链接文件 "
        elif [ $i == p ]
        then
                echo "$file 的文件类型为: 管道文件 "
        elif [ $i == S ]
        then
                echo "$file 的文件类型为: 套接字文件 "
        elif [ ! -e $file ]
        then
                echo "$file 文件不存在 "
        fi

fi
done

2. 字符串的判断

测试选项作用
-z 字符串判断字符串是否为空(真)
-n 字符串判断字符串是否为非空(非空返回真)
字符串1 == 字符串2判断字符串1是否和字符串2相等(相等返回真)
字符串1 != 字符串2判断字符串1是否和字符串2不相等(不相等返回真)

#字符串是否为空判断

[root@localhost ~]# name = qb
[root@localhost ~]# age = ""
[root@localhost ~]# unset sex
[root@localhost ~]# [ -z "$name " ] && echo yes || echo no			#字符串是否为空
no
[root@localhost ~]# [ -z "$age " ] && echo yes || echo no			#字符串是否为空
yes
[root@localhost ~]# [ -z "$sex " ] && echo yes || echo no 			#字符串是否为空
yes
[root@localhost ~]# [ "$age" == "$ sex" ] && echo yes || echo no		#由于两个字符串都为空,所以调用变量的值相等
yes

3. 按照文件权限进行判断

测试选项作用
-r 文件判断该文件是否存在、且拥有读权限
-w 文件判断该文件是否存在、且拥有写权限
-x 文件判断该文件是否存在、且拥有执行权限
-u 文件判断该文件是否存在、且拥有SUID权限
-g 文件判断该文件是否存在、且拥有SGID权限
-k 文件判断该文件是否存在、且拥有SBit权限

#判断/usr/bin/passwd 是否有suid权限

[root@localhost ~]# [ -u /usr/bin/passwd ] && echo yes || echo no
yes
[root@localhost ~]# 

#判断/tmp/文件是否有sbit权限

[root@localhost ~]# [ -k /tmp ] && echo yes || echo no
yes

4. 两个文件间进行比较

测试选项作用
文件1 -nt 文件2判断文件1的修改时间是否比文件2的新
文件1 -ot 文件2判断文件1的修改时间是否比文件2的旧
文件1 -ef 文件2判断文件1是否和文件2的Inode号一致, 即判两个文件是否为同一个文件(常用于判断硬链接)

#判断文件新旧程度

[root@localhost ~]# [ /root/ying.txt -nt /root/1.txt ] && echo yes || echo no
yes

#判断是否为硬链接

[root@localhost ~]# echo "ying test" > ying.txt
[root@localhost ~]# ln ying.txt /tmp/
[root@localhost ~]# [ /root/ying.txt -ef /tmp/ying.txt ] && echo yes || echo no
yes

5. 两个整数间进行比较

测试选项作用
整数 1 -eq 整数 2判断整数 1 是否和整数 2 相等(equal )
整数 1 -ne 整数 2判断整数 1 是否和整数 2 不相等(not equal)
整数 1 -gt 整数 2判断整数 1 是否大于整数 2(greater than)
整数 1 -lt 整数 2判断整数 1 是否小于整数 2(less than)
整数 1 -ge 整数 2判断整数 1 是否大于等于整数 2(greater than or equal to)
整数 1 -le 整数 2判断整数 1 是否小于等于整数 2(less than or equal to)

6. 多重条件判断

测试选项作用
判断 1 -a 判断 2逻辑与,判断 1 和判断 2 都成立,最终结果才为真
判断 1 -o 判断 2逻辑非,判断 1 和判断 2 有一个成立,最终结果就为真
!判断逻辑非,对判断结果取反,! 和 判断条件之间有个空格

注意:

在两个条件需要 同时触发 时可以用到 [ 条件 1 -a 条件 2 ]

在两个条件 只需要触发一个 的时候 [ 条件 1 -o 条件 2 ]

#逻辑与
a=100
[ -n "$a" -a "$a" -gt 150 ] && echo yes || echo no

#逻辑或
b=150
[ "$b" -gt 150 -o "$b" -eq 150 ] && echo yes || echo no

#逻辑非
c=200
[ ! -n "$c" ] && echo yes || echo no

4. 流程控制

编程中流程控制分为三类:顺序结构、分支结构、循环结构

流程控制:顺序、分支(if、case)、循环(for、while、until)

分支结构

1. if 条件判断

if 语句: 单分支、双分支、if 嵌套 if 多分支

单分支条件语句比较简单,只需一个判断条件,符合则执行,不符合则直接退出

判断条件符合的情况:

  • true

  • test 或中括号条件判断式的结果为 0 的

  • 命令执行的结果为 0 的

格式一:

if [ 条件判断式 ]; then

程序

fi

格式二:

if [ 条件判断式 ]

then

程序

elif [ 条件判断 ]

then

程序

else

fi

练习:监控根分区的使用率

#需求:监控根分区的使用率,根分区使用率超过 60%将报警。

源代码:

vim jiankong.sh
#!/bin/bash
df=$(df -h|awk '/\/$/{print $5 }'|tr -d "%")
if [ $df -gt 60 ]
then
        echo -e "根分区使用量为: \e[31;5m $df %\e[0m超过规定范围(60%),请及时处理"
else
        echo "当前跟分区使用量为: $df %"

解析:

#!/bin/bash
df=$(df -h|awk '/\/$/{print $5 }'|tr -d "%")		#获取根分区使用量数值,并赋值给 df 变量
if [ $df -gt 60 ]									#df变量与60作比较
then
        echo -e "根分区使用量为: \e[31;5m $df %\e[0m超过规定范围	(60%),请及时处理"							#判断正确说明根分区使用量>60,输出此命令。
else
        echo "当前跟分区使用量为: $df %"			#错误说明使用量<60,输出此命令。

执行:

[root@localhost ~]# bash jiankong.sh
当前跟分区使用量为: 22 %
#将数值调成20 "[ $df -gt 20 ]"看超出规定范围输出结果输出结果
[root@localhost ~]# bash jiankong.sh
根分区使用量为:  22 %超过规定范围(60%),请及时处理
练习:监控内存,cpu 使用量

需求:监控并汇报内存和 CPU 使用量,并对其数值设限(cpu 90,men 70)

源代码:

vim cpu.sh
#!/bin/bash
free=$(free|awk '/Mem/{printf "%.f\n",$3/$2*100}')
cpu=$(top -n 1|awk '/%Cpu/{printf "%.f\n",$2+$4}')
if [ $free -gt 70 ]
then
        echo -e "当前内存使用率已经达到\e[31m$free %\e[0m,(常规使用率为:70%)"
else
        echo "当前内存使用率为$free%"
fi
if [ $cpu -gt 90 ]
then
        echo -e "当前cpu使用率已经达到\e[31m$cpu %\e[0m,(常规使用率为:90%)"
else
        echo "当前cpu使用率为$cpu%"
fi             

解析:

#!/bin/bash
free=$(free|awk '/Mem/{printf "%.f\n",$3/$2*100}')						#提取Mem使用率整数数值
cpu=$(top -n 1|awk '/%Cpu/{printf "%.f\n",$2+$4}')						#提取cpu使用率整数数值
if [ $free -gt 70 ]															#判断Mem使用率整数数值是否>70
then
        echo -e "当前内存使用率已经达到\e[31m$free %\e[0m,(常规使用率为:70%)"
else
        echo "当前内存使用率为$free%"
fi
if [ $cpu -gt 90 ]															#判断cpu#判断Mem使用率整数数值是否>90
then
        echo -e "当前cpu使用率已经达到\e[31m$cpu %\e[0m,(常规使用率为:90%)"
else
        echo "当前cpu使用率为$cpu%"
fi  

执行结果:

[root@localhost ~]# bash cpu.sh
当前内存使用率为48%
当前cpu使用率为12%

2.多分支 case 条件语句

语法:

case $变量名 in

“值 1”)

如果$变量等于值 1,则执行程序 1

;;

“值 2”)

如果$变量等于值 2,则执行程序 2

;;

....省略...

*

如果$变量的值不是以上值,则执行此程序

;;

esac

#只能进行一种条件的判断,会列出所有可能的值; #case 列出的值,可以是一个数字、一个字符串,或是通配符([ ]、*、?)、正则中的“|”

练习:用户输出 yes 或者 no

需求:无论用户输入 y, Y, n, N, yes, Yes, No, NO 等一系列字符,均向用户传达肯定,以及否定的回复,y:肯定,n:否定

源代码

vim yn.sh
#!/bin/bash
read -p "请输入您的选择:" choose
case "$choose" in
[yY]|[yY][eE][sS])
        echo "正确"
        ;;
[Nn]|[Nn][Oo])
        echo "错误"
        ;;
esac

执行:

[root@localhost ~]# bash yn.sh
请输入您的选择:y
正确
[root@localhost ~]# bash yn.sh
请输入您的选择:Y
正确
[root@localhost ~]# bash yn.sh
请输入您的选择:yEs
正确
[root@localhost ~]# bash yn.sh
请输入您的选择:No
错误
练习:等级判断

需求:判断分数,并划分等级:

100 - 90 A

89 - 80 B

79 - 70 C

70 以下 D

注意:不接受 100 以上或字符串 等特殊字符。

源代码:

vim dengji.sh
#!/bin/bash
read -p "请输入您的分数:" num
case "$num" in
100|9[0-9])
        echo "评级为A"
        ;;
8[0-9])
        echo "评级为B"
        ;;
7[0-9])
        echo "评级为C"
        ;;
[0-9]|[1-6][0-9])
        echo "评级为D"
        ;;
*)
        echo "请输入一个0-100以内的正整数"
        ;;
esac

解析:

#!/bin/bash
read -p "请输入您的分数:" num
case "$num" in
100|9[0-9])
        echo "评级为A"
        ;;
8[0-9])
        echo "评级为B"
        ;;
7[0-9])
        echo "评级为C"
        ;;
[0-9]|[1-6][0-9])
        echo "评级为D"
        ;;
*)
        echo "请输入一个0-100以内的正整数"
        ;;
esac

执行:

[root@localhost ~]# bash dengji.sh
请输入您的分数:70
评级为C
[root@localhost ~]# bash dengji.sh
请输入您的分数:89
评级为B
[root@localhost ~]# bash dengji.sh
请输入您的分数:1690
请输入一个0-100以内的正整数
[root@localhost ~]# bash dengji.sh
请输入您的分数:-92
请输入一个0-100以内的正整数

循环结构

有限次循环: for

无限次数循环: while until

1. for 循环

语法一:

for 变量 in 值 1 值 2 值 3 ...

do

执行程序

done

语法二:

for ((初始值;循环控制条件;变量变化))

do

执行程序

done

注:初始值:在循环开始时,需要给某个变量赋予初始值,如 i = 1;循环控制条件:用于指定变量循环的次数,如 i <= 100,则只要 i 的值小于等于 100,循环就会继续;变量变化:每次循环之后,变量该如何变化,如 i = i+1。代表每次循环之后,变量 i 的值都加 1。

#!/bin/bash
for ((i=0;i<=9;i++))				#i为0 每循环一次 i加一 	i大于9时停止	
do
        echo "$RANDOM"
done       

数字循环格式区别:

for i in {1..10..2} 此类表达式中: 1 为起始循环数值,10 为终止循环数值, 2 为步长

for i in $(seq 1 2 10) 此类表达式中:1 为起始循环数值,2 为步长,10 为终止循环数值

for ((i = 1; i <= 10; i+= 2)) 此类表达式中:1 为起始循环数值,10 为终止循环数值, 2 为步长

计算 0-100 中的偶数和

方法一

源代码:

#!/bin/bash
he=0
for i in {2..100..2}
do
        he=$(($he+$i))
done
echo "$he"

执行

[root@localhost ~]# bash fo1.sh
2550

方法二

源代码:

vim fo2.sh
#!/bin/bash
declare -i he=0
for ((i=0;i<=100;i+=2))
do
        he+=$i
done
echo "$he"

执行

[root@localhost ~]# bash fo2.sh
2550

方法三

源代码:

#!/bin/bash

declare -i he=0
for i in $(seq 0 2 100)
do
        he+=$i
done
echo "$he"

执行

[root@localhost ~]# bash fo3.sh
2550

2. while

只要条件判断式成立,循环就会一直继续,直到条件不成立,循环才停止

语法:

while [ 条件判断式 ]

do

程序

done

计算 1+..100 的值

vim jiaf.sh
#!/bin/bash
declare -i he=0
declare -i i=0
while [ $i -le 100 ]
do
        let he+=$i
        let i+=1
done
echo "$he"

执行

[root@localhost ~]# bash jiaf.sh
5050 

while true #无线死循环

练习:监控 httpd 是否开启

需求:实时监控 httpd 开启状态,每十秒提示一次开启状态,要求后台执行,当 httpd 关闭时立即提示红色警告,并提问是否重新开启。循环结束直至 httpd 程序再次开启。

源代码:

vim httpd.sh
#!/bin/bash
while true
do
        httpd=$(ss -anpt|grep httpd)

        if [ -n "$httpd" ]
        then
                echo "httpd程序已开启"
                sleep 10
        else
                echo -e "\e[31;5mhttpd程序未开启\e[0m"
read -p "您是否开启httpd服务:" choose
case "$choose" in
[yY]|[yY][eE][sS])
        systemctl restart httpd
        ;;
[Nn]|[Nn][Oo])
        echo "httpd服务已关闭"
        exit
        ;;
esac
fi
done

执行:

[root@localhost ~]# bash httpd.sh
httpd程序已开启
#此时通过另一个终端关闭httpd服务
httpd程序未开启
您是否开启httpd服务:YEs 				#输入yes
httpd程序已开启

3. until 循环

until 循环和 while 循环相反,只要条件 判断式不成立则一直循环;直到条件 成立则结束 循环

格式:

until [ 条件判断式 ]

do

程序

done

#!/bin/bash
i=1
sum=0
until [ $i -gt 100 ]
do
        let sum+=$i
        let i++
done
echo "the sum is:$sum"

特殊流程控制

continue 直接跳转至当前结构结束之前

break 直接跳转至当前结构结束之后

exit 直接结束当前脚本,并退出,并输出结束值以供 echo $?搜索

for i in {2..100..2}
do
        he=$(($he+$i))
  #<============================ continue 作用位置   
done
  #<=============================break 作用位置
echo "$he"
	#<========================exit 作用位置

exit

系统中的 exit 是退出当前登录,但在 shell 中是退出脚本,回到 Linux 命令行

格式:

exit [ 值 ]

exit 退出时如果定义好了返回值,那么我们可以通过“$?”来查看。如果 exit 命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的

返回值。可以通过$?查询,来查看返回值, 范围是 0-255。如果 exit 之后没有定义返回值,脚本执行之后的返回值是执行 exit 之前,最后执行一条命令的返回值

break

#break 概述:跳出当前整个循环或结束当前循环,在 for、while 等循环语句中,用于跳出当前所在的循环体,执行循环体之后的语句

#后面如果什么也不加,表示跳出当前循环等价于 break 1,也可以在后面加数字, 假设 break 3 表示跳出第三层循环

continue 语句

continue 概述:忽略本次循环剩余的代码,直接进行下一次循环;在 for、while 等循环语句中,用于跳出当次所在的循环,不终止循环,继续执行剩余循环;

#如果后面加的数字是 1,表示忽略本次条件循环,如果是 2 的话,忽略下来 2 次条件的循环

练习:猜数字

需求: 1.随机生成一个 100 以内的正整数,猜中显示”猜中了“,猜大显示“大了”,猜小显示”小了“

2.猜中后显示猜了几次猜中

3.猜中后显示是否继续游戏,如果继续则重新开始游戏。

源代码:

vim caishuzi.sh
#!/bin/bash

caishuzi(){
num=$(($RANDOM%100+1))
declare -i g=1
while true
do
        read -p "请输入一个1-100的数字:" s1
        if [ $s1 -gt $num ]
        then
                echo "大了"
        elif [ $s1 -lt $num ]
        then
                echo "小了"
        elif [ $s1 -eq $num ]
        then
                echo "猜对啦!"
                break
        fi
let g+=1
done
echo "您一共猜了$g次"
}

declare -i li=0
while true
do
        if [ $li -eq 0 ]
        then
                caishuzi
                read -p "是否继续游戏:" choose
                case "$choose" in
                [yY]|[yY][eE][sS])
                        declare -i li=0
                        ;;
                [Nn]|[Nn][Oo])
                        let li+=1
                        ;;
                esac

        else
                exit
        fi
done

解析:

#!/bin/bash

#思路:将猜数字游戏定义为函数caishuzi,后通过 while true 对一个变量赋值实现是否继续游戏
#具体解析如下
caishuzi(){
						#<==================================定义函数
num=$(($RANDOM%100+1))									#随机一个100 以内的数字
declare -i g=1												#定义计数变量
while true													#无限循环结构
do	
        read -p "请输入一个1-100的数字:" s1					#用户猜测数字s1
        if [ $s1 -gt $num ]								#如果 s1>随机数字 
        then
                echo "大了"
        elif [ $s1 -lt $num ]							#如果 s1<随机数字 
        then
                echo "小了"
        elif [ $s1 -eq $num ]							##如果 s1=随机数字 
        then
                echo "猜对啦!"
                break
        fi
let g+=1														#每猜一次计数变量自增1
done
echo "您一共猜了$g次"												#输出自增变量次数
}									#<==================函数定义完毕
	


declare -i li=0										#是否继续参考变量

while true											#无限循环结构
do
        if [ $li -eq 0 ]						#如果参考变量符合条件则执行caishuzi函数
        then
                caishuzi
                read -p "是否继续游戏:" choose		#执行过后判断是否继续
                case "$choose" in						#case判断结构
                [yY]|[yY][eE][sS])
                        declare -i li=0				#是为继续游戏,参考变量赋值不变,继续重复while true循环
                        ;;
                [Nn]|[Nn][Oo])							#否为停止游戏,参考变量赋值改变,则退出此脚本。
                        let li+=1
                        ;;
                esac

        else
                exit
        fi
done

执行结果:

[root@localhost ~]# bash caishuzi.sh
请输入一个1-100的数字:50
小了
请输入一个1-100的数字:70
小了
请输入一个1-100的数字:80
大了
请输入一个1-100的数字:78
大了
请输入一个1-100的数字:77
大了
请输入一个1-100的数字:74
大了
请输入一个1-100的数字:71
小了
请输入一个1-100的数字:73
猜对啦!
您一共猜了8次
是否继续游戏:yes
请输入一个1-100的数字:72
大了
请输入一个1-100的数字:52
大了
请输入一个1-100的数字:42
大了
请输入一个1-100的数字:31
大了
请输入一个1-100的数字:21
大了
请输入一个1-100的数字:2
小了
请输入一个1-100的数字:14
大了
请输入一个1-100的数字:1
小了
请输入一个1-100的数字:9
大了
请输入一个1-100的数字:8
大了
请输入一个1-100的数字:8 8
大了
请输入一个1-100的数字:8
大了
请输入一个1-100的数字:6
大了
请输入一个1-100的数字:4
大了
请输入一个1-100的数字:3
猜对啦!
您一共猜了15次
是否继续游戏:no
[root@localhost ~]# 

5. 函数

在编写脚本时,有些语句会被重复使用多次。把这些可能重复使用的代码写成函数,这样我们通过函数名称可以更高效的重复利用他们。如果想让自己写的脚本代码可以为别人所使用,同样需要函数功能。

格式:

function 函数名() {

程序

}

用法:

若需要在当前脚本下调用其他文本中的函数

需要先 . 或 source [函数文件] 引入函数所在的脚本

即可调用脚本。

举例:

#!/bin/bash

#思路:将猜数字游戏定义为函数caishuzi,后通过 while true 对一个变量赋值实现是否继续游戏
#具体解析如下
caishuzi(){
						#<==================================定义函数
num=$(($RANDOM%100+1))									#随机一个100 以内的数字
declare -i g=1												#定义计数变量
while true													#无限循环结构
do	
        read -p "请输入一个1-100的数字:" s1					#用户猜测数字s1
        if [ $s1 -gt $num ]								#如果 s1>随机数字 
        then
                echo "大了"
        elif [ $s1 -lt $num ]							#如果 s1<随机数字 
        then
                echo "小了"
        elif [ $s1 -eq $num ]							##如果 s1=随机数字 
        then
                echo "猜对啦!"
                break
        fi
let g+=1														#每猜一次计数变量自增1
done
echo "您一共猜了$g次"												#输出自增变量次数
}									#<==================函数定义完毕
	


declare -i li=0										#是否继续参考变量

while true											#无限循环结构
do
        if [ $li -eq 0 ]						#如果参考变量符合条件则执行caishuzi函数
        then
                caishuzi
                read -p "是否继续游戏:" choose		#执行过后判断是否继续
                case "$choose" in						#case判断结构
                [yY]|[yY][eE][sS])
                        declare -i li=0				#是为继续游戏,参考变量赋值不变,继续重复while true循环
                        ;;
                [Nn]|[Nn][Oo])							#否为停止游戏,参考变量赋值改变,则退出此脚本。
                        let li+=1
                        ;;
                esac

        else
                exit
        fi
done

nmap 端口检测工具

yum -y install nmap

用法:

检测某台主机的端口: nmap -sT 192.168.59.130

检测某个网段的端口: nmap -sT 192.168.59.0/24

检测主机端口

[root@localhost ~]# nmap -sT 192.168.59.130

Starting Nmap 6.40 ( http://nmap.org ) at 2024-11-23 09:15 CST
Nmap scan report for 192.168.59.130
Host is up (0.00057s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
111/tcp  open  rpcbind
514/tcp  open  shell
6000/tcp open  X11

Nmap done: 1 IP address (1 host up) scanned in 4.09 seconds

检测网段端口:

 [root@localhost ~]# nmap -sT 192.168.59.0/24
 ​
 Starting Nmap 6.40 ( http://nmap.org ) at 2024-11-23 09:26 CST
 Nmap scan report for 192.168.59.1
 Host is up (0.00014s latency).
 All 1000 scanned ports on 192.168.59.1 are filtered
 MAC Address: 00:50:56:C0:00:08 (VMware)
 ​
 Nmap scan report for 192.168.59.2
 Host is up (0.0015s latency).
 Not shown: 999 closed ports
 PORT   STATE SERVICE
 53/tcp open  domain
 MAC Address: 00:50:56:F4:E1:D7 (VMware)
 ​
 Nmap scan report for 192.168.59.254
 Host is up (0.000055s latency).
 All 1000 scanned ports on 192.168.59.254 are filtered
 MAC Address: 00:50:56:FB:72:1C (VMware)
 ​
 Nmap scan report for 192.168.59.130
 Host is up (0.00029s latency).
 Not shown: 996 closed ports
 PORT     STATE SERVICE
 22/tcp   open  ssh
 111/tcp  open  rpcbind
 514/tcp  open  shell
 6000/tcp open  X11
 ​
 Nmap done: 256 IP addresses (4 hosts up) scanned in 8.42 seconds

如果主机没开放

 [root@localhost ~]# nmap -sT 192.168.59.4
 ​
 Starting Nmap 6.40 ( http://nmap.org ) at 2024-11-23 09:29 CST
 Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
 Nmap done: 1 IP address (0 hosts up) scanned in 0.42 seconds
 [root@localhost ~]# 

curl模拟浏览器访问

格式:

curl 域名/IP地址

 ​

tr 替换命令

删除空格:

 tr -d ' '
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值