如何在 shell if 语句中表示多个条件?
Posted
技术标签:
【中文标题】如何在 shell if 语句中表示多个条件?【英文标题】:How to represent multiple conditions in a shell if statement? 【发布时间】:2011-04-19 02:12:55 【问题描述】:我想像这样表示多个条件:
if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]
then
echo abc;
else
echo efg;
fi
但是当我执行脚本时,它会显示
syntax error at line 15: `[' unexpected,
第 15 行是显示 if ... 的行。
这种情况有什么问题?我猜()
有问题。
【问题讨论】:
你问的不是shell条件,而是test条件。您示例中的整个表达式由test
([
) 评估,而不是由 shell 评估。 shell 只评估[
的退出状态。
另见***.com/questions/16203088/…
相关:Compound if statements with multiple expressions in Bash
【参考方案1】:
经典技巧(转义元字符):
if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi
我已将对$g
的引用用双引号括起来;一般来说,这是一个很好的做法。严格来说,不需要括号,因为 -a
和 -o
的优先级即使没有它们也可以正确。
请注意,-a
和 -o
运算符是 test
的 POSIX 规范的一部分,也称为 [
,主要是为了向后兼容(因为它们是第 7 版 UNIX 中 test
的一部分,对于例如),但它们被 POSIX 明确标记为“过时”。 Bash(参见 conditional expressions)似乎抢占了 -a
和 -o
的经典和 POSIX 含义,并使用其自己的带参数的替代运算符。
请注意,您可以使用更现代的[[
运算符,但请注意,Bash 和 Korn Shell 中的版本(例如)不必相同。
for g in 1 2 3
do
for c in 123 456 789
do
if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
then echo "g = $g; c = $c; true"
else echo "g = $g; c = $c; false"
fi
done
done
示例运行,在 Mac OS X 上使用 Bash 3.2.57:
g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false
您不需要像使用 [
那样引用 [[
中的变量,因为它不像 [
那样是一个单独的命令。
这不是一个经典的问题吗?
我会这么想的。但是,还有另一种选择,即:
if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi
确实,如果您阅读了autoconf
工具或相关软件包的“便携式外壳”指南,他们推荐使用这种表示法——使用“||
”和“&&
”。我想你甚至可以做到:
if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi
在动作与回声一样微不足道的情况下,这还不错。当要重复的动作块是多行时,重复太痛苦了,最好使用早期版本之一 - 或者您需要将动作包装到在不同 then
块中调用的函数中。
【讨论】:
很高兴知道转义括号有效;顺便说一句:在这种特殊情况下,甚至不需要括号,因为-a
实际上比 -o
具有更高的优先级(与 shell 中的 &&
和 ||
不同 - 但是,inside i> bash
[[ ... ]]
条件, &&
also 的优先级高于 ||
)。如果您想避免使用 -a
和 -o
以获得最大的健壮性和可移植性 - POSIX man page itself 建议 - 您还可以使用 subshells 进行分组:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
很好的解决方案,但我喜欢没有括号和方括号的表格:if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
我有点晚了,但它仍然是一个热门搜索结果,所以我只想指出,使用 &&
或 ||
也更可取,因为它的行为更像其他语言的条件,并让您短路条件。例如:if [ -n "$check_inodes" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]
。这样做,如果check_inodes
为空,您可以避免两次调用stat
,而更大、更复杂的测试条件必须在执行前处理 all 参数(如果您这样做也可能导致错误忘记那种行为)。【参考方案2】:
在 Bash 中:
if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]
【讨论】:
绝对是bash
中的最佳方法。顺便说一句:在这种特殊情况下甚至不需要括号,因为 inside [[ ... ]]
conditionals &&
实际上比 ||
具有更高的优先级 - 不像 在这样的条件之外。
有什么方法可以找出这里匹配的条件吗?是第一个括号中的那个还是另一个?
@Firelord:您需要将条件分成if
/ else
语句,并将then
和fi
之间的代码放入一个函数中以避免重复它。在非常简单的情况下,您可以使用 case
语句和 ;&
fallthrough(在 Bash 4 中)。
两个方括号的作用是什么?
@peter:请看我的回答here、Conditional Constructs in the Bash Manual 和BashFAQ/31。【参考方案3】:
使用/bin/bash
将起作用:
if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
echo "Entered $option"
fi
【讨论】:
【参考方案4】:如果字符串变量中有空格并检查是否存在,请小心。请务必正确引用它们。
if [ ! "$somepath" ] || [ ! "$otherstring" ] || [ ! "$barstring" ] ; then
【讨论】:
当我们在美元符号后使用大括号!!【参考方案5】:$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc
【讨论】:
那是一个无用的子shell。可以改用 ;
。【参考方案6】:
在 bash 中进行字符串比较,您可以使用以下技术。
if [ $var OP "val" ]; then
echo "statements"
fi
例子:
var="something"
if [ $var != "otherthing" ] && [ $var != "everything" ] && [ $var != "allthings" ]; then
echo "this will be printed"
else
echo "this will not be printed"
fi
【讨论】:
【参考方案7】:#!/bin/bash
current_usage=$( df -h | grep 'gfsvg-gfslv' | awk 'print $5' )
echo $current_usage
critical_usage=6%
warning_usage=3%
if [[ $current_usage%? -lt $warning_usage%? ]]; then
echo OK current usage is $current_usage
elif [[ $current_usage%? -ge $warning_usage%? ]] && [[ $current_usage%? -lt $critical_usage%? ]]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi
【讨论】:
欢迎来到 Stack Overflow!这个问题是在寻找一个解释,而不仅仅是为了工作代码。您的回答没有为提问者提供任何见解,可能会被删除。请edit解释导致观察到的症状的原因。【参考方案8】:你也可以链接两个以上的条件:
if [ \( "$1" = '--usage' \) -o \( "$1" = '' \) -o \( "$1" = '--help' \) ]
then
printf "\033[2J";printf "\033[0;0H"
cat << EOF_PRINT_USAGE
$0 - Purpose: upsert qto http json data to postgres db
USAGE EXAMPLE:
$0 -a foo -a bar
EOF_PRINT_USAGE
exit 1
fi
【讨论】:
以上是关于如何在 shell if 语句中表示多个条件?的主要内容,如果未能解决你的问题,请参考以下文章