bash中是否有“goto”声明?

bash中是否有“goto”声明? 我知道这被认为是不好的做法,但我特别需要“转到”。

不,那里没有; 请参阅Bash参考手册中的第3.2.4节“复合命令”了解有关存在的控制结构的信息。 尤其要注意提及breakcontinue ,它不像goto那样灵活,但在Bash中比在某些语言中更灵活,并且可以帮助你实现你想要的。 (无论你想要什么…)

如果你正在使用它跳过一个大脚本的一部分进行debugging(见Karl Nicoll的评论),那么如果false是一个好的select(不知道“false”总是可用的,对我来说它是在/ bin / false) :

 # ... Code I want to run here ... if false; then # ... Code I want to skip here ... fi # ... I want to resume here ... 

当你需要翻译你的debugging代码的时候,就会遇到困难。 “如果错误”构造是相当直接和令人难忘的,但你如何find匹配的fi? 如果您的编辑器允许您阻止缩进,则可以缩进跳过的块(然后在完成时您将要放回原位)。 或者在网上发表评论,但这将是你会记得的事情,我怀疑它会依赖于程序员。

对于某些debugging或演示需求确实可能是有用的。

我发现,朱迪·施密特仿真http://bobcopeland.com/blog/2012/10/goto-in-bash/ helpfull:

 #!/bin/bash # include this boilerplate function jumpto { label=$1 cmd=$(sed -n "/$label:/{:a;n;p;ba};" $0 | grep -v ':$') eval "$cmd" exit } start=${1:-"start"} jumpto $start start: # your script goes here... x=100 jumpto foo mid: x=101 echo "This is not printed!" foo: x=${x:-10} echo x is $x 

结果是:

 $ ./test.sh x is 100 $ ./test.sh foo x is 10 $ ./test.sh mid This is not printed! x is 101 

你可以在bash中使用case来模拟goto:

 #!/bin/bash case bar in foo) echo foo ;& bar) echo bar ;& *) echo star ;; esac 

生产:

 bar star 

虽然其他人已经阐明了在bash中没有直接的goto等价(并提供了函数,循环和break等最接近的替代方法),但我想说明如何使用循环加break来模拟特定types的goto语句。

我发现这种情况最有用的情况是,如果某些条件没有得到满足,我需要返回到一段代码的开头。 在下面的例子中,while循环将永远运行,直到ping停止丢弃数据包到testingIP。

 #!/bin/bash TestIP="8.8.8.8" # Loop forever (until break is issued) while true; do # Do a simple test for Internet connectivity PacketLoss=$(ping "$TestIP" -c 2 | grep -Eo "[0-9]+% packet loss" | grep -Eo "^[0-9]") # Exit the loop if ping is no longer dropping packets if [ "$PacketLoss" == 0 ]; then echo "Connection restored" break else echo "No connectivity" fi done 

还有一个能够达到预期结果的能力:命令trap 。 例如,它可以用于清理目的。

在bash中没有goto

这是一些使用trap只是向后跳转的肮脏的解决方法:)

 #!/bin/bash -e trap ' echo I am sleep 1 echo here now. ' EXIT echo foo goto trap 2> /dev/null echo bar 

输出:

 $ ./test.sh foo I am here now. 

这不应该以这种方式使用,但仅用于教育目的。 这是为什么这个工程:

trap是使用exception处理来实现代码stream的变化。 在这种情况下, trap捕捉任何导致脚本退出的东西。 goto命令不存在,因此抛出一个错误,通常会退出脚本。 这个错误被trap2>/dev/null隐藏了通常会显示的错误信息。

goto的这种实现显然是不可靠的,因为任何不存在的命令(或者任何其他的错误)都会执行相同的trap命令。 特别是,你不能select去哪个标签。


基本上在实际情况下,你不需要任何goto语句,它们是多余的,因为随机调用不同的地方只会让你的代码难以理解。

如果您的代码被多次调用,则考虑使用循环并更改其工作stream程以使用continuebreak

如果您的代码重复它自己,请考虑编写函数并根据需要多次调用它。

如果你的代码需要跳转到基于variables值的特定部分,那么考虑使用case语句。

如果您可以将长代码分成较小的代码,请考虑将其移动到单独的文件中,并从父脚本中调用它们。

如果您正在testing/debugging一个bash脚本,并且只想跳过一个或多个代码段,那么这是一个非常简单的方法,以后也很容易find和删除(不像大多数的方法如上所述)。

 #!/bin/bash echo "Run this" cat >/dev/null <<GOTO_1 echo "Don't run this" GOTO_1 echo "Also run this" cat >/dev/null <<GOTO_2 echo "Don't run this either" GOTO_2 echo "Yet more code I want to run" 

要将脚本恢复正常,只需使用GOTO删除任何行。

我们也可以通过添加一个goto命令作为别名来美化这个解决scheme:

 #!/bin/bash shopt -s expand_aliases alias goto="cat >/dev/null <<" goto GOTO_1 echo "Don't run this" GOTO_1 echo "Run this" goto GOTO_2 echo "Don't run this either" GOTO_2 echo "All done" 

别名通常不会在bash脚本中工作,所以我们需要使用shopt命令来修复它。

如果你想启用/禁用你的goto ,我们需要多一点:

 #!/bin/bash shopt -s expand_aliases if [ -n "$DEBUG" ] ; then alias goto="cat >/dev/null <<" else alias goto=":" fi goto '#GOTO_1' echo "Don't run this" #GOTO1 echo "Run this" goto '#GOTO_2' echo "Don't run this either" #GOTO_2 echo "All done" 

然后你可以在运行脚本之前export DEBUG=TRUE

标签是注释,所以如果禁用我们的goto (通过设置goto到' : 'no-op)不会导致语法错误,但这意味着我们需要在我们的goto语句中引用它们。

每当使用任何types的goto解决scheme时,都需要注意,您跳过的代码不会设置任何后来依赖的variables – 您可能需要将这些定义移动到脚本的顶部,你的goto语句之一。

我find了一种使用函数来做到这一点的方法。

比如说,你有三种select: ABC AB执行一个命令,但是C给了你更多的信息,并把你带到原来的提示。 这可以使用函数来完成。

请注意,由于行包含function demoFunction只是设置函数,因此您需要在该脚本之后调用demoFunction ,以便函数实际运行。

如果需要在shell脚本中“ GOTO ”另一个地方,可以通过编写多个其他函数并调用它们来轻松地进行调整。

 function demoFunction { read -n1 -p "Pick a letter to run a command [A, B, or C for more info] " runCommand case $runCommand in a|A) printf "\n\tpwd being executed...\n" && pwd;; b|B) printf "\n\tls being executed...\n" && ls;; c|C) printf "\n\toption A runs pwd, option B runs ls\n" && demoFunction;; esac } demoFunction