我不明白这个:
脚本:WORKDIR/sh/script.sh
[ -e filename ] \
&& echo filename \
|| [ -e ../filename ] \
&& echo ../filename \
|| { echo 'ERROR: failed to find "filename"' 1>&2 ; exit -1; }
输出:
$ cd WORKDIR/sh
$ ./script.sh
../filename
$ cd WORKDIR
$ sh/script.sh
filename
../filename # <---- WHY????
我的想法:
1
[ -e filename ] \ -> false
&& -> skip this, it is already false
echo filename \ -> don't even try
|| [ -e ../filename ] \ -> true
&& echo ../filename \ -> true
|| -> already true, skip the rest
{ echo 'ERROR: failed to find "filename"' 1>&2 ; exit -1; }
2
[ -e filename ] \ -> true
&& echo filename \ -> true
|| -> already true, skip the rest
[ -e ../filename ] \
&& echo ../filename \
|| { echo 'ERROR: failed to find "filename"' 1>&2 ; exit -1; }
版本:
bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
答案1
&&
并且||
具有相同的优先级,因此:
当一个命令通过时,它将寻找下一个&&
并执行它,即使它不是直接相邻的运算符。你应该绝不在单个命令列表中使用多个这些运算符。如果需要多个,您可以使用 if/then 结构。
$ true && true || echo yes && echo no
no
这与以下内容有很大不同:
if true; then
true
else
echo yes && echo no
fi
$ if true; then true; else echo yes && echo no; fi
$
或者:
$ true && false || echo yes && echo no
yes
no
$ if true; then false; else echo yes && echo no; fi
$
我会将你的构造写为:
if [ -e filename ]; then
echo filename
elif [ -e ../filename ]; then
echo ../filename
else
echo 'ERROR: failed to find "filename"' >&2
exit -1
fi
答案2
我想你希望 bash 这样做:
(A && B) || (C && D) || E
但它实际上是这样做的
(A && B || C) && D || E
其中 D 执行 if任何一个B或C成功。
添加更多分组:
[ -e filename ] && echo filename || {
[ -e ../filename ] && echo ../filename || {
echo 'ERROR: failed to find "filename"' 1>&2
exit -1
}
}
或者
{ [ -e filename ] && echo filename ; } ||
{ [ -e ../filename ] && echo ../filename; } ||
{ echo 'ERROR: failed to find "filename"' 1>&2 ; exit -1; }
if-elif-else
或者使用@Jesse_b 演示的非常清晰易读的风格。
一步一步,这正在发生:
文件名位于当前目录中:
[ -e filename ] \ # test succeeds, status is now 0 && # status is zero, will execute this branch echo filename \ # echo succeeds, status is now 0 || # status is zero, do not execute [ -e ../filename ] \ # not executed && # status is zero, will execute this branch echo ../filename \ # echo succeeds, status is now 0 || # status is zero, do not execute { echo; exit; } # not executed
文件名位于父目录中:
[ -e filename ] \ # test fails, status is now 1 && # status is non-zero, do not execute this branch echo filename \ # not executed || # status is non-zero, will execute this branch [ -e ../filename ] \ # test succeeds, status is now 0 && # status is zero, will execute this branch echo ../filename \ # echo succeeds, status is now 0 || # status is zero, do not execute { echo; exit; } # not executed