1.脚本中的测试判断式
在shell脚本中,我们除了使用【$?】这一变量的返回值进行判断以外,还有【test】和中括号【[]】这两个测试判断式可以进行条件判断
(1)test命令
test这个命令用于条件判断的话,可谓是十分的好用,但是我们在直接使用test命令,例如test -e 来判断一个文件是否存在的时候,系统并不会直接给我们输出它的返回值。

但是我们可以配合相应的【&&】和【||】命令来展示其结果。


(2)判断符号【[ ]】
【[ ]】中括号这个符号和test命令的使用效果是一致的,不过使用【[ ]】作为判断符号有3个必须要注意的地方就是:
①中括号的两端需要有空格符来分隔。
例:[ "${1a}" == "${2a}" ],注意变量和括号间隔的空格
②括号内的变量最好有【“ ”】双引号括住
③括号内的常数最好有单引号【‘ ’】或双引号【“ ”】括住
例:[ "${1a} " == "2" ]
例如,我想判断一个变量'input'是不是空变量,如果是的话就返回一个“这是一个空变量”,如果不是的话就输出“这是非空变量”,我应该怎么写这个判断式子?
使用【test】命令,我们可以写成:
test -z ${input} && echo '这是一个空变量' || echo '这是非空变量'

而使用中括号【[ ]】,我们可以写成:
[ -z "${input}"] && echo '这是一个空变量' || echo '这是非空变量'

(3)判断式常用参数
① 【文件类型】的判断
关于某个文件名的【文件类型】的判断,例如
test -e filename 判断文件是否存在
Ⅰ. -e
判断是否存在拥有该【文件名】的文件
Ⅱ. -f
该【文件名】是否存在,且是否为文件?
Ⅲ. -d
该【文件名】是否存在,且是否为目录?
② 【文件权限】的判断
关于某个文件名的【文件权限】的判断
例如[ -r "filename" ] 判断该文件是否存在,且是否可读
Ⅰ. -r
该【文件名】是否存在,且是否可读?
Ⅱ. -w
该【文件名】是否存在,且是否可写?
Ⅲ. -x
该【文件名】是否存在,且是否可执行?
Ⅳ. -u
该【文件名】是否存在,且是否拥有SUID属性
Ⅴ. -g
该【文件名】是否存在,且是否拥有SGID属性
③ 【文件之间比较】的判断
用于比较两个文件之间的不同
例如 test file1 -nt file2,比较第一个文件是否比第二个文件新
Ⅰ. -nt(newer than)
test file1 -nt file2
比较file1是否比file2新
Ⅱ. -ot (older than)
test file1 -ot file2
比较file1是否比file2旧
④【两个整数之间比较】的判断
用于比较两个整数的大小关系
例如:test n1 -eq n2
Ⅰ. -eq(equal)
比较两个数值是否相等
Ⅱ. -ne(no equal)
比较两个数值是否不等
Ⅲ. -gt(greater than)
比较n1是否大于n2
Ⅳ. -lt(less than)
比较n1是否小于n2
Ⅴ. -ge(greater than or equal)
比较n1是否大于等于n2
Ⅵ. -le(less than or equal)
比较n1是否小于等于n2
⑤ 【字符串数据】的判断
用于判断字符串是否是空字符串,两个字符串是否相等
例如:test -z ${PATH},判定PATH是否是空变量
Ⅰ. -z
判断字符串是否为空字符串,若是,则为true
Ⅱ. -n
test -n string
判断字符串是否为空字符串,若是,则为false
(-n可省略,区别-z参数)
Ⅲ. ==
test str1 == str2
判断str1是否和str2相等,若相等,则为true
Ⅳ. !=
test str1 != str2
判断str1是否和str2不相等,若不相等,则为true
⑥ 【多重条件】的判断
和(and)、或(or)、反选(!)等条件的使用
例如:test -r file1 -a -x file2
当file1有可读权限并且file2有可执行权限时,才返回true
Ⅰ. -a(and)
test -z file1 -a -z file2
和(and)两条件同时成立,才返回true
Ⅱ. -o(or)
test -z file1 -o -z file2
或(or)两条件只要达成一个,就返回true
Ⅲ. !
test ! -x file1
反相选择,如果file1不具有可执行权限,则返回true

2.脚本的默认变量和特殊变量
(1)默认变量
我们通过之前的学习能够得知,再输入命令时,我们可以在命令后面带上选项和参数,那么脚本在执行的时候,我们能不能接上相应的参数呢?
答案是可以的,并且脚本后续所带的参数,我们是可以在脚本的内容里进行指定的,通过直接输入参数来执行脚本,就可以省去一些手动输入变量的操作。
而这个脚本的后续参数,其实就是脚本自身的默认变量($0 $1 $2....),具体的我们可以通过一个脚本执行来看看:
例如:sh ping.sh opt1 opt2 opt3 opt4
则默认变量为 $0 $1 $2 $3 $4
脚本的文件名就是$0这个变量,然后后续的参数依顺序分别对应变量$1、$2、$3.....
(2)特殊变量
除了上述的基本默认变量以外,我们还可以在脚本的编写中使用一些特殊变量:
① $#
代表后接参数的个数,上边的例子,$#的值为【4】
② $@
可以列出全部的参数,格式为【"$1""$2""$3""$4"】
③ $*
同样也可以列出全部的参数,但是格式为【“$1c$2c$3c$4”】,其中【c】为分隔符,默认为空格,上边的例子显示则为【“$1 $2 $3 $4”】
例如:如下这个脚本内容可以显示我们执行脚本时输入的选项对应的变量

其执行结果为:

3.脚本中的条件判断式
(1)if.... then....fi
当符合某个条件判断(if)时,就予以进行某任务(then).....,但是要注意在条件命令的结尾,要加上【fi】来表示命令结束
① 单层、简单条件判断式
如果只有一个条件的话,可以直接使用if....;then...fi来进行命令编写
语句格式:if [条件判断式]; then (如果是用test命令,则不加中括号【[ ]】)
条件达成要执行的任务
fi ←==将if反过来写,代表结束之意
例如:if test -z ${path}; then
echo "变量内容是空的!"
fi
然后在中括号[条件判断式]的写法可以参考第一节中的内容,如果包含多个想要达成的条件,除了使用【-a】或者【-o】的参数以外,也可以使用【&&】和【||】这两个,但是表达的意思和管道命令中的意思不同,【&&】也代表着【和】的意思,【||】代表着【或】
例如:[ "y" == "4" -o "z" == 5 ]可以写成:[ "y"==4 ] || [ "z"==5 ]
② 多重、复杂条件判断式
如果含有多个条件,可以使用 if...;then elif....;then elif...;then else.... fi 这个命令来进行编写
语句格式:if [第一个条件]; then
第一个条件达成执行的任务
elif [第二个条件]; then
第二个条件达成执行的任务
else
第一个和第二个条件都不达成时执行的任务
fi
脚本演示:
例1:if....;then脚本内容演示

例2:带参数的脚本演示


例3:使用if判别式的系统端口判断脚本内容演示


(2)case...esac
case...esac和if...then...fi类似,也是一种条件判断式。如果说if...then....fi是用【比对】的方式对变量进行判断,符合状态就进行某些操作,并且通过多层次(.....elif)来进行多个变量的程序代码编写。那么case...esac就是用于多个【既定】的变量内容状态的设定(【既定】说的是固定数量的参数,比如一个代码我固定了其在执行时必须要输入的后续参数,假设是两个参数,那么除去默认变量的$0,就还有两个变量,分别是$1和$2)。假设脚本有1个参数,参数的内容我指定为【hello】和【bye】,那我就可以用case...esac来分别指定参数为【hello】时和【bye】时返回的信息。
语句格式:case ${变量内容} in
“第一个变量内容”)←变量的内容要双引号【“”】来括住,关键字为右边的括号
第一个程序段
;; ←每个变量内容结束时,要输入两个连续的分号【;;】
“第二个变量内容”)
第二个程序段
;;
*) ←最后一个变量的内容使用星号【*】来代表所有其他值
除了第一和第二个变量内容以外的程序执行段
exit 1
;;
esac ←case判断式的结尾要用esac来结尾
例1:我想创建一个脚本,当用户输入【hello】这第一个参数的时候,就显示“hello,how are you”;当用户没有输入参数时,显示“请输入参数”;当输入其他参数时,显示“请输入参数(hello)”
程序:case $1 in
"hello")
echo "hello,how are you"
"")
echo “请输入参数”
*)
echo “请输入参数(hello)”
esac


case的参数变量内容除了跟随脚本执行时一起输入以外,也可以配合read命令来让用户进行输入
例如这样的程序:这个程序能将输入的第一个数字参数从小写转为大写
read -p ‘请输入英文数字’ num
case ${num} in
“one”)
echo ‘你输入的是ONE’
;;
“two”)
echo '你输入的是TWO'
;;
"three")
echo '你输入的是THREE'
;;
*)
echo '请输入(one)或(two)或(three)'
;;
esac
(3)function(函数功能)
① 了解function
在脚本的编写中,一些重复的命令可以使用function(函数)功能进行一个命令简化,那啥是function功能?
function功能就相当于我特意编写一个专门执行某个特定命令的命令,来取代我脚本内重复的命令
命令格式:function 函数名 ( ) {
程序框
}
这里要注意一个问题,由于shell的脚本命令执行顺序是从上到下,从左到右,为了能够让脚本在执行时能找到我们所需的程序段,我们function一定要放在我们脚本程序的最前边,就有点像python里边的依赖那样
继续以(2)节里最后一个脚本来举例子,我们可以看出无论我们输入one还是two还是three,程序都是输出一段文字“你输入的是”,然后加上一个转换大小写后的英文数字。
那我们就考虑使用一个function来取代那个重复的文字输出,我们可以这样做:
function printit ( ){
echo "你输入的是"
}
case $1 in
"one")
printit ; echo $1 |tr [a-z] [A-Z]
;;
"two")
printit;echo $1 | tr [a-z] [A-Z]
;;
"three")
printit; echo $1 | tr [a-z] [A-Z]
;;
*)
echo '请输入(one)或(two)或(three)'
;;
esac


② function的内置变量
和脚本自带的内置变量同样,function也拥有自己的内置变量$0 、$1 、$2等,$0也代表着function名(function定义的函数名),但是$1,$2和之后的变量代表的意义是和脚本的内置变量是不同的。
这里我们用脚本来直接进行演示比较好说明

这里我们创建一个名为【printit】的function,那么接下来调用的printit的第一个参数就是内置变量$1

4.不定循环
不定循环指的是不知道具体循环次数的循环,在shell中有两种不定循环的语句,一个是当满足条件时进行循环的【while...do...done】;一个是当满足条件就跳出循环的【until...do...done】
(1)while...do...done
【while】的意思是,当xx条件成立时,就进行循环,否则就停止循环
语句格式:while [条件判断式]
do←循环的开始使用do
程序段落
done←循环的结束使用done
例如:我想让用户输入一个2~100的之间的数字n,然后做一个1到n的累加。
read -p '请输入一个2~100之间的数字:' num
i=1
s=0
while [ "${i}" -lt "${num}" ]
do
s=$(($s+$i)) **←这里注意计算式的写法$((计算式))**
i=$(($i+1))
done
echo "累加的结果为:"${s}


(2)until...do...done
until...do...done和while...do...done的意义相反,其意义为:当满足xx条件时,就跳出循环,不然就一直循环
语句格式:until [ 条件判断式 ]
do
程序段
done
继续以上边的例子为例,我们写成until语句的话,就可以这样:
read -p '请输入一个2~100之间的数字:' num
i=1
s=0
until [ "${i}" -gt "${num}" ]
do
s=$(($s+$i))
i=$(($i+1))
done
echo "累加的结果为:"${s}
5.固定循环
【固定循环】指的是我已经知道了应该要循环的次数的状态。比如有一个数组,我反复的取里边的值出来,就是一种固定循环。
(1)for...do...done
语句格式:for var(变量) in $(seq 1 10)
do
程序块
done
这个语句的意思是,变量的内容在1、2、3....10这些内容中进行循环。$(seq 1 10)的是连续的意思,表示后续的两个数值的内容是一直连续的。
第一次循环中,$var的值为1;
第二次循环中,$var的值为2;
第三次循环中,$var的值为3;
.......
其中,变量的内容也可以是一个变量,例如:创建一个名为user的变量,其内容为user=$(cut -d ':' -f 1 /etc/passwd),也就是取出/etc/passwd这个文件的第一列的用户名。
然后我可以创建这么一个循环,从${user}变量中一次取出一个值进行循环,直到取尽其值。
for username(变量名) in ${user}
do
程序块
done
例如:我想创建一个脚本,能够自动帮我ping一个指定网段的IP是否畅通,我该如何用if...do...done来创建?
脚本内容:
read -p "请输入你想要查询的网段的网络地址(x.x.x):" netip
read -p "请输入你要查询的网段的起始主机地址:" beginip
read -p “请输入你想要查询的网段的结尾主机地址:” endip
echo "正在查询...请稍等"
for ip in $((seq ${begin} ${endip}))
do
ping -c 2 ${netip}.${ip} &>/dev/null && result=0 || result=1
if [ "${result} == “0” ]; then
echo "${netip}.${ip}这个网络地址通畅"
else
echo "${netip}.${ip}这个网络地址不通畅"
fi
done


6.shell脚本的跟踪和调试
我们在写完脚本后,有没有什么命令可以进行语法错误排查或运行跟踪排错呢?
答案是有的,我们可以使用【sh】命令带参数来运行脚本。
命令格式:sh 【-n v x】 脚本名
常用参数:
-n:不输出脚本内容,仅仅检查脚本语法有无错误,无错误则不进行输出

-v:脚本运行之前先输出脚本的内容,然后在依次运行脚本

-x:将使用到的脚本内容输出到屏幕上,查看脚本运行过程(好用)

Comments NOTHING