[linux] 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 문을 시뮬레이션하는 방법을 설명하고 싶습니다 .

이것이 가장 유용한 상황은 특정 조건이 충족되지 않으면 코드 섹션의 시작 부분으로 돌아 가야 할 때입니다. 아래 예제에서 while 루프는 ping이 테스트 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


답변

이 솔루션 에는 다음과 같은 문제가있었습니다.

  • 으로 끝나는 모든 코드 줄을 무차별 적으로 제거 :
  • 줄의 label:아무 곳 이나 레이블로 취급

다음은 고정 ( shell-check깨끗한) 버전입니다.


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