zoukankan      html  css  js  c++  java
  • && 与 || 差在哪?-- Shell十三问<第十问>

    && 与 || 差在哪?-- 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 是不存在的:

    $ 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 ,请在 command line 下打 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 test 吧!

    虽然洋洋洒洒讲了一大堆,或许你还在嘀咕. 那. 那个 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 ...)

  • 相关阅读:
    (Java) LeetCode 44. Wildcard Matching —— 通配符匹配
    (Java) LeetCode 30. Substring with Concatenation of All Words —— 与所有单词相关联的字串
    (Java) LeetCode 515. Find Largest Value in Each Tree Row —— 在每个树行中找最大值
    (Java) LeetCode 433. Minimum Genetic Mutation —— 最小基因变化
    (Java) LeetCode 413. Arithmetic Slices —— 等差数列划分
    (Java) LeetCode 289. Game of Life —— 生命游戏
    (Java) LeetCode 337. House Robber III —— 打家劫舍 III
    (Java) LeetCode 213. House Robber II —— 打家劫舍 II
    (Java) LeetCode 198. House Robber —— 打家劫舍
    (Java) LeetCode 152. Maximum Product Subarray —— 乘积最大子序列
  • 原文地址:https://www.cnblogs.com/passzhang/p/12200911.html
Copyright © 2011-2022 走看看