最佳做法是使用$?猛击?


10

当我阅读有关$的答案时?另一个问题浮现在脑海。

是否有使用$的最佳做法?猛击?


让我们举个例子:

我们有一个线性脚本,我想知道所有命令都已正确执行。您是否认为可以调用一个小函数(将其称为“ did_it_work”)以检查错误代码,如果不是,则将其中断。

#!/bin/bash 

function did_it_work {
    code=$1
    if [ "$code" -ne "0" ]
    then
        echo "Error failure: code $code "
        exit 1
    fi
}

dir=some/path

mkdir -p $dir
did_it_work $? 

cd $dir
did_it_work $? 

run_some_command
did_it_work $? 

当然,这种方法意味着我必须手动解决问题(如果有)并重新运行脚本。

您认为这是个好主意还是有其他最佳做法呢?

/谢谢

Answers:


15

一种常见的方式是:

die() {
    IFS=' ' # make sure "$*" is joined with spaces

    # output the arguments if any on stderr:
    [ "$#" -eq 0 ] || printf '%s\n' "$*" 1>&2
    exit 1
}

然后您可以像这样使用它:

mkdir -p some/path || die "mkdir failed with status $?"

或者,如果您希望它包含退出状态,则可以将其更改为:

die() {
    last_exit_status=$?
    IFS=' '
    printf '%s\n' "FATAL ERROR: $* (status $last_exit_status)" 1>&2
    exit 1
}

然后使用它会容易一些:

mkdir -p some/path || die "mkdir failed"

当它失败时,mkdir可能已经发出了一条错误消息,因此第二个消息可能被视为冗余消息,您可以执行以下操作:

mkdir -p some/path || exit   # with the same (failing) exit status as mkdir's
mkdir -p some/path || exit 1 # with exit status 1 always

(或使用die上面的第一个变体,不带参数)

万一您以前从未见过command1 || command2,它会运行command1,如果command1失败,它将运行command2

因此,您可以像“创建目录或终止目录”那样阅读它。

您的示例如下所示:

mkdir -p some/path || die "mkdir failed"
cd some/path || die "cd failed"
some_command || die "some_command failed"

或者,您可以dies在右侧进一步对齐,以使主代码更加明显。

mkdir -p some/path         || die "mkdir failed"
cd some/path               || die "cd failed"
some_command               || die "some_command failed"

或在命令行较长时在以下行上:

mkdir -p some/path ||
  die "mkdir failed"

cd some/path ||
  die "cd failed"

some_command ||
  die "some_command failed"

另外,如果要some/path多次使用该名称,请将其存储在变量中,这样就不必继续键入它,并且可以根据需要轻松地对其进行更改。并且在将变量参数传递给命令时,请确保使用--选项定界符,以使参数以开头的选项不被视为选项-

dir=some/path
mkdir -p -- "$dir"         || die "Cannot make $dir"
cd -P -- "$dir"            || die "Cannot cd to $dir"
some_command               || die "Cannot run some_command"

9

您可以这样重写代码:

#!/bin/bash
function try {
    "$@"
    code=$?
    if [ $code -ne 0 ]
    then
        echo "$1 did not work: exit status $code"
        exit 1
    fi
}

try mkdir -p some/path
try cd some/path
try run_some_command

如果您实际上不需要记录错误代码,而只是记录命令是否成功,则可以try()进一步缩短,如下所示:

function try {
    if ! "$@"
    then
        echo "$1 did not work"
        exit 1
    fi
}

您也可以使用这种格式的代码。<pre> function try {
BillThor 2011年

如果您内联使用此功能,并且不想从真实的方面返回,则可以return $?:内置函数替换。
BillThor 2011年

8

如果您确实想exit出错并且正在使用Bash,那么您还应该考虑set -e。来自help set

-e如果命令以非零状态退出,则立即退出。

当然,这并不能为您提供did_it_work()函数的灵活性,但是,这是一种确保bash脚本在发生错误时停止而又不增加对新函数的调用的简便方法。


set -e是有用的。在正常情况下,有些命令会返回非零值(例如diff)。当我在期望非零回报的脚本中使用set -e时,我会这样做command || true
肖恩·高夫

2
此外,即使您使用set -e,也可以设置一个“异常处理程序”以捕获所有错误trap did_it_work EXIT
吉尔(Gilles)“所以,别再邪恶了”,

1
这是POSIX的一部分,不是bash的特定功能。使用它,但要注意一些陷阱mywiki.wooledge.org/BashFAQ/105
kmkaplan 2014年

@ ShawnJ.Goff我更喜欢做command && true。这样,返回值不会更改。
kmkaplan 2014年

@kmkaplan您的最后评论对我没有任何意义。目的command || true是防止返回非零退出代码时set -e退出脚本command。因为我们需要,它更改了退出代码。如果`命令成功(返回零退出代码),那么唯一的事情command && true就是运行true(返回零退出代码)-这是一个完全的无操作操作。
Tripleee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.