文章目录
- shell脚本的判断式
- 利用test命令的测试功能
- 关于某个文件名的【文件类型】判断
- 关于文件的权限检测
- 两个文件之间的比较
- 关于两个整数之间的比较
- 判定字符串的数据
- 多重条件判定
- 例题
- 利用判断符号[ ]
- 例题
- shell脚本的默认变量($0、$1...)
- 例题
- shift:造成参数变量号码偏移
shell脚本的判断式
在之前的博客写过$?所代表的意义。此外,也通过&&及||来作为前一个命令执行返回值对于后一个命令是否要进行的根据。如果想要判断一个目录是否存在,当时我们使用的是ls这个命令搭配数据流重定向,最后配合%?来决定后续的命令进行与否,如下图。
但是我们有更简单的方法来进行【条件判断】吗?利用【test】这个命令
利用test命令的测试功能
当我们要检测上面某些文件或是相关的属性时,利用test这个命令来进行检测
例如我要检查/csq 是否存在时
[root@localhost ~]# test -e /csq
[root@localhost ~]# echo $?
1
【test -e /csq】并没有显示任何信息,当我们输入了 echo $? 返回值不是0 代表是错误信息,我们也可以利用 &&及||来展销整个结果
例如我换一种方法检测一下/csq是否存在
[root@localhost ~]# test -e /csq && echo "this is exist" || echo "this is no exist"
this is no exist
最终结果告诉我们是【exist】还是【no exist】,那我们知道 -e 是测试一个【东西】存在不存在,如果我还想测试目录下的文件是否存在时,该用哪些参数呢?
关于某个文件名的【文件类型】判断
例如:test -e filename 表示存在否
测试的参数 | 代表的意义 |
---|---|
-e | 该【文件名】是否存在 |
-f | 该【文件名】是否存在且位文件(file) |
-d | 该【文件名】是否存在且位目录 |
-b | 该【文件名】是否存在且为一个block device 设备 |
-c | 该【文件名】是否存在且为一个 character device |
-S | 该【文件名】是否存在且为一个socket文件 |
-p | 该【文件名】是否存在且为一个FIFO文件 |
-L | 该【文件名】是否存在且为一个链接文件 |
关于文件的权限检测
例如:test -r filename 表示可读否
测试的参数 | 代表的意义 |
---|---|
-r | 检测该文件名是否存在且具有【可读】的权限 |
-w | 检测该文件名是否存在且具有【可写】的权限 |
-x | 检测该文件名是否存在且具有【可执行】的权限 |
-u | 检测该文件名是否存在且具有【SUID】的属性 |
-g | 检测该文件名是否存在且具有【SGID】的属性 |
-k | 检测该文件名是否存在且具有【SBIT】的属性 |
-s | 检测该文件名是否存在且为【非空文件】 |
两个文件之间的比较
例如:test file1 -nt file2
测试的参数 | 代表的意义 |
---|---|
-nt | 判断【file1】是否比【file2】新 |
-ot | 判断【file1】是否比【file2】旧 |
-ef | 判断【file1】与【file2】是否为同一个文件,可用在判断硬链接上面。 主要意义在于判定,两个文件是否均指向同一个inode |
关于两个整数之间的比较
例如:test n1 -eq n2
测试的参数 | 代表的意义 |
---|---|
-eq | 两数值相等 |
-ne | 两数值不相等 |
-gt | n1 大于 n2 |
-lt | n1 小于 n2 |
-ge | n1 大于等于 n2 |
-le | n1 小于等于 n2 |
判定字符串的数据
测试的参数 | 代表的意义 |
---|---|
test -z string | 判定字符串是否为0?若string为空字符串,则为true |
test string | 判断字符串是否非为0?若string为空字符串,则为false |
test str1 == str2 | 判定str1是否等于str2,若相等,则返回true |
test str1 != str2 | 判定str1是否等于str2,若相等,则返回true |
多重条件判定
例如:test -r filename -a -x filename
测试的参数 | 代表的意义 |
---|---|
-a | 两条件同时成立。 例如:test -r file -a -x ,则file同时具有r与x权限时,才返回true |
-o | 两条件任何一个成立 例如:test -r file -o -x ,则file具有r或x权限时,旧可返回true |
! | 反相状态 例如:test ! -x file ,当file不具有x时,返回true |
例题
首先我让用户输入一个文件名,我们判断:
- 整个文件是否存在,若不存在则给予一个【文件不存在】的信息,并中断程序
- 若这个文件存在,则判断它是个文件或目录,结果输出【这个文件是普通文件】或【这个文件是目录文件】
- 判断一下,执行者的身份对这个文件或目录所拥有者的权限,并输出权限输出
[root@localhost shelldir]# vim panduanfile.sh
#!/bin/bash
# 程序说明:
# 用户输入一个文件,程序进行了以下操作
# 1.输入的文件是否存在 2.是文件还是目录 3.文件的权限是什么?
# History
# 2023/04/28 csq
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:~/shelldir
export PATH
read -p "请用户输入一个文件:" filename
test -z ${filename} && echo "你必须输入一个文件!" && exit 0
test ! -e ${filename} && echo "文件${filename}不存在" && exit 0
test -f ${filename} && filetype="普通文件"
test -d ${filename} && filedir="目录文件"
test -r ${filename} && readfile="可读"
test -w ${filename} && writefile="可写"
test -x ${filename} && executefile="可执行"
echo -e "这个文件是:${filetype}${filedir}"
echo "$LOGNAME用户对这个${filetype}${filedir}拥有的权限有:${readfile}${writefile}${executefile}"
执行结果(如果文件存在)
[root@localhost shelldir]# vim panduanfile.sh
请用户输入一个文件:csq
这个文件是:目录文件
root用户对这个目录文件拥有的权限有:可读可写可执行
执行结果(如果文件不存在)
[root@localhost shelldir]# vim panduanfile.sh
请用户输入一个文件:ooo
文件ooo不存在
执行结果(在其他用户上面执行)
[csq@localhost /]$ sh panduanfile.sh
请用户输入一个文件:aaa
这个文件是:普通文件
csq用户对这个普通文件拥有的权限有:可读
利用判断符号[ ]
其实除了test之外,我们还可以利用【[ ]】判断符号来进行数据判断。举例来说,如果我想知道${HOME}这个变量是否为空,可以这样做:
[root@localhost ~]# [ -z "$HOME" ] ; echo $?
1
使用中括号必须要特别注意,因为中括号用在很多地方,包括通配符和正则表达式等。所以说如果要在bash的语法当中使用中括号作为shell的判断式时,必须要注意中括号的两端需要有空格符来分隔。假设空格键使用【□】符号来表示,那你这些地方都需要有空格
[root@localhost ~]# [□"HOME"□==□"$MAIL"□]
你会发现上面的判断式中使用了两个等号【==】,其实在bash当中使用一个等号和两个等号的结果是一样3的。不过在一般常用程序的写法中,一个等号代表【变量的设置】
,两个等号则代表【逻辑判断(是与否之意)】
。由于问在中括号内重点在于【判断】而非【设置变量】,因此建议你使用两个等号
上面的例子在说明,两个字符串【$HOME】与【$MAIL】是否相同,相当于【 test ${HOME} == ${MAIL}】。而如果没有空白分隔例如:[${HOME}==${MAIL}],我们的bash就会显示错误信息。
中括号[]内的每个组件都需要有空格来分隔
在括号内的变量,最好都以双引号括起来
在中括号内的常数,最好都以单或双引号括起来
例题
- 当执行一个程序的时候,这个程序会让用户选择Y或N
- 如果用户输入Y或y时,就显示【OK,继续】
- 如果用户输入N或n时,就显示【NO!,不继续】
- 如果不是Y/yN/n之内的字符,就显示【我不知道你输入的是什么】
[root@localhost shelldir]# vim continue.sh
#!/bin/bash
# 程序说明:
# 这个程序就是让用户做选择
# 时间:
# 2023/04/29
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:~/shelldir
export PATH
read -p "请输入一个Y/y,N/n我们来进行下一步:" yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK,继续" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "NO,不继续" && exit 0
echo -e "\n我不知道你输入的是什么\a"
由于输入正确(Yes)的方法有大小写之分,不论输入大写或小写y都是可以的,此时判断式内就得要两个判断才行,由于是任何一个成立即可(大写或小写的y),所以这里使用-o连接两个判断。
执行结果如下(输入Y)
[root@localhost shelldir]# sh continue.sh
请输入一个Y/y,N/n我们来进行下一步:Y
OK,继续
执行结果如下(没输入)
[root@localhost shelldir]# sh continue.sh
请输入一个Y/y,N/n我们来进行下一步:
我不知道你输入的是什么
shell脚本的默认变量($0、$1…)
我们知道命令可以带有选项参数,例如 【ls -al】可以查看包含隐藏文件的所有的属性与权限。那么shell脚本能不能再脚本文件名后面带有参数呢?
例如:如果你想要重新启动系统网络,可以这样做
[root@localhost ~]# file /etc/init.d/network
/etc/init.d/network: Bourne-Again shell script, ASCII text executabl
# 使用file来查询后,系统告知这个文件是个bash可执行的文件
[root@localhost ~]# /etc/init.d/network restart
restart是重启的意思,上面的命令可以【重新启动 /etc/init.d/network 这个程序】。那么如果你再 【/etc/init.d/network 】加个个stop ,就直接关闭服务了。
那么脚本怎么完成这个功能呢?其实脚本针对参数已经设置好了一些变量名称,对应如下
/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4
执行的脚本文件名为 $0这个变量,第一个接的参数就是$1。所以只要我们在脚本里面善用$1的话,就可以很简单地立即执行某些命令功能了。除了这些变量之外,还有一些较为特殊的变量可以在脚本内使用来调用这些参数
$#:代表后接的参数【个数】,以上表为例这里显示为【4】
$@:代表【"$1" "$2" "$3" "$4"】之意,每个变量都是独立的(用双引号括起来)
- $*:代表【“$1c$2c$3c$4c”】,其中c为分隔符,默认为空格,所以本例中代表【“$1 $2 $3 $4”】
$@和$*一般情况下可以直接记忆$@
例题
假设我要执行要个可以携带的参数脚本,执行该脚本后屏幕会显示如下数据:
- 程序的文件名是什么?
- 共有几个参数
- 如果文件名后面没跟参数就提示他没跟参数
- 若参数的个数小于2则告知用户参数数量太少
- 全部的参数内容是什么
- 第一个参数是什么
- 第二个参数是什么
[root@localhost shelldir]# vim args_shibie.sh
#!/bin/bash
# 程序说明:
# 展示以下执行shell脚本的文件名,以及参数
# 时间:
# 2023/04/29
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
export PATH
echo "这个文件名是:${0}"
echo "共有$#个参数"
[ "$#" == "0" ] && echo "文件名后面没跟参数" && exit 0
[ "$#" -lt 2 ] && echo "参数太少" && exit 0
echo "全部的参数内容是:$@"
echo "第一个参数是:$1"
echo "第二个参数是:$2"
执行结果(跟了参数)
[root@localhost shelldir]# sh args_shibie.sh csq zzg zzc
这个文件名是:args_shibie.sh
共有3个参数
全部的参数内容是:csq zzg zzc
第一个参数是:csq
第二个参数是:zzg
执行结果(没跟参数)
[root@localhost shelldir]# sh args_shibie.sh
这个文件名是:args_shibie.sh
共有0个参数
文件名后面没跟参数
shift:造成参数变量号码偏移
除此之外,脚本后面所接的变量是否能够进行偏移(shift)呢?什么是偏移?我们举例来说明,还是用上面的例题。
[root@localhost shelldir]# vim args_shibie.sh
#!/bin/bash
# 程序说明:
# 显示shift造成的参数变量号码偏移了多少
# 时间:
# 2023/04/29
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
export PATH
echo "共有$#个参数"
echo "全部的参数内容是:$@"
shift
echo "共有$#个参数"
echo "全部的参数内容是:$@"
shift 3
echo "共有$#个参数"
echo "全部的参数内容是:$@"
执行结果如下
[root@localhost shelldir]# sh args_shibie.sh aa bb cc dd ff gg hh
共有7个参数
全部的参数内容是:aa bb cc dd ff gg hh
共有6个参数
全部的参数内容是:bb cc dd ff gg hh
共有3个参数
全部的参数内容是:ff gg hh
看到上面的结果就可以知道,shift会移动变量,而且shift后面可以接数字,代表拿掉最前面的几个参数的意思。上面执行结果中,第一次进行shift后它的显示情况是【 aa bb cc dd ff gg hh 】所以只剩下6个参数,第二次直接拿掉三个,就变成【 aa bb cc dd ff gg hh 】。