if else 语句是否等价于逻辑和 && 或 || 我应该在哪里比另一个更喜欢?

Sub*_*dar 28 shell-script control-flow syntax

我正在学习决策结构,我遇到了这些代码:

if [ -f ./myfile ]
then
     cat ./myfile
else
     cat /home/user/myfile
fi


[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
Run Code Online (Sandbox Code Playgroud)

他们两个的行为都是一样的。使用一种方式与另一种方式有什么优势吗?

ica*_*rus 30

大多数人觉得它更容易理解的if... ... then... ... else... ...fi形式。

对于a && b || c,您必须确保b返回 true。这是导致细微错误的原因,也是避免这种风格的一个很好的理由。如果 b 不返回 true 这些就不一样了。

 $ if true; then false ; else echo boom ; fi
 $ true && false || echo boom
 boom
Run Code Online (Sandbox Code Playgroud)

对于没有 else 子句的非常短的测试和操作,缩短的长度很有吸引力,例如

 die(){ printf "%s: %s\n" "$0" "$*" >&2 ; exit 1; }

 [ "$#" -eq 2] || die "Needs 2 arguments, input and output"

 if [ "$#" -ne 2 ] ; then
     die "Needs 2 arguments, input and output"
 fi
Run Code Online (Sandbox Code Playgroud)

&&并且||short circuiting operators,一旦知道结果,就会跳过更多不需要的测试。a && b || c被分组为(a && b) || c. 首先a是运行。如果它fails被定义为不返回退出状态 0,则该组(a && b)已知fail并且b不需要运行。在||不知道表达式的结果所以需要执行c。如果a成功(返回零),则&&操作员尚不知道结果,a && b因此必须运行b以找出答案。如果b成功则a && b成功并且||知道总体结果是成功的,因此不需要运行c。如果b失败那么||仍然不知道表达式的值,因此需要运行c.


xhi*_*nne 29

不,结构if A; then B; else C; fiA && B || C不等价的

使用if A; then B; else C; fi,命令A总是被评估和执行(至少尝试执行它),然后命令B或命令C被评估和执行。

A && B || C,这是相同的各种命令AB但对于不同C:命令C被评估并执行,如果任一 A发生故障 B失败。

在你的例子中,假设你chmod u-r ./myfile,那么,尽管[ -f ./myfile ]成功,你会cat /home/user/myfile

我的建议:使用A && BA || B随心所欲,这仍然易于阅读和理解,并且没有陷阱。但是,如果您的意思是 if...then...else... 然后使用if A; then B; else C; fi.


Geo*_*iou 7

如果前一个命令成功执行,运算符&&执行下一个命令(返回退出代码 ($?) 0 = 逻辑真)。

在 form 中A && B || C,评估命令(或条件)A,如果A返回true(成功,退出代码 0),则执行命令B。如果失败(从而将返回- 0以外的退出代码)和/或失败(返回),则命令Ç将被执行。

此外,&&运算符在条件检查中用作AND,并且运算符在条件检查中的||工作方式类似于OR

根据您要对脚本执行的操作,表单A && B || C可用于像您的示例一样的条件检查,也可用于链接命令并确保在先前命令成功退出代码0 时执行一系列命令。
这就是为什么经常看到以下命令的原因:
do_something && do_something_else_that_depended_on_something

示例:
apt-get update && apt-get upgrade 如果更新失败,则不执行升级,(在现实世界中有意义......)。

mkdir test && echo "Something" > test/file
echo "Something"仅当mkdir test成功且操作返回退出代码0 时才会执行 该部分。

./configure --prefix=/usr && make && sudo make install
通常在编译作业以将必要的依赖命令链接在一起时找到。

如果您尝试使用if - then - else来实现上面的“链”,那么对于一个简单的任务,您将需要更多的命令和检查(因此需要编写更多的代码 - 更多的错误)。

另外,请记住带有&&|| 的链接命令 由 shell 从左到右读取。您可能需要用括号对命令和条件检查进行分组,以便下一步取决于先前某些命令的成功输出。例如看这个:

root@debian:$ true || true && false;echo $?
1 
#read from left to right
#true OR true=true AND false = false = exit code 1=not success

root@debian:$ true || (true && false);echo $?
0 
# true OR (true AND false)=true OR false = true = exit code 0 = success
Run Code Online (Sandbox Code Playgroud)

或者一个现实生活中的例子:

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 ]] && [[ $c -eq 2 ]];echo $?
1 
#condition $a = true OR condition b = true AND condition $c = false
#=> yields false as read from left to right, thus exit code=1 = not ok

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 && $c -eq 2 ]];echo $?
0 
#vars b and c are checked in a group which returns false, 
#condition check of var a returns true, thus true OR false yields true = exit code 0
Run Code Online (Sandbox Code Playgroud)

请记住,某些命令根据执行的进程返回不同的退出代码,或者根据其操作返回不同的代码(例如,命令 GNU diff,如果两个文件不同,则返回1,否则返回0)。在&&|| 中需要小心处理这些命令 .

也只是为了将所有难题放在一起,请注意使用;operator连接命令。使用某种格式A;B;C,无论 commandAB.