捕获编译错误并终止bash脚本

时间:2013-08-24 10:06:59

标签: linux bash

我编写了一个bash脚本,可以从源代码安装3个软件包。脚本非常简单,./configuremakemake install语句写入三次(cd进入源文件夹后)。为了使它看起来更清洁,我将输出重定向到另一个文件,如:./configure >> /usr/local/the_packages/install.log 2>&1

问题是,如果任何一个软件包由于某种原因而无法编译(我甚至不确定是什么原因,因为它一直成功运行到现在 - 这只是我要添加的内容),我'我希望终止脚本和回滚。

我想回滚只是删除prefix=/install/path中指定的目标文件夹,但如何终止脚本呢?

3 个答案:

答案 0 :(得分:2)

也许这样的事情可行:

./configure && make && make install || rm -rf /install/path

答案 1 :(得分:2)

选项1

您可以使用$? bash变量检查脚本运行的返回代码。

moo@cow:~$ false
moo@cow:~$ echo $?
1
moo@cow:~$ true
moo@cow:~$ echo $?
0

选项2

您也可以直接将命令放入if语句中来检查返回码。

moo@cow:~$ if echo a < bad_command; then echo "success"; else echo "fail"; fi
fail

反转返回代码

可以使用!字符反转命令的返回码。

moo@cow:~$ if ! echo a < bad_command; then echo "success"; else echo "fail"; fi
success

示例脚本

为了好玩,我决定根据你的问题编写这个脚本。

#!/bin/bash

_installed=()

do_rollback() {
    echo "rolling back..."
    for i in "${_installed[@]}"; do
        echo "removing $i"
        rm -rf "$i"
    done
}

install_pkg() {
    local _src_dir="$1"
    local _install_dir="$2"
    local _prev_dir="$PWD"
    local _res=0

    # Switch to source directory
    cd "$_src_dir"

    # Try configuring
    if ! ./configure --prefix "$_install_dir"; then
        echo "error: could not configure pkg in $_src_dir"
        do_rollback
        exit 1
    fi

    # Try making
    if ! make; then
        echo "error: could not make pkg in $_src_dir"
        do_rollback
        exit 1
    fi

    # Try installing
    if ! make install; then
        echo "error: could not install pkg from $_src_dir"
        do_rollback
        exit 1
    fi

    # Update installed array
    echo "installed pkg from $_src_dir"
    _installed=("${_installed[@]}" "$_install_dir")

    # Restore previous directory
    cd "$_prev_dir"
}

install_pkg /my/source/directory1 /opt/install/dir1
install_pkg /my/source/directory2 /opt/install/dir2
install_pkg /my/source/directory3 /opt/install/dir3

答案 2 :(得分:1)

分两部分:

要在任何命令返回错误时立即中止脚本,您需要使用set -e。从手册页(BUILTINS部分; set内置的描述):

-e

Exit immediately if a pipeline (which may consist of a single simple command),
a subshell command enclosed in parentheses, or one of the commands executed as
part of a command list enclosed by braces (see SHELL GRAMMAR above) exits with
a non-zero status. The shell does not exit if the command that fails is part of
the command list immediately following a while or until keyword, part of the
test following the if or elif reserved words, part of any command executed in a
&& or ││ list except the command following the final && or ││, any command in a
pipeline but the last, or if the command's return value is being inverted with
!. A trap on ERR, if set, is executed before the shell exits. This option
applies to the shell environment and each subshell environment separately (see
COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before
executing all the commands in the subshell.

你可以用三种方式设置它:将你的shebang线加到#!/bin/bash -e;将脚本称为bash -e scriptname;或者只是在脚本顶部附近使用set -e

问题的第二部分(解释)如何在退出前赶上出口并进行清理。上面引用了答案 - 您想要设置a trap on ERR

为了向您展示这些如何协同工作,这是一个简单的脚本运行。请注意,只要我们有一个非零退出代码,执行就会转移到负责清理的信号处理程序:

james@bodacious:tmp$cat test.sh
#!/bin/bash -e

cleanup() {
  echo I\'m cleaning up!
}

trap cleanup ERR

echo Hello
false
echo World
james@bodacious:tmp$./test.sh
Hello
I'm cleaning up!
james@bodacious:tmp$