订购功能和条件的正确方法

时间:2019-04-09 21:02:16

标签: bash function conditional-statements

我正在编写一个bash脚本来配置NFS服务器。我能够手动配置NFS服务器,并且该服务器功能齐全。 现在,我想在bash脚本中重现相同的步骤。 我有所有步骤,每一步,shell命令,我都放入了bash函数。 然后,我在一个主要部分中进行函数调用,总共有16个函数。 在主要部分中,我想检查函数的返回值,通常只是“ $?”。值

if [ "function_1" -eq "0" ]; then
    echo "Success"
else
    echo "Failure"
fi

由于有16个函数调用,因此每个函数调用都取决于先前的函数是否成功,因此整个过程变得有点荒唐

if [ "function_1" -eq "0" ]; then
    if [ "function_2" -eq "0" ]; then
        if [ "function_3" -eq "0" ]; then
            if [ "function_..." -eq "0" ]; then
                if [ "function_16" -eq "0" ]; then

我的问题是,这是构建程序的正确方法吗?还是根本不使用函数,而只在主要部分中进行命令验证?

chmod -R 0755 $SHARED_FILE_SYSTEM
if [ "$?" -eq "0" ]; then
    echo "Success"
else
    echo "Failure
fi

3 个答案:

答案 0 :(得分:1)

一个选择是列出功能列表并循环运行它们,如以下Shellcheck-纯净代码所示:

#! /bin/bash -p

# ...

config_functions=(
    function_1
    function_2
    # ...
    function_15
    function_16 )

for cfunc in "${config_functions[@]}" ; do
    if "$cfunc" ; then
        printf 'Success: %s\n' "$cfunc"
    else
        printf 'Failure: %s (%d)\n' "$cfunc" "$?"
    fi
done
  • 不需要显式检查$?,并且Shellcheck会发出警告。参见Shellcheck SC2181
  • 如果要在任何功能失败时立即停止,请将breakexit "$?"放在相应的if的'Failure'分支中。

如果函数采用参数,但仅当参数始终相同时,此方法也可以很好地工作。 (只需将参数添加到循环中的函数调用中。)如果不同的函数采用不同的参数,则效率较低。您可以尝试将完整函数调用放在数组的字符串中,但是处理需要用引号引起来的参数是很棘手的。

请考虑使用诸如ChefPuppetAnsibleSalt之类的配置管理工具来配置NFS服务。与脚本相比,它们具有许多优势。

答案 1 :(得分:1)

如果函数采用参数(而不同的函数采用不同的参数),则简化命令验证的一种方法是使用函数来实现:

#! /bin/bash -p

# ...

# Run a configuration command (passed as arguments) and report if it succeeds or
# fails.  Call 'exit' if the command fails.
function doconf
{
    if "$@" ; then
        printf 'Success: %s\n' "$*"
        return 0
    else
        local status=$?
        printf 'Failure: %s (%d)\n' "$*" "$status"
        exit "$status"
    fi
}

doconf function_1 arg1
doconf function_2 arg2a arg2b
# ...
doconf function_15 arg15a arg15b arg15c arg15d
doconf function_16 arg16a arg16b arg16c

如果您不希望程序在函数失败时立即退出,则可以通过将exit调用放在子shell中来捕获doconf完成的doconf

# ...

(
    doconf function_1 arg1
    doconf function_2 arg2a arg2b
    # ...
    doconf function_15 arg15a arg15b arg15c arg15d
    doconf function_16 arg16a arg16b arg16c
)

# Program execution continues here, even if a `doconf` exits
# ...
  • doconf并不是一个好名字。您可能要更改它。
  • doconf应该进行检查,以确保至少提供了一个参数(命令名称)。

答案 2 :(得分:1)

检查$?是一种反模式。最好直接在if语句中测试命令:

if cmd; then
    ...
fi

进行明确的if检查和错误消息非常麻烦。避免这种情况的常见模式是在命令失败时直接退出,然后依靠该命令打印自己的错误消息。您无需自己打印任何内容。然后,当命令失败时,您可以使用|| return|| exit来纾困,其中a || bif ! a; then b; fi的简写。

function_1 || exit
function_2 || exit
function_3 || exit
...

请注意,returnexit将自动使用$?

如果要在任何命令失败时退出,一个更简单的选择是使用errexit启用set -e标志。这样做,外壳程序将自动退出脚本,而无需插入繁琐的检查。

set -e

function_1
function_2
function_3
...