0

我编写了一个 bash 脚本,它从源代码安装 3 个包。该脚本相当简单,用./configure, make,make install语句编写三次(在cding 到源文件夹之后)。为了使它看起来更干净,我将输出重定向到另一个文件,如下所示:./configure >> /usr/local/the_packages/install.log 2>&1.

问题是,如果任何一个包由于某种原因无法编译(我什至不确定是什么原因,因为它一直成功运行到现在 - 这只是我想添加的东西),我想终止脚本并回滚。

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

4

3 回答 3

3

也许这样的事情可以工作:

./configure && make && make install || rm -rf /install/path
于 2013-08-24T10:24:32.203 回答
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
于 2013-08-24T15:21:22.327 回答
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$
于 2013-08-24T12:34:55.437 回答