如何在 Bash 中不使用 goto 进行处理?

Pil*_*ot6 9 command-line bash

Bash 没有 goto 操作符。我有一个简单的任务,我不知道如何在不转到或添加新 proc 的情况下解决它,这是不可取的。

我有两个条件和一个应该以这种方式工作的代码块:

[条件 1] 如果为真,则运行一些命令并检查 [条件 2];如果 false 执行一段代码。

[条件 2] 如果为真,则不执行相同的代码块;如果为假,则执行相同的块。

它是否可以解决,或者我必须定义一些 proc 并exit在那里使用?我使用了标志变量,但我不喜欢它。

使用 goto 时,它看起来像这样:

[ cond 1 ] || goto label 1
  command
  ...
  command
  [ cond 2 ] && goto label 2

:label 1

block of code

:label 2
Run Code Online (Sandbox Code Playgroud)

类似的东西。

Ser*_*nyy 14

在 shell 脚本中使用分支的典型方法是通过在主代码块之前声明的函数。但是,我认为这里的根本问题是合乎逻辑的问题,而不是 goto。显然label 1是重复的,所以这可以作为函数存在。而且,条件 2 可以变成一个函数,label 1为了可读性也调用:

#!/bin/bash

label1(){
    echo "label 1 function"
}

check_cond2(){
    if ! [ condition2 ]; then
        label1 arg1 arg2
    fi
}

if [ condition1  ]; then

    command
    ...
    command
    check_cond2
else 
    label1
fi

othercommand2
othercommand3
Run Code Online (Sandbox Code Playgroud)

我注意到的是,在这两种情况下,您都有if false exec a block of codeif false exec a block of code,所以一个想法是开始检查这些条件是否都为假。但是,制作类似的东西if ! [ cond1 ] || ! [ cond2 ]会改变分支逻辑。您仍然可以通过查看此帖子的编辑历史记录来查看其伪代码版本。

  • @Pilot6 我认为上游可能误解了流程是什么,不是什么。bash中的函数在当前shell中运行,没有新进程:https://unix.stackexchange.com/a/305360/85039 但是任何非内置命令都是一个进程,无论它是否在函数中运行 (2认同)

Fab*_*bby 12

当我从Windows转移到Linux我的桌面上,我有很多预先存在的.BAT.CMD要转换的文件,我不打算重写逻辑对于他们来说,让我发现了一种方法做一个goto在bash是可行的,因为自行goto function运行sed以去除脚本中不应运行的任何部分,然后对其进行评估。

以下源代码与原始源代码略有修改,以使其更加强大

#!/bin/bash

# BAT / CMD goto function
function goto
{
    label=$1
    cmd=$(sed -n "/^:[[:blank:]][[:blank:]]*${label}/{:a;n;p;ba};" $0 | 
          grep -v ':$')
    eval "$cmd"
    exit
}

apt update

# Just for the heck of it: how to create a variable where to jump to:
start=${1:-"start"}
goto "$start"

: start
goto_msg="Starting..."
echo $goto_msg
# Just jump to the label:
goto "continue"

: skipped
goto_msg="This is skipped!"
echo "$goto_msg"

: continue
goto_msg="Ended..."
echo "$goto_msg"

# following doesn't jump to apt update whereas original does
goto update
Run Code Online (Sandbox Code Playgroud)

正如 Linus Torvalds 所说的那样,我一点也不感到内疚:

来自:Linus Torvalds
主题:Re:2.6.0-test* 的机会吗?
日期:2003 年 1 月 12 日,星期日 11:38:35 -0800(太平洋标准时间)

我认为 goto 很好,而且它们通常比大量缩进更具可读性。如果代码流实际上不是自然缩进的,则尤其如此(在这种情况下,它是,所以我认为使用 goto 并没有比不使用更清晰,但总的来说,goto 的可读性非常好)。

当然,在像 Pascal 这样的愚蠢语言中,标签无法描述,goto 可能很糟糕。但这不是 goto 的错,这是语言设计者的脑残。

代码的原始来源 (经过修改以减少出错的可能性)
引用的来源

  • “这不是 goto 的错,这是语言设计师的脑残” Linus 一如既往地是一位彬彬有礼的绅士。 (4认同)

Byt*_*der 11

您应该将您的block_of_code放入一个函数并使用一些 if/else:

my_function() {
    block of code
    ...
}

if [[ condition 1 ]] ; then
    command
    ...
    command

    if [[ ! condition 2 ]] ; then
        # label 1
        my_function
    fi

else
    # label 1
    my_function
fi

# label 2    
Run Code Online (Sandbox Code Playgroud)