好不容易,进入两位数的章节了…一路走来,很辛苦吧?也很快乐吧?
在解答本章题目之前,先让我们了解一个概念:return value(返回值)!
我们在shell下跑的每一个command或function,在结束的时候都会传回父进程一个值,称为return value(返回值)。
在shell 命令行中可用$?这个变量得到最新的一个return value,也就是刚结束的那个进程传回的值。
Return Value(RV)的取值为0-255之间,由脚本的作者自行定义:
*若在script里,用exit RV来指定其值,若没指定,在结束时以最后一道命令之RV为值 *若在function里,则用return RV来代替exit RV即可。
Return Value的作用,是用来判断进程的退出状态(exit status),只有两种:
*0的话为“真”(true) *非0的话为“假”(false)
举个例子来说明好了:假设当前目录内有一个my.file文件,而no.file是不存在的:
$ touch my.file $ ls my.file $ echo $? # first echo 0 $ ls no.file ls: no.file: No such file or directory $ echo $? # second echo 1 $ echo $? # third echo 0
上例的第一个echo是关于ls my.file的RV,可得到0的值,因此为true
第二个echo是关于ls no.file的RV,则得到非0的值,因此为false
第三个echo是关于第二个echo $?的RV,为0的值,因此也为true。
请记住:每一个command 在结束时都会送回return value的!不管你跑什么样的命令…
然而,有一个命令却是“专门”用来测试某一条件而送出return value一共true或false的判断。它就是test命令了。
若你用的是bash,请在命令行下输入man test或man bash来了解这个test的用法。这是你可以用作参考的最精确的文件了,要是听别人说的,仅作参考就好…
下面我只见到做一些辅助说明,其余一律以man为准:
首先,test的表示式我们称为expression,其命令格式有两种:
test expression or: [ expression ]
(请务必注意[]之间的空格)
用哪一种格式无所谓,都是一样的效果。(我个人比较喜欢后者…)
其次,bash的test目前支持的对象只有三种:
*string:字符串,也就是纯文字 *integer:整数(0或正整数,不含负数或小数点) *file:文件
请初学者一定要搞清楚这三者的差异,因为test所用的expression是不一样的。以A=123这个变量为例:
* [ "$A" = 123 ]:是字符串的测试,以测试 $A 是否为 1、2、3 这三个连续的"文字"。 * [ "$A" -eq 123 ]:是整数的测试,以测试 $A 是否等于"一百二十三"。 * [ -e "$A" ]:是关于文件的测试,以测试 123 这份"文件"是否存在。
第三,当expression测试为“真”时,test就送回0(true)的return value,否则送出非0(false)。
若在expression之前加上一个“!”(感叹号),则是当expression为“假”时才送出0,否则送出非0。
同时,test也允许多种的符合测试:
* expression1 -a expression2 :当两个 exrepssion 都为 true ,才送出 0 ,否则送出非 0 。 * expression1 -o expression2 :只需其中一个 exrepssion 为 true ,就送出 0 ,只有亮者都为 false 才送出非 0 。
例如:
[ -d "$file" -a -x "$file" ]
是表示当 $file 是一个目录、且同时具有 x 权限时,test 才会为 true 。
第四,在 command line 中使用 test 时,请别忘记命令行的”重组”特性,也就是在碰到 meta(元字符) 时会先处理 meta 再重新组件命令行。(这个特性我在第二及第四章都曾反复强调过)
比方说,若 test 碰到变量或命令替换时,若不能满足 expression 格式时,将会得到语法错误的结果。举例来说好了:
关于 [ string1 = string2 ] 这个 test 格式,在 = 号两边必须要有字串,其中包括空(null)字串(可用 soft quote 或 hard quote 取得)。
假如 $A 目前沒有定义,或被定义为空字串的话,那如下的写法将会失败:
$ unset A $ [ $A = abc ] [: =: unary operator expected
这是因为命令行碰到 $ 这个 meta 时,会替换 $A 的值,然后再重组命令行,那就变成了:
[ = abc ]
如此一来 = 号左边就沒有字串存在了,因此造成 test 的语法错误!但是,下面这个写法则是成立的:
$ [ "$A" = abc ] $ echo $? 1
这是因为在命令行重组后的结果为:
[ "" = abc ]
由于 = 左边我们用 soft quote 得到一个空字串,而让 test 语法得以通过…
读者诸君请务必留意这些细节哦,因为稍一不慎,将会导致test的结果变了个样!若您对 test 还不是很有经验的话,那在使用 test 时不妨先采用如下这一个”法则”:
* 假如在 test 中碰到变量替换,用 soft quote 是最保险的﹗
若你对 quoting 不熟的话,请重新温习第四章的內容吧… ^_^
okay,关于更多的 test 用法,老话一句:请看 man page 吧﹗ ^_^
虽然洋洋洒洒了一大堆,或许你还在嘀咕…. 那… 那个 return value 有啥用啊?!
问得好!
告诉你:return value 的作用可大了﹗若你想让你的 shell 变”聪明”的话,就全靠它了:
有了 return value,我们可以让 shell 根据不同的状态做不同的事情…
这时候,才让我来揭晓本章的答案吧~~~ ^_^
&& 与 || 都是用来”组件”多个 command line 用的:
* command1 && command2 :其意思是 command2 只有在 RV 为 0 (true) 的条件下执行。 * command1 || command2 :其意思是 command2 只有在 RV 为非 0 (false) 的条件下执行。
来,以例子来说好了:
$ A=123 $ [ -n "$A" ] && echo "yes! it's ture." yes! it's ture. $ unset A $ [ -n "$A" ] && echo "yes! it's ture." $ [ -n "$A" ] || echo "no, it's NOT ture." no, it's NOT ture.
(注:[ -n string ] 是测试 string 长度大于 0 则为 true 。)
上例的第一个 && 命令行之所以会执行其右边的 echo 命令,是因为上一个 test 送回了 0 的 RV 值;但第二次就不会执行,因为 test 送回非 0 的结果…
同理,|| 右边的 echo 会被执行,却正是因为左边的 test 送回非 0 所引起的。
事实上,我们在同一命令行中,可用多个 && 或 || 来组件呢:
$ A=123 $ [ -n "$A" ] && echo "yes! it's ture." || echo "no, it's NOT ture." yes! it's ture. $ unset A $ [ -n "$A" ] && echo "yes! it's ture." || echo "no, it's NOT ture." no, it's NOT ture.
怎样,从这一刻开始,你是否觉得我们的 shell 是”很聪明”的呢? ^_^
好了,最后,布置一道习题给大家做做看、、、
下面的判断是:当 $A 被赋值时,再看是否小于 100 ,否则送出 too big! :
$ A=123 $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!' too big!
若我将 A 取消,照理说,应该不会送文字才对啊(因为第一个条件就不成立了)…
$ unset A $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!' too big!
为何上面的结果也可得到呢?
又,如何解決之呢?
(提示:修改方法很多,其中一种方法可利用第七章介绍过的 command group …)
快﹗告我我答案﹗其余免谈….
转载请注明:知识蚂蚁 » shell十三问?(简体中文版)第10问:&&与||差在哪?