个人网站备案 导航,国际重大新闻,南阳市建网站公,建站平台选择建议本章主要介绍如何使用bash
了解通配符了解变量了解返回值和数值运算判断语句
grep的用法是“grep 关键字 file”#xff0c;意思是从file中过滤出含有关键字的行
例如#xff0c;grep root /var/log/messages#xff0c;意思是从/var/log/messages 中过滤出含有root 的行…本章主要介绍如何使用bash
了解通配符了解变量了解返回值和数值运算判断语句
grep的用法是“grep 关键字 file”意思是从file中过滤出含有关键字的行
例如grep root /var/log/messages意思是从/var/log/messages 中过滤出含有root 的行。这里很明确的是过滤含有“root”的行
不管是通配符还是正则表达式都是为了模糊匹配为了匹配某一类内容而不是具体的某个关键字。通配符一般用在shell语言中正则表达式一般用在其他语言中
不管是通配符还是正则表达式主要是理解它们的元字符,然后用元字符来组合成我们想要的那一类字符,本章主要讲解通配符的使用
1.1 通配符
通配符一般用在shell语言中,通配符中常见的元字符如下
1[]匹配一个字符,匹配的是出现在中括号中的字符
2[abc]匹配一个字符且只能是a或b或c
3[a-z]“-”有特殊意义表示“到”的意思这里表示a~z即匹配任一字母
4[0-9]表示匹配任一数字
如果想去除含有特殊意义的字符前面加“\”表示转义即去除此字符的特殊意义
5[a\-z]这里的“-”就没有“到”的意思了匹配的是“a”或“-”或“z”这三个中的一个
如果想表示“除了”的意思则在第一个中括号后面加“!”或“^”
6[!a-z]、[^a-z]表示除字母外的其他字符
7?表示一个任意字符这里强调是一个不是0个也不是多个但不能匹配表示隐藏文件的点
8*表示任意多个任意字符可以是0个也可以是1个或多个但不能匹配表示隐藏文件的点 练习先创建目录vv并在目录中创建如下几个测试文件
[rootredhat8 ~]# mkdir vv
[rootredhat8 ~]# cd vv
[rootredhat8 vv]# touch 1_aa aa11 Aa11 _aaa aa.txt f1aa u_12
[rootredhat8 vv]#
找出首字符是字母、第二个字符是数字的文件
[rootredhat8 vv]# ls [a-z][0-9]*
f1aa
[rootredhat8 vv]#
找出首字符是字母、第二个字符不是数字的文件
[rootredhat8 vv]# ls [a-z][^0-9]*
aa11 Aa11 aa.txt u_12
[rootredhat8 vv]#
找出首字符不是字母、第二个字符不是数字的文件
[rootredhat8 vv]# ls [^a-z][^0-9]*
1_aa _aaa
[rootredhat8 vv]#
可以看到找出来的文件完全符合我们的需求。下面找出首字符是大写字母、第二个字符是非数字的文件
[rootredhat8 vv]# ls [A-Z][!0-9]*
Aa11 u_12
[rootredhat8 vv]#
可以看到首字符是大写字母的文件列出来了首字符是小写字母的文件有的列出来了, 有的没有列出来所以[a-z]或[A-Z]有时并不精确。如果要更精确可以用如下元字符
1[[:upper:]]纯大写
2[[:lower:]]小写
3[[:alpha:]]字母
4[[:alnum:]字母和数字
5[[:digit:]]数字
列出首字符是小写字母、第二个字符是数字的文件
[rootredhat8 vv]# ls [[:lower:]][0-9]*
f1aa
[rootredhat8 vv]#
列出首字符是大写字母、第二个字符是数字或字母的文件
[rootredhat8 vv]# ls [[:upper:]][[:alnum:]]*
Aa11
[rootredhat8 vv]#
如果想在yum 源中列出所有以 vsftpd开头的包
[rootredhat8 vv]# yum list vsftpd*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查1 day, 19:22:27 前执行于 2023年12月06日 星期三 15时34分15秒。
可安装的软件包
vsftpd.x86_64 3.0.3-34.el8 aa
[rootredhat8 vv]#
在当前目录中创建一个文件vsftpdxxx
[rootredhat8 vv]# touch vsftpdxxx
[rootredhat8 vv]#
然后再执行yum list vsftpd*命令
[rootredhat8 vv]# yum list vsftpd*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查1 day, 19:23:15 前执行于 2023年12月06日 星期三 15时34分15秒。
错误没有匹配的软件包可以列出
[rootredhat8 vv]#
此处显示没有匹配的包为什么呢?因为yum是 bash的一个子进程vsftpd在 bash中首先被解析成了vsftpdxxx然后再经过yum。所以本质上执行的是yum list vsftpdxx命令而yum源中是没有vsftpdxxx 这个包的所以报错
为了防止 bash 对这里的*进行解析可以加上转义符“\”所以下面的命令是正确的
[rootredhat8 vv]# yum list vsftpd\*
正在更新 Subscription Management 软件仓库。
无法读取客户身份本系统尚未在权利服务器中注册。可使用 subscription-manager 进行注册。上次元数据过期检查1 day, 19:24:25 前执行于 2023年12月06日 星期三 15时34分15秒。
可安装的软件包
vsftpd.x86_64 3.0.3-34.el8 aa
[rootredhat8 vv]#
1.2 变量
所谓变量指的是可变的值并非具体的值。例如我自己嘴中发出的“我”指的是我自己张三嘴中发出的“我”指的是张三那么这个“我”就是一个变量
变量可以分为本地变量、环境变量、位置变量和预定义变量
1.2.1 本地变量
定义本地变量的格式如下
变量名值
定义变量有以下几点需要注意
1变量名可以包含_、数字、大小写字母但不能以数字开头
2“”两边不要有空格
3“值”如果含有空格要使用单引号或双引号引起来
4定义变量时变量名前是不需要加$的引用变量时需要在变量名前加$
本章实验都放在~/yy中练习
[rootredhat8 ~]# mkdir yy
[rootredhat8 ~]# cd yy
[rootredhat8 yy]#
下面开始练习定义变量
[rootredhat8 yy]# 1aa123
bash: 1aa123: 未找到命令...
文件搜索失败: /mnt/AppStream was not found
[rootredhat8 yy]#
这里定义变量不正确因为变量名不能以数字开头
[rootredhat8 yy]# aa-1123
bash: aa-1123: 未找到命令...
文件搜索失败: /mnt/AppStream was not found
[rootredhat8 yy]#
这里定义变量不正确因为变量名只能是字母、数字、下划线的组合
[rootredhat8 yy]# aa 123
bash: aa: 未找到命令...
文件搜索失败: /mnt/AppStream was not found
[rootredhat8 yy]#
这里的错误是因为等号左边有空格
[rootredhat8 yy]# aa1 2
bash: 2: 未找到命令...
[rootredhat8 yy]#
这里的错误是因为“值”部分有空格没有用引号引起来
[rootredhat8 yy]# aa123
[rootredhat8 yy]#
这里正确地定义了一个变量
在使用本地变量时,变量名前需要加$
[rootredhat8 yy]# echo $aa
123
[rootredhat8 yy]#
本地变量的特点是只能影响当前shell不能影响子shell
[rootredhat8 yy]# echo $aa
123
[rootredhat8 yy]# echo $$
1841
[rootredhat8 yy]#
当前shell的PID是1841。下面打开一个子shell
[rootredhat8 yy]# bash
[rootredhat8 yy]# echo $$
2183
[rootredhat8 yy]#
这个子shell的PID是2183
[rootredhat8 yy]# echo $aa[rootredhat8 yy]#
可以看到没有aa变量
[rootredhat8 yy]# exit
exit
[rootredhat8 yy]# echo $$
1841
[rootredhat8 yy]# echo $aa
123
[rootredhat8 yy]#
定义变量除刚才显式的定义外还可以使用如下两种方法
1把一个命令的结果赋值给一个变量这个变量要使用$()括起来或者用反引号“引起来。这里是反引号与波浪号是同--个键,不是单引号
例如定义一个名称是ip的变量对应的值是ens160的IP
[rootredhat8 yy]# ip$(ifconfig ens160 | awk /inet /{print $2})
[rootredhat8 yy]# echo $ip
192.168.161.16
[rootredhat8 yy]#
2通过read命令来获取变量
read的用法如下
read ‐p 提示信息 变量
当遇到read命令时系统会等待用户输入用户所输入的值会赋值给read后面的变量
[rootredhat8 yy]# read -p 请输入你的名字 aa
请输入你的名字jin
[rootredhat8 yy]# echo $aa
jin
[rootredhat8 yy]#
当执行read这条命令时系统会提示用户输人一些内容所输入的内容会赋值给aa变 量。这里我们输入的是 jin所以打印aa变量时看到的值是jin
这样的用法比较适合写需要和用户交互的脚本
1.2.2 环境变量
定义环境变量的注意点和本地变量是一样的。在定义环境变量时前面加上export 即可
[rootredhat8 yy]# export bb123
[rootredhat8 yy]#
或者先定义为本地变量然后再通过export转变为环境变量
[rootredhat8 yy]# bb123
[rootredhat8 yy]# export bb
[rootredhat8 yy]#
要想查看所有的环境变量可以执行env命令
环境变量的特点是可以影响shell这里强调的是子shell不能影响父shell
[rootredhat8 yy]# echo $$
1841
[rootredhat8 yy]# echo $bb
123
[rootredhat8 yy]
当前shell的PID是1841里面有一个环境变量bb
[rootredhat8 yy]# echo $$
2330
[rootredhat8 yy]# echo $bb
123
[rootredhat8 yy]#
打开一个子shellPID为2330里面可以看到bb变量的值说明环境变量已经影响到 子shell 了
[rootredhat8 yy]# export bb456
[rootredhat8 yy]# exit
exit
[rootredhat8 yy]#
在子 shell中重新给bb赋值为456然后退回到父shell
[rootredhat8 yy]# echo $$
1841
[rootredhat8 yy]# echo $bb
123
[rootredhat8 yy]#
可以看到在父shell 中bb的值仍然是123说明在子shell 中定义的变量不会影响到父shell
系统中默认已经存在很多个变量
1UID表示当前用户的uid
2USER表示当前用户名
3HOME表示当前用户的家目录
分别显示这些变量的值
[rootredhat8 yy]# echo $UID
0
[rootredhat8 yy]# echo $USER
root
[rootredhat8 yy]# echo $HOME
/root
[rootredhat8 yy]#
有一个很重要的环境变量PATH当我们执行命令时一定要指定这个命令的路径如果没有写路径则会到PATH变量所指定的路径中进行查询。先查看当前用户的PATH变量
[rootredhat8 yy]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[rootredhat8 yy]#
PATH变量由多个目录组成每个目录之间用冒号“:”分隔我们把写好的脚本放在PATH变量指定的目录中之后运行此脚本时就不需要指定路径了
以上定义的环境变量也只是在当前终端中生效关闭终端之后这个变量也就消失了。如果想让定义的变量永久生效可以写人家目录的.bash_profile中。因为打开终端时首先会运行家目录下的一个隐藏文件.bash_profile
1.3 返回值
执行某命令之后结果不是正确的就是错误的。命令正确执行了返回值为0如果没有正确执行则返回值为非零。返回值为非零不一定是语法错误执行结果如果有“否定”的意思,返回值也为非零。例如, ping 192.168.161.12语法没有错误但是没有ping通,返回值 也为非零
返回值记录在$?中且$?只记录刚刚执行过命令的返回值。因为$?的值会被新执行命令的返回值覆盖
练习先执行一个xxx命令
[rootredhat8 yy]# xxx
bash: xxx: 未找到命令...
文件搜索失败: /mnt/AppStream was not found
[rootredhat8 yy]# echo $?
127
[rootredhat8 yy]# echo $?
0
[rootredhat8 yy]#
先执行一个xxx命令这个命令是错误的命令$?记录的是刚刚执行过xxx命令的返回值。所以查看$?的值是127是一个非零的值。再次查看$?的值时却变成了0因为这个$?记录的不再是xxx命令的返回值而是它前面执行过的echo $?命令的返回值
逻辑上“否定”的意思也是可以体现出来的
[rootredhat8 yy]# grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
[rootredhat8 yy]# echo $?
0
[rootredhat8 yy]#
这里在/etc/passwd过滤行开头为root的行结果找到了所以返回值为0
[rootredhat8 yy]# grep ^rootxxx /etc/passwd
[rootredhat8 yy]# echo $?
1
[rootredhat8 yy]#
这里在/etc/passwd过滤行开头为rootxxx的行结果没有找到即使语法没有错误但是逻辑上有“否定”的意思,所以返回值为非零
1.4 数值运算
在写脚本时,有时我们经常要做一些数学运算。数学运算的符号如下
1表示加
2-表示减
3*表示乘
4/表示除
5**表示次方
进行数学运算的表达式有$(())、$[]、let等
[rootredhat8 yy]# echo $((41))
5
[rootredhat8 yy]# echo $((4*1))
4
[rootredhat8 yy]# echo $((4**1))
4
[rootredhat8 yy]# echo $[4**1]
4
[rootredhat8 yy]#
其中$(O)和$[]的用法是一样的如果不用这样的表达式
[rootredhat8 yy]# echo 2**3
2**3
[rootredhat8 yy]#
这里并不是计算的2的3次方而是直接把这4个字符打印出来了
let也可以用于数学运算
[rootredhat8 yy]# let aa12
[rootredhat8 yy]# echo $aa
3
[rootredhat8 yy]#
这里aa的值就是为3
下面来看不使用let的情况
[rootredhat8 yy]# aa12
[rootredhat8 yy]# echo $aa
12
[rootredhat8 yy]#
这里并没有把aa的值12当成数字而是当成了3个字符:“1”“”“2”所以结果显示的也是12
可以实现定义aa为整数类型然后再做数学运算
[rootredhat8 yy]# declare -i aa
[rootredhat8 yy]# aa12
[rootredhat8 yy]# echo $aa
3
[rootredhat8 yy]#
首先declare -i aa把aa定义为一个整数所以12等于3,然后赋值给aa.所以aa的值为3
以上表达式不能求得小数如果要得到小数需要使用 bc 命令 echo scaleN ; 算法 | bc
这里N是一个数字,表示小数点后面保留几位
计算2/3小数点后面保留3位命令如下
[rootredhat8 yy]# echo scale3 ; 2/3 | bc
.666
[rootredhat8 yy]#
这里得到的结果是0.666整数部分的0没有显示
1.5 if判断语句
在脚本中执行某条命令需要满足一定的条件如果不满足就不能执行。此时我们就要用到 判断语句了
先看if判断if判断的语法如下
1. if 条件1 ; then
2. 命令1
3. elif 条件2 ; then
4. 命令2
5. else 命令3
6. fi先判断if后面的判断是不是成立
如果成立则执行命令1然后跳到f后面执行6后面的命令
如果不成立则不执行命令1然后判断elif后面的条件2是不是成立
如果成立则执行命令2然后跳到f后面执行f后面的命令
如果不成立则不执行命令2进行下一轮的elif 判断以此类推
如果所有if和elif都不成立则执行clse中的命令3
练习写一个脚本/opt/sc1.sh要求只有root用户才能执行此脚本其他用户不能执行
[rootredhat8 ~]# cat /opt/sc1.sh
#/bin/bash
if [ $UID -ne 0 ]; thenecho 只有root才能执行此脚本exit 1
fi
echo hello root[rootredhat8 ~]# chmod x /opt/sc1.sh
[rootredhat8 ~]# 脚本分析如下
root的uid是0其他用户的uid不为0。第一个判断如果uid不等于0则打印警告信 息“只有root才能执行此脚本”然后exit退出脚本
如果这里不加 exit判断之后仍然会继续执行echo hello root命令这样判断就失去 了意义。只有加了exit之后如果不是root则到此结束不要继续往下执行了
如果是jin 执行此脚本则判断成立打印完警告信息之后通过exit退出脚本
如果是 root执行此脚本则判断不成立直接执行f后面的命令
使用root用户执行此脚本的结果如下
[rootredhat8 ~]# /opt/sc1.sh
hello root
[rootredhat8 ~]#
使用jin用户执行此脚本的结果如下
[jinredhat8 ~]$ /opt/sc1.sh
只有root才能执行此脚本
[jinredhat8 ~]$