Bash:正确处理错误

时间:2017-07-30 10:02:59

标签: bash shell error-handling

我的bash脚本类似于:

{
  # Try block
  command 1
  command 2
  command 3
} || {
  # Catch errors
  while true; do
  {
    # Try block inside
    # Change parameters for command 1, command 2
    command 1
    command 2
    command 3
    break
  } || {
      # Change parameters and try again
      continue
  }
done
}

或多或少这段代码工作得很好,但是......

由于某种原因,try部分的工作效果与我预期不符。如果我的一些命令没有返回0代码,我认为它失败了,但事实并非如此。

对于某些特定情况,我的command 2会在第一个try块中返回1个代码,但它不会失败并进入catch部分,command 3从此处执行try阻止,就是这样。

这是我的问题:

如何处理bash中的错误?只是玩回报代码?

更新:

原始代码看起来非常类似于: 主要思想是所有3个命令都应该逐个执行,并且所有这些命令都与folder_name有某种关系。

folder_name=my_folder
suffix=0
{
  cd /home/test/
  mkdir $folder_name
  ls -la $folder_name
} || {
    while true; do
      suffix=$(expr $suffix + 1)
      {
        folder_name=$folder_name_$suffix
        cd /home/test/
        mkdir $folder_name
        ls -la $folder_name
        break
      } || {
          continue
      }
    done
}

2 个答案:

答案 0 :(得分:1)

正如您可能已经知道的那样,您可以使用set -e(== set -o errexit)来简化错误处理,方法是让脚本在未经测试的失败时中止。

不幸的是,非exec的子shell的行为与exec-ed shell子行为不同,因为非exec的子shell可以看到它是否经过测试,而exec'd shell子则不能。

因此,这个:

#!/bin/sh -e

echo "EXEC'D SHELL CHILD"
if sh -e <<'EOF'
true(){ echo true; return 0; }
false(){ echo false; return 1; }
true
false 
true
true
EOF
then
    echo SUCCESS
else
    echo FAILED: $?
fi

echo ===========
echo "NON-EXEC'D SUBSHELL"
if (
true(){ echo true; return 0; }
false(){ echo false; return 1; }
true
false 
true
true
)
then
    echo SUCCESS
else
    echo FAILED: $?
fi

输出:

EXEC'D SHELL CHILD
true
false
FAILED: 1
===========
NON-EXEC'D SUBSHELL
true
false
true
true
SUCCESS

(可以随意使用/ bin / bash代替/ bin / sh - 它的行为完全相同)

因此,您可以使用set -e来简化错误处理,但在测试的子shell(或块或函数)中仍需要&&|| return 1,或者您需要使用exec'd贝壳儿童代替。在您的情况下,您可以这样做:

 sh -ec' command 1
  command 2
  command 3' || ...

 {  comman 1 && command 2 && command 3; } || ... 

答案 1 :(得分:1)

我在这里看到两个问题。

使用大括号对命令进行分组时,必须最后是分号(或结束大括号前的换行符)。请参阅docs here

另一方面,您还没有考虑返回代码。您通常会使用[[ $? -eq 0 ]]之类的内容检查返回代码。但在这里,您可以使用&&简单地链接命令。 e.g。

{
  cd /home/test/ && 
  mkdir $folder_name &&
  ls -la $folder_name;
}

但是,以下将做你需要的。

cd /home/test/
prefix=my_folder                                                                                                                                      
suffix=0

folder_name="$prefix"
while true; do
  if [[ -e $folder_name ]]; then
    folder_name="${prefix}_$((++suffix))"
    continue
  fi  
  mkdir "$folder_name"
  if [[ $? -ne 0 ]]; then
    echo "mkdir failed"
    exit 1
  fi  
  break
done