在if-elif-else语句中使用逻辑ands和ors对脚本进行Bash处理



我搜索并找到了很多if-elif函数的例子,但我发现的似乎都没有包含逻辑and或or运算符。

我在bash脚本中遇到了以下if语句的问题:

#!/bin/bash
BASE="$(basename "${PWD}")"
REPO="$(cut -d/ -f4 <<<"${PWD}")"
if [ "$BASE" = "$REPO" ] -o [ "$BASE" = "" ]
then
echo "[$REPO]"
elif [ "$REPO" = "" ] -a [ "$BASE" != "" ]
then
echo "$BASE"
else
echo "[$REPO] $BASE"
fi

我得到了IF和ELIF的ol'bash: [: too many arguments错误,我似乎无法使其工作。bash脚本是否不喜欢它们的IF语句来获得这种复杂性?期待这种水平的比较似乎并不过于乐观,是吗?

您正在混合[(也称为test)和Bash本身的语法。在[]之间,-a是一个布尔and,但它只是这个特定命令的一个特性。

在一般情况下,只有当command1返回成功时,command1 && command2才会执行command2,类似地,command1 || command2只有在command1返回失败时才执行command2

所以你可以说

if [ condition1 -a condition2 ]

if [ condition1 ] && [ condition2 ]

但无论如何,您的代码看起来实际上需要case。我在遵循脚本的逻辑时遇到了一些问题,但它可以简化很多,因为实际上不存在basename $PWD可以是空字符串的情况(在根目录中,基本名称为/)。此外,在elif分支中,您已经知道$BASE不为空(暂时忽略它永远不会为空的事实),因为如果为空,那么if分支就已经被占用了。

无论如何,假设您想检查我们是在(a)根目录中,还是在四级以下的目录中;或(b)在低于四级的非根目录中;或者(c)在其他地方(这意味着一个五级或五级以上的目录),试试这个。因为case将采用第一个匹配分支(请记住,如果需要,*甚至会匹配上下文中包含斜杠的字符串),所以我不得不稍微重新排序。

case $PWD in
/*/*/*/*/* )   # more than 4  (c)
echo "[$REPO] $BASE" ;;
/ | /*/*/*/* )  # root or exactly 4  (a)
echo "[$REPO"] ;;
*)             # else, less than 4, not root  (b)
echo "$BASE" ;;
esac

您应该使用||&&:

#!/bin/bash
BASE="$(basename "${PWD}")"
REPO="$(cut -d/ -f4 <<<"${PWD}")"
if [ "$BASE" = "$REPO" ] || [ "$BASE" = "" ]
then
echo "[$REPO]"
elif [ "$REPO" = "" ] && [ "$BASE" != "" ]
then
echo "$BASE"
else
echo "[$REPO] $BASE"
fi

问题在于比较,您使用的选项-a(File)在文件存在时返回true,但表达式"$BASE" != ""不是File。

您应该使用逻辑"and"one_answers"or"而不是(-a,-o)选项。

这个代码对我有效:

#!/bin/bash
BASE="$(basename "${PWD}")"
REPO="$(cut -d/ -f4 <<<"${PWD}")"
if [ "$BASE" = "$REPO" ] || [ "$BASE"  = "" ]
then
echo "[$REPO]"
elif [ "$REPO" = "" ] && [ "$BASE" != "" ]
then
echo "$BASE"
else
echo "[$REPO] $BASE"
fi