&& 与 || 差在哪?-- Shell十三问<第十问>

好不容易,进入两位数的章节了... 一路走来,很辛苦吧?也很快乐吧?

在解答本章题目之前,先让我们了解一个概念:return value !我们在 shell 下跑的每一个 command 或 function ,在结束的时候都会传回父进程一个值,称为 return value 。

在 shell command line 中可用 $? 这个变量得到最"新"的一个 return value ,也就是刚结束的那个进程传回的值。

Return Value(RV) 的取值为 0-255 之间,由程序(或 script)的作者自行定议:

  • 若在 script 里,用 exit RV 来指定其值,若没指定,在结束时以最后一道命令之 RV 为值。
  • 若在 function 里,则用 return RV 来代替 exit RV 即可。

Return Value 的作用,是用来判断进程的退出状态(exit status),只有两种:

  • 0 的话为"真"( true )
  • 非 0 的话为"假"( false )

举个例子来说明好了:

假设当前目录内有一份 my.file 的文件,而 no.file 是不存在的:

  1. $ touch my.file
  2. $ ls my.file
  3. $ echo $? # first echo
  4. 0
  5. $ ls no.file
  6. ls: no.file: No such file or directory
  7. $ echo $? # second echo
  8. 1
  9. $ echo $? # third echo
  10. 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 ,请在 command line 下打 man test 或 man bash 来了解这个 test 的用法。这是你可用作参考的最精确的文件了,要是听别人说的,仅作参考就好.

下面我只简单作一些辅助说明,其余的一律以 man 为准:

  1. 首先,test 的表示式我们称为 expression ,其命令格式有两种:
  2. test expression
  3. or:
  4. [ expression ]
  5. ( 请务必注意 [ ] 之间的空格键!)

用哪一种格式没所谓,都是一样的效果。(我个人比较喜欢后者...)

其次,bash 的 test 目前支持的测试对像只有三种:

  • string:字符串,也就是纯文字。
  • integer:整数( 0 或正整数,不含负数或小数点)。
  • file:文件。

请初学者一定要搞清楚这三者的差异,因为 test 所用的 expression 是不一样的。

  1. A=123 这个变量为例:
  2. * [ "$A" = 123 ]:是字符串的测试,以测试 $A 是否为 123 这三个连续的"文字"
  3. * [ "$A" -eq 123 ]:是整数的测试,以测试 $A 是否等于"一百二十三"
  4. * [ -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 。

例如:

  1. [ -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 目前没有定义,或被定议为空字符串的话,那如下的写法将会失败:

  1. $ unset A
  2. $ [ $A = abc ]
  3. [: =: unary operator expected

这是因为命令行碰到 $ 这个 meta 时,会替换 $A 的值,然后再重组命令行,那就变成了:

  1. [ = abc ]

如此一来 = 号左边就没有字符串存在了,因此造成 test 的语法错误!

但是,下面这个写法则是成立的:

  1. $ [ "$A" = abc ]
  2. $ echo $?
  3. 1
  4. 这是因为在命令行重组后的结果为:
  5. [ "" = abc ]

由于 = 左边我们用 soft quote 得到一个空字符串,而让 test 语法得以通过... 读者诸君请务必留意这些细节哦,因为稍一不慎,将会导至 test 的结果变了个样! 若您对 test 还不是很有经验的话,那在使用 test 时不妨先采用如下这一个"法则":

  • 假如在 test 中碰到变量替换,用 soft quote 是最保险的!若你对 quoting 不熟的话,请重新温习第四章的内容吧.okay,关于更多的 test 用法,老话一句:请看 man test 吧!

虽然洋洋洒洒讲了一大堆,或许你还在嘀咕. 那. 那个 return value 有啥用啊?!

问得好!

告诉你:return value 的作用可大了!若你想让你的 shell 变"聪明"的话,就全靠它了:

  • 有了 return value,我们可以让 shell 跟据不同的状态做不同的时情...

这时候,才让我来揭晓本章的答案吧!

&& 与 || 都是用来"组建"多个 command line 用的:

  • command1 && command2 :其意思是 command2 只有在 RV 为 0 (true) 的条件下执行。
  • command1 || command2 :其意思是 command2 只有在 RV 为非 0 (false) 的条件下执行。

    来,以例子来说好了:
  1. $ A=123
  2. $ [ -n "$A" ] && echo "yes! it's ture."
  3. yes! it's ture.
  4. $ unset A
  5. $ [ -n "$A" ] && echo "yes! it's ture."
  6. $ [ -n "$A" ] || echo "no, it's NOT ture."
  7. no, it's NOT ture.
  8. (注:[ -n string ] 是测试 string 长度大于 0 则为 true 。)
  9. 上例的第一个 && 命令行之所以会执行其右边的 echo 命令,是因为上一个 test 送回了 0
  10. RV 值﹔但第二次就不会执行,因为为 test 送回非 0 的结果...同理,|| 右边的 echo
  11. 会被执行,却正是因为左边的 test 送回非 0 所引起的。
  12. 事实上,我们在同一命令行中,可用多个 && || 来组建呢:
  13. $ A=123
  14. $ [ -n "$A" ] && echo "yes! it's ture." || echo "no, it's NOT ture."
  15. yes! it's ture.
  16. $ unset A
  17. $ [ -n "$A" ] && echo "yes! it's ture." || echo "no, it's NOT ture."
  18. no, it's NOT ture.
  19. 怎样,从这一刻开始,你是否觉得我们的 shell "很聪明"的呢?

好了,最后,布置一道习题给大家做做看

  1. 下面的判断是:当 $A 被赋与值时,再看是否小于 100 ,否则送出 too big!
  2. $ A=123
  3. $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
  4. too big!
  5. 若我将 A 取消,照理说,应该不会送文字才对啊(因为第一个条件就不成立了)...
  6. $ unset A
  7. $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
  8. too big!

为何上面的结果也可得到呢?又,如何解决之呢?

(提示:修改方法很多,其中一种方法可利用第七章介绍过的 command group ...)

&& 与 || 差在哪?-- Shell十三问<第十问>的更多相关文章

  1. > 与 < 差在哪?-- Shell十三问<第十一问>

    > 与 < 差在哪?-- Shell十三问<第十一问> 谈到 I/O redirection ,不妨先让我们认识一下 File Descriptor (FD) .程序的运算,在 ...

  2. $(( )) 与 $( ) 还有${ } 差在哪?-- Shell十三问<第八问>

    $(( )) 与 \(( ) 还有\){ } 差在哪?-- Shell十三问<第八问> 我们上一章介绍了 ( ) 与 { } 的不同,这次让我们扩展一下,看看更多的变化:$( ) 与 \( ...

  3. ( ) 与 { } 差在哪?-- Shell十三问<第七问>

    ( ) 与 { } 差在哪?-- Shell十三问<第七问> 先说一下,为何要用 ( ) 或 { } 好了. 许多时候,我们在 shell 操作上,需要在一定条件下一次执行多个命令,也就是 ...

  4. exec 跟 source 差在哪?-- Shell十三问<第六问>

    exec 跟 source 差在哪?-- Shell十三问<第六问> 这次先让我们从 CU Shell 版的一个实例贴子来谈起吧: 例中的提问是: cd /etc/aa/bb/cc 可以执 ...

  5. var=value?export前后差在哪?-- Shell十三问<第五问>

    var=value?export前后差在哪?-- Shell十三问<第五问> 这次让我们暂时丢开 command line ,先来了解一下 bash 变量(variable)吧.所谓的 变 ...

  6. " "( 双引号) 与 ' '( 单引号) 差在哪?-- Shell十三问<第四问>

    " "( 双引号) 与 ' '( 单引号) 差在哪?-- Shell十三问<第四问> 经过前面两章的学习,应该很清楚当你在 shell prompt 后面敲打键盘.直到 ...

  7. 别人 echo 、你也 echo ,是问 echo 知多少?-- Shell十三问<第三问>

    别人 echo .你也 echo ,是问 echo 知多少?-- Shell十三问<第三问> 承接上一章所介绍的 command line ,这里我们用 echo 这个命令加以进一步说明. ...

  8. [^ ] 跟 [! ] 差在哪?-- Shell十三问<第十四问>

    [^ ] 跟 [! ] 差在哪?-- Shell十三问<第十四问> 这道题目说穿了, 就是要探讨 Wildcard(通配符)与 Regular Expression(正则表达式)的差别的. ...

  9. shell十三问

    1) 为何叫做 shell ?在介绍 shell 是甚幺东西之前,不妨让我们重新检视使用者与计算机系统的关系:图(FIXME)我们知道计算机的运作不能离开硬件,但使用者却无法直接对硬件作驱动,硬件的驱 ...

随机推荐

  1. mdn & remove & removeChild

    mdn & remove & removeChild Element https://developer.mozilla.org/en-US/docs/Web/API/Element ...

  2. MySQL 修改数据表

    修改数据表: 创建数据表 更改表明 更改字段数据类型 更改字段名称 更改字段名称和数据类型 为表添加新字段 将字段顺序改为第一位 将字段顺序改为另一个字段之后 删除字段 1 use test; 2 3 ...

  3. springCloud中的注册中心Nacos

    springCloud中的注册中心Nacos 三个模块: 1.注册中心 2.服务提供者(生产者) 提供服务 3.服务消费者(消费者)调用服务 流程:消费者和生产者都要向注册中心注册,注册的是二者中服务 ...

  4. 2021-2-25:对于 Java MMAP,如何查看文件映射脏页,如何统计MMAP的内存大小?

    我们写一个测试程序: public static void main(String[] args) throws Exception { RandomAccessFile randomAccessFi ...

  5. 微信小程序:自定义组件

    为什么要学习自定义组件? 1.用上我自己的单词abc,我希望在页面中展示椭圆形的图片, 2.打开手机淘宝,假如现在要做一个企业级项目,里面有很多页面,首页存在导航模块,点击天猫,进入第二个页面,而第二 ...

  6. Oracle数据库的函数

    一.字符函数upper和lower (1).upper和lower upper把小写的字符转换成大小的字符 ,lower把大写字符变成小写字符 . select upper('yes') from d ...

  7. 1.3.1 apache的配置(下)

    (1)httpd.conf的配置 使用文本编辑工具(推荐使用Editplus.UltraEdit等工具),打开httpd.conf. 其中,行首为#的部分为注释部分,不会被apache服务器程序进行读 ...

  8. 普通的一天,说一个普通的XML

    什么是XML XML全称是Extensible Markup Language,译为"可扩展标记语言",常用来存储和传输信息. XML的结构 我们经常看到的XML文件是这个样子的: ...

  9. 【Arduino学习笔记07】模拟信号的输入与输出 analogRead() analogWrite() map() constrain()

    模拟信号:Arduino中的模拟信号就是0v~5v的连续的电压值 数字信号:Arduino中的数字信号就是高电平(5V)或者低电平(0V),是两个离散的值 模拟信号->数字信号:ADC(模数转换 ...

  10. JavaScript offset、client、scroll家族

    offsetParent <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...