使用函数中止bash脚本

时间:2015-10-13 15:20:15

标签: bash shell

我尝试创建一个可以中断脚本执行的函数(由于致命错误):

quit() {
  echo -e "[ERROR]" | log
  exit 1
}

致电示例:

if [ "$#" -eq 1 ]; then
    # Do stuff
else
    echo -e "function getValue: wrong parameters" | log
    quit
fi

调用函数quit(日志文件中的echo),但脚本继续运行。我读过exit只终止子shell(是真的吗?),这意味着它终止quit函数而不是整个脚本。

目前,我不想在quit方法中使用返回代码,因为它意味着很多代码重构。

有没有办法从quit函数停止脚本?

修改 出现错误的完整示例:

#!/bin/bash

logfile="./testQuit_log"

quit() {
  echo "quit" | log
  exit 1
}

log() {
  read data
  echo -e "$data" | tee -a "$logfile"
}


foo() {
  if [ "$#" -ne 1 ]; then
    echo "foo error" | log
    quit
  fi
  echo "res"
}

rm $logfile

var=`foo p1 p2`
var2=`foo p1`

echo "never echo that!" | log

EDIT2: 切换这些行时它可以正常工作:

var=`foo p1 p2`
var2=`foo p1`

var= foo p1 p2
var2= foo p1

任何解释?这是因为子shell吗?

2 个答案:

答案 0 :(得分:4)

正如问题的评论部分所述,在子shell中使用exit只会退出子shell,并且要解决此限制并不容易。幸运的是,退出子shell或甚至同一个shell中的函数不是最好的想法:

解决在没有异常的语言中处理较低级别(如函数或子shell)上的错误的问题的良好模式是返回错误,而不是直接从较低级别终止程序:

foo() {
   if [ "$#" -ne 1 ]; then
       echo "foo error" | log
       return 1
   else
       echo "res"
       # return 0 is the default
   fi
} 

这允许控制流甚至在出错时返回到最高级别,这通常被认为是一件好事(并且将极其简化调试复杂程序)。您可以使用以下功能:

var=$( foo p1 p2 ) || exit 1
var2=$( foo p1 ) || exit 1

为了清楚起见,如果赋值失败(它不会),则不会输入||分支,但如果命令替换($( ))内的命令行返回非 - 零退出代码。

请注意,$( )应该用于命令替换而不是反引号,请参阅此related question

答案 1 :(得分:2)

查看脚本的调试显示了问题。 var =`foo p1 p2` 强制在子shell中执行foo注意:级别从+增加到{{1}在下面的调用时)脚本的执行在子shell中继续,直到达到++exit 1有效地退出返回主脚本的子shell。

exit 1

您可以利用此优势来完成您想要做的事情。怎么样?当$ bash -x exitstuck.sh + logfile=./testQuit_log + rm ./testQuit_log ++ foo p1 p2 # var=`foo p1 p2` enters subshell '+ -> ++' ++ '[' 2 -ne 1 ']' ++ echo 'foo error' ++ log # log() called ++ read data ++ echo -e 'foo error' ++ tee -a ./testQuit_log ++ quit # quit() called ++ echo quit ++ log ++ read data ++ echo -e quit ++ tee -a ./testQuit_log ++ exit 1 # exit 1 exits subshell, note: '++ -> +' + var='foo error quit' ++ foo p1 ++ '[' 1 -ne 1 ']' ++ echo res + var2=res + log + read data + echo 'never echo that!' + echo -e 'never echo that!' + tee -a ./testQuit_log never echo that! 退出子shell时,它会返回退出代码exit 1。您可以在主脚本中测试退出代码并按预期退出:

1

再次在调试中运行会显示预期的操作:

var=`foo p1 p2`
if [ $? -eq 1 ]; then
    exit
fi
var2=`foo p1`