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; fi和A && B || C是不等价的。
使用if A; then B; else C; fi,命令A总是被评估和执行(至少尝试执行它),然后命令B或命令C被评估和执行。
用A && B || C,这是相同的各种命令A和B但对于不同C:命令C被评估并执行,如果任一 A发生故障或 B失败。
在你的例子中,假设你chmod u-r ./myfile,那么,尽管[ -f ./myfile ]成功,你会cat /home/user/myfile
我的建议:使用A && B或A || B随心所欲,这仍然易于阅读和理解,并且没有陷阱。但是,如果您的意思是 if...then...else... 然后使用if A; then B; else C; fi.
如果前一个命令成功执行,运算符&&执行下一个命令(返回退出代码 ($?) 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/fileecho "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,无论 commandA和B.