如何在“如果”情况下使用圆括号

时间:2019-12-03 16:23:41

标签: bash unix

我正在创建一个bash脚本,并且在里面的某个地方有以下代码:

if [ $# -eq 2 -a (! -r "$2" -o ! -f "$2") ]; then
echo "rvf: bestand \""$2"\" bestaat niet of is onleesbaar" 1>&2
exit 2
fi

当我尝试在脚本中运行它时,出现此错误:

Syntax Error (bash -n):
rvf: line 14: syntax error in conditional expression
rvf: line 14: syntax error near `-a'
rvf: line 14: `if [[ $# -eq 2 -a (! -r "$2" -o ! -f "$2") ]]; then'

'()'在Bash脚本中如何工作?

3 个答案:

答案 0 :(得分:5)

[[不支持-a,并且对于[而言,它被视为已过时且不可移植。使用[的正确解决方案是

if [ "$#" -eq 2 ] && { [ ! -r "$2" ] || [ ! -f "$2" ]; }; then

使用{ ... }而不是( ... )完成分组,以避免创建不必要的子shell。

[[简化为

if [[ "$#" -eq 2 && ( ! -r "$2" || ! -f "$2" ) ]]; then

括号可以用于在[[内部进行分组;作为一种复合命令,与诸如[(这只是test的别名,而不是任何语法)之类的普通命令相比,它使用了单独的解析和评估规则。

无论哪种情况,De Morgan's laws都可以使它重构为更简单的方式:

if [ "$#" -eq 2 ] && ! { [ -r "$2" ] && [ -f "$2" ] }; then

if [[ "$#" -eq 2 && ! ( -r "$2" && -f "$2" ) ]]; then

答案 1 :(得分:4)

这里有多个困惑点。

  • [可以(作为标准的可选XSI扩展)支持(作为单独的单词(表示周围需要有空格),但是the POSIX sh specification将其标记为“过时”(例如-a-o),并建议不要使用它。
  • [[ 确实支持(,但同样,它必须始终是一个单独的单词。

但是根本不这样做。如果您将每个测试都保留为自己的简单命令,并且仅将它们与外壳程序的布尔逻辑支持结合使用,那么您将仅使用功能强大且可移植的功能。

也就是说:

if [ "$#" -eq 2 ] && { [ ! -r "$2" ] || [ ! -f "$2" ]; }; then
  echo "rvf: bestand \"$2\" bestaat niet of is onleesbaar" >&2
  exit 2
fi

答案 2 :(得分:0)

重组您的逻辑。
“不是A还是不是B”只是说“不是(A和B)”的一种更为复杂的方式。

bash中,尝试

if [[ "$#" == 2 ]] && ! [[ -r "$2" && -f "$2" ]]; then

更好

if [[ "$#" == 2 && -r "$2" && -f "$2" ]]
then : all good code
else : nope code
fi

更好,

if [[ "$#" == 2 ]]            # correct args
then if [[ -r "$2" ]]         # is readable
     then if [[ if -f "$2" ]] # is a file
          then echo "all good"
               : do all good stuff
          else echo "'$2' not a file"
               : do not a file stuff
          fi
     else echo "'$2' not readable"
          : do not readable stuff
     fi
else echo "Invalid number of args"
     : do wrong args stuff
fi

清除错误日志记录值得一试。

甚至更好,恕我直言-

if [[ "$#" != 2 ]]
then : wrong args stuff
fi
if [[ ! -r "$2" ]]
then : unreadable stuff
fi
if [[ ! -f "$2" ]] 
then : do not a file stuff
fi

: do all good stuff