在bash中,“else if”和“elif”的区别是什么?

22

我有以下的shell脚本,它的作用是将几个Java .ear/.war文件简单地部署到JBoss上:

SUCCESS=false
DEPLOY_PATH=/apps/jboss/server/default/deploy

E_NOARGS=75
M_USAGE="usage: $0 {rcm|hcm}"
M_MISSING_RCM="missing: rcm.war file not present"
M_MISSING_HCM="missing: hcm.ear or hcm.war file not present"

if [ -z "$1" ] 
then
  echo $M_USAGE
  exit $E_NOARGS
else
  M_START="deploying $1 ..."
  M_FINISH="finished deploying $1"
fi

until [ -z "$1" ]
do
  echo $M_START 
  case "$1" in
    rcm*)
      # do a hot-deploy of the rcm.war file
      # TODO: test if rcm.war file is present, error out if not
      if [ -e rcm.war ]
      then 
        cp -v rcm.war $DEPLOY_PATH/rcm.war
        SUCCESS=true
      else
        echo $M_MISSING_RCM
      fi
      ;;
    hcm*)
      # do a shutdown, deploy hcm.war, and restart jboss
      ps -ef | awk '/jboss/{print $2}' | xargs kill -s KILL

      HCM_DEPLOYED=false

      if [ -e hcm.ear ]
      then
        cp -v hcm.ear $DEPLOY_PATH/hcm.ear
        HCM_DEPLOYED=true
      else
        if [ -e hcm.war ]
        then
          cp -v hcm.war $DEPLOY_PATH/hcm.war
          HCM_DEPLOYED=true
        else 
          echo $M_MISSING_HCM
        fi
      fi

      if $HCM_DEPLOYED ;
      then
        # TODO: detect the hostname
        nohup /apps/jboss/bin/run.sh -b <HOSTNAME> & &> /dev/null
        SUCCESS=true
      fi
      ;;
    *)
      echo $M_USAGE
      exit 1
  esac
  shift
done

if $SUCCESS ;
then
  echo $M_FINISH
fi

让我感到困惑的是这部分内容:

      if [ -e hcm.ear ]
      then
        cp -v hcm.ear $DEPLOY_PATH/hcm.ear
        HCM_DEPLOYED=true
      else
        if [ -e hcm.war ]
        then
          cp -v hcm.war $DEPLOY_PATH/hcm.war
          HCM_DEPLOYED=true
        else 
          echo $M_MISSING_HCM
        fi
      fi

我似乎无法在远程服务器上正确运行elif [ -e hcm.war ]。远程服务器上运行的是bash 3.2.25版本的redhat(如果这有任何区别)。我怀疑我只是忽略了一些挑剔的bash shell脚本细节。

有什么建议吗?


你是说你无法让 if then ... elif then ... fi 正常工作吗? - Manny D
1
在向这里提问之前,考虑养成通过 http://shellcheck.net/ 运行代码的习惯 - 它可以捕获几个错误。 - Charles Duffy
2个回答

37

根据您发布的代码,它似乎可以工作。

使用elif ... fielse ; if ... fi之间有区别。一个真实的elif ... fi会比你的代码少一个fi

按照您发布的代码,它询问“如果hcm.ear存在,则检查是否有hcm.war”。这符合您的期望吗?另一条逻辑路径测试应该是“如果hcm.ear不存在,则检查是否有hcm.war。”

替代的逻辑路径看起来像:

  if [ -e hcm.ear ] ; then
    cp -v hcm.ear $DEPLOY_PATH/hcm.ear
    HCM_DEPLOYED=true
  elif [ -e hcm.war ] ; then
      cp -v hcm.war $DEPLOY_PATH/hcm.war
      HCM_DEPLOYED=true
  else 
    echo $M_MISSING_HCM
  fi

我希望这能帮上你。


是的,你发布的代码是正确的解释。有时候,团队会想要部署.ear文件,但大多数情况下,我们会为测试目的部署.war文件。我的代码中没有;,所以我会尝试加上看看是否有区别。 - emptyset
1
抱歉,if ... ; thenif ... then 在一行和两行上实际上是相同的。我只是喜欢让我的代码更紧凑,这样你就可以在一页上看到更多内容。感谢您的勾选!祝好运。 - shellter

2

这并不是对问题(elif vs else)的直接回答,但我会进行重构:

HCM_DEPLOYED=true
cp -v hcm.ear "${DEPLOY_PATH}/" || cp -v hcm.war "${DEPLOY_PATH}/" || HCM_DEPLOYED=false
if [ ! ${HCM_DEPLOYED} ]; then
   echo "${M_MISSING_HCM}"
else
    # TODO: detect the hostname
    ...

即使你总是想要执行它们,也应该尝试拷贝,如果一个失败了,就尝试下一个,等等。

此外,你总是希望用引号来包装路径和字符串。否则,包含空格的路径将导致你的应用程序出现故障。


[ ! ${HCM_DEPLOYED} ] 是一个非常糟糕的想法。请记住,[ ! ] 等同于 [ -n "!" ] -- 也就是说,如果没有其他参数,! 将被视为我们要测试其是否为空/非空的字符串。如果您将提出所谓的最佳实践代码,也许应该是 [ -z "$HCM_DEPLOYED" ]! [ -n "$HCM_DEPLOYED" ] - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接