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
답변
case
bash에서 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
진술.
답변
다른 사람들은 이미 goto
bash에 직접 동등한 기능 이 없으며 (함수, 루프 및 중단과 같은 가장 가까운 대안을 제공함) 명확하게 설명했지만 루프 플러스 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