Programing

bash에 "goto"문이 있습니까?

lottogame 2020. 5. 18. 08:01
반응형

bash에 "goto"문이 있습니까?


bash에 "goto"문이 있습니까? 나는 그것이 나쁜 습관으로 여겨지지만 특별히 "고토"가 필요하다는 것을 알고 있습니다.


아니 없어; 참조 §3.2.4 "복합 명령의"에 수동 강타 참조 제어 구조에 대한 정보는 어떻게 존재합니다. 특히 break의 언급은와 continue같이 유연하지 goto않지만 일부 언어에서보다 Bash에서 더 유연하며 원하는 것을 달성하는 데 도움이 될 수 있습니다. (무엇이든지 원하는 것은 ...)


디버깅을 위해 큰 스크립트의 일부를 건너 뛰기 위해이 도구를 사용하는 경우 (Karl Nicoll의 의견 참조) false가 좋은 옵션이 될 수있는 경우 ( "false"가 항상 사용 가능한지 확실하지 않은 경우 / bin / false에 있음) :

# ... Code I want to run here ...

if false; then

# ... Code I want to skip here ...

fi

# ... I want to resume here ...

디버깅 코드를 제거해야 할 때 어려움이 있습니다. "거짓이면"구조는 매우 간단하고 기억에 남지만 일치하는 fi를 어떻게 찾습니까? 편집기에서 들여 쓰기를 차단할 수있는 경우 건너 뛴 블록을 들여 쓰기 할 수 있습니다 (완료되면 다시 되돌리려 고 함). 또는 fi 라인에 대한 의견이지만, 기억해야 할 것이 있어야합니다. 프로그래머에게 매우 의존적이라고 생각합니다.


실제로 일부 디버그 또는 데모 요구에 유용 할 수 있습니다.

Bob Copeland 솔루션 http://bobcopeland.com/blog/2012/10/goto-in-bash/ elegant을 발견했습니다 .

#!/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

casebash에서 goto를 시뮬레이션 할 수 있습니다 :

#!/bin/bash

case bar in
  foo)
    echo foo
    ;&

  bar)
    echo bar
    ;&

  *)
    echo star
    ;;
esac

생산 :

bar
star

bash 스크립트를 테스트 / 디버깅하고 있고 하나 이상의 코드 섹션을 건너 뛰려면 단순히 대부분의 방법과 달리 나중에 쉽게 찾아 제거 할 수있는 매우 간단한 방법이 있습니다. 전술 한 바와).

#!/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명령을 별칭으로 추가하여이 솔루션을 구체화 할 수도 있습니다 .

#!/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스크립트를 실행하기 전에 수행 할 수 있습니다 .

레이블은 주석이므로 ' 'no-op goto로 설정 goto하여 '를 비활성화하면 구문 오류가 발생하지 :않지만 goto명령문 에서 인용해야 합니다.

어떤 종류의 goto솔루션을 사용할 때마다 과거에 점프하는 코드가 나중에 의존하는 변수를 설정하지 않도록주의해야합니다. 이러한 정의를 스크립트의 맨 위 또는 바로 위로 이동해야 할 수도 있습니다 당신의 goto진술.


다른 사람들은 이미 gotobash에 직접 동등한 기능 이 없으며 (함수, 루프 및 중단과 같은 가장 가까운 대안을 제공함) 명확하게 설명했지만 루프 플러스 break를 사용하여 특정 유형의 goto 문을 시뮬레이션하는 방법을 설명하고 싶습니다 .

The situation where I find this the most useful is when I need to return to the beginning of a section of code if certain conditions are not met. In the example below, the while loop will run forever until ping stops dropping packets to a test IP.

#!/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

There is one more ability to achieve a desired results: command trap. It can be used to clean-up purposes for example.


There is no goto in bash.

Here is some dirty workaround using trap which jumps only backwards:)

#!/bin/bash -e
trap '
echo I am
sleep 1
echo here now.
' EXIT

echo foo
goto trap 2> /dev/null
echo bar

Output:

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

This shouldn't be used in that way, but only for educational purposes. Here is why this works:

trap is using exception handling to achieve the change in code flow. In this case the trap is catching anything that causes the script to EXIT. The command goto doesn't exist, and hence throws an error, which would ordinarily exit the script. This error is being caught with trap, and the 2>/dev/null hides the error message that would ordinarily be displayed.

This implementation of goto is obviously not reliable, since any non-existent command (or any other error, for that manner), would execute the same trap command. In particular, you cannot choose which label to go-to.


Basically in real scenario you don't need any goto statements, they're redundant as random calls to different places only make your code difficult to understand.

If your code is invoked many times, then consider to use loop and changing its workflow to use continue and break.

If your code repeats it-self, consider writing the function and calling it as many times as you want.

If your code needs to jump into specific section based on the variable value, then consider using case statement.

If you can separate your long code into smaller pieces, consider moving it into separate files and call them from the parent script.


This solution had the following issues:

  • Indiscriminately removes all code lines ending in a :
  • Treates label: anywhere on a line as a label

Here's a fixed (shell-check clean) version:


#!/bin/bash

# GOTO for bash, based upon https://stackoverflow.com/a/31269848/5353461
function goto
{
 local label=$1
 cmd=$(sed -En "/^[[:space:]]*#[[:space:]]*$label:[[:space:]]*#/{:a;n;p;ba};" "$0")
 eval "$cmd"
 exit
}

start=${1:-start}
goto "$start"  # GOTO start: by default

#start:#  Comments can occur after labels
echo start
goto end

  # skip: #  Whitespace is allowed
echo this is usually skipped

# end: #
echo end

This is a small correction of the Judy Schmidt script put up by Hubbbitus.

Putting non-escaped labels in the script was problematic on the machine and caused it to crash. This was easy enough to resolve by adding # to escape the labels. Thanks to Alexej Magura and access_granted for their suggestions.

#!/bin/bash
# include this boilerplate
function goto {  
label=$1
cmd=$(sed -n "/$#label#:/{:a;n;p;ba};" $0 | grep -v ':$')
eval "$cmd"
exit
}

start=${1:-"start"}

goto $start

#start#
echo "start"
goto bing

#boom#
echo boom
goto eof

#bang#
echo bang
goto boom

#bing#
echo bing
goto bang

#eof#
echo "the end mother-hugger..."

A simple searchable goto for the use of commenting out code blocks when debugging.

GOTO=false
if ${GOTO}; then
    echo "GOTO failed"
    ...
fi # End of GOTO
echo "GOTO done"

Result is-> GOTO done


I found out a way to do this using functions.

Say, for example, you have 3 choices: A, B, and C. A and Bexecute a command, but C gives you more info and takes you to the original prompt again. This can be done using functions.

Note that since the line containg function demoFunction is just setting up the function, you need to call demoFunction after that script so the function will actually run.

You can easily adapt this by writing multiple other functions and calling them if you need to "GOTO" another place in your shell script.

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

참고URL : https://stackoverflow.com/questions/9639103/is-there-a-goto-statement-in-bash

반응형