Shell 编程学习笔记
Shell 编程
1.简单脚本 “hello world 输出”
-
写入脚本
cd /root #切换至root目录下 vim hello.sh #新建一个名为“hello”的shell文件,并进入编写
编写内容如下:
#!/bin/bash #声明!! 此程序运用/bin/bash为编译 echo "hello word" #使用echo输出: hello world :wq #末行模式 保存并退出
-
执行命令
方法一:
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 删除永久设置的别名
-
在设置的配置文件中删除后
-
使用 source 或 . +配置文件 #重新加载配置文件
[root@localhost ~]#. ./.bashrc
或
root@localhost ~]# source ./.bashrc
-
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/stdin | 0 | 标准输入 |
显示器 | /dev/stdout | 1 | 标准正确输出 |
显示器 | /dev/stderr | 2 | 标准错误输出 |
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位置参数变量
位置参数变量:根据调用脚本时传入参数值的位置,进行变量赋值和取值
位置参数变量 | 作用 |
---|---|
$n | n为数字,$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语法,实现该效果。
需求如下:
-
输出下图的样式,作为工具的交互界面。
-
当执行该脚本后,检测当前系统是否安装了tree命令:工具,若安装,则输出tree工具已安装;若未安装,则输出tree工具未安装。
-
最后的检测结束行,要闪烁,提示用户检测已经结束。 ===========软件测试工具========= ||*声明:该工具检测系统是否缺少 || ||运维工具命令,并帮助暗示装饰用.*|| ===========检测中......=========== 请输入你想检查的软件: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生命周期
grep,sed和awk都是读一行处理一行,直到处理完成
接收一行作为输入
把刚刚读入进来得到文本进行分解
使用处理规则处理文本
输入一行,赋值给$0,直至处理完成
把处理完成之后的所有数据交给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
BEGIN{} : 最开始执行
// : 正则
{} : 循环体
END{} : 最后执行
这里面最少有一个,最多有四个!
动作{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函数
print : 打印
printf : 格式化打印
%s : 字符串
%d : 数字
- : 左对齐
+ : 右对齐(默认通常不写入)
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 ' '