【问题标题】:Trouble with error handling in my first bash script我的第一个 bash 脚本中的错误处理问题
【发布时间】:2017-02-21 16:45:25
【问题描述】:

好的,所以我是 bash 脚本的初学者,我知道这个问题的措辞可能有点尴尬,但我会尽可能清楚!

我编写了以下脚本来在文件夹中创建存储库的备份。脚本如下:

#!/bin/bash

SVNREPO="/var/svn"
TEMP="/var/tmp"
BACKUP="/home/helix/backups"

cd $SVNREPO

if [ $# -eq 0 ]; then
    for REPO in *; do
        ARRAY+=($REPO)
    done
else
    for REPO in $@; do
        ARRAY+=($REPO)
    done
fi

for REPO in ${ARRAY[@]}; do
    svnadmin dump $SVNREPO/$REPO -r HEAD | gzip > $TEMP/$REPO.svn.gzip sd
    cp $TEMP/$REPO.svn.gzip $BACKUP/$REPO.svn.gzip
    rm $TEMP/$REPO.svn.gzip 
done

当不带参数调用该脚本时,此脚本成功生成 'var/svn' 中所有存储库的 .gzip 备份,并创建作为参数调用的特定存储库的 .gzip 备份。太好了!

但是,如果使用与存在的存储库不对应的参数运行脚本,则程序将崩溃并显示错误消息:svnadmin: E000002: Can't open file '/var/svn/ada/format': No such file or directory。我想要实现的是捕捉这个错误并将更用户友好的输出打印到控制台。我一直在尝试使用“陷阱”来做到这一点。

首先我添加了以下行:

trap 'echo ERROR! The repository or repositories that you are trying to backup do not exist!' ERR

...然后我在最后的for循环中将错误推送到/dev/null:

svnadmin dump $SVNREPO/$REPO -r HEAD 2>/dev/null | gzip > $TEMP/$REPO.svn.gzip

我在我所做的地方推送到 /dev/null 文件,因为这是程序出错的地方。但是,该脚本似乎不再起作用。我在这里做错了什么?将2>/dev/null 放在一行中间是否有问题?如果是这样,我该如何重构这段代码,使其不需要行中间的管道?

非常感谢您的帮助,我希望我的问题相当清楚!确认一下,最终的非工作代码如下:

#!/bin/bash

SVNREPO="/var/svn"
TEMP="/var/tmp"
BACKUP="/home/helix/backups"

cd $SVNREPO

if [ $# -eq 0 ]; then
    for REPO in *; do
        ARRAY+=($REPO)
    done
else
    for REPO in $@; do
        ARRAY+=($REPO)
    done
fi

trap 'echo ERROR! The repository or repositories that you are trying to backup do not exist!' ERR

for REPO in ${ARRAY[@]}; do
    svnadmin dump $SVNREPO/$REPO -r HEAD 2>/dev/null | gzip > $TEMP/$REPO.svn.gzip sd
    cp $TEMP/$REPO.svn.gzip $BACKUP/$REPO.svn.gzip
    rm $TEMP/$REPO.svn.gzip 
done

【问题讨论】:

  • 您可以使用if [ -d directory-name ] 测试目录是否存在,或者使用-f 测试文件是否存在。
  • 双引号扩展和变量,它将解决bashfor REPO in "$@"for REPO in "${ARRAY[@]}"中的大部分问题
  • @cdarke 干杯,我可能可以将其合并到我的脚本中以使其正常工作。

标签: linux bash bash-trap dev-null


【解决方案1】:

我不确切知道trap 命令的工作原理,但我会建议另一种可能以另一种方式解决您的问题的方法:

首先,在您的 for 循环之前,添加以下行:

set -o pipefail

这意味着当管道中的任何命令失败时,如果有任何失败,最后一个退出代码 ($?) 将包含错误代码。

在您拨打svnadmin 之后,我建议您添加以下内容:

if [ $? -ne 0 ]; then
    echo "ERROR! Received error code $? for repository '$REPO'."
    continue
fi

您当然可以根据自己的喜好更改错误消息。功能应该很清楚:如果svnadminbzip 失败,它将打印一条错误消息并继续for 循环中的下一项。

希望这会有所帮助。

【讨论】:

  • 我试过了,不管参数是否正确、不正确或没有参数,它都会出错。
【解决方案2】:

使用@cdarke 检查文件是否存在的建议,我现在可以使用以下代码:

#!/bin/bash

SVNREPO="/var/svn"
TEMP="/var/tmp"
BACKUP="/home/helix/backups"

cd $SVNREPO

if [ $# -eq 0 ]; then
    for REPO in *; do
        ARRAY+=($REPO)
    done
else
    for REPO in $@; do
        ARRAY+=($REPO)
    done
fi

for REPO in ${ARRAY[@]}; do
    if [ -f $SVNREPO/$REPO/format ]; then
        vnadmin dump $SVNREPO/$REPO -r HEAD 2>/dev/null | gzip > $TEMP/$REPO.svn.gzip
        cp $TEMP/$REPO.svn.gzip $BACKUP/$REPO.svn.gzip
        rm $TEMP/$REPO.svn.gzip 
    else
        echo ERROR! The repository $REPO does not exist. No backup has been made for this argument.
    fi
done

【讨论】:

  • 如果您找到了问题的答案,您应该通过单击答案旁边的复选标记来接受答案(甚至是您自己的答案)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多