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
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 문을 시뮬레이션하는 방법을 설명하고 싶습니다 .
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 B
execute 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
'Programing' 카테고리의 다른 글
+ PHP에서 배열 연산자? (0) | 2020.05.18 |
---|---|
이진 트리에서 두 노드의 가장 낮은 공통 조상을 찾는 방법은 무엇입니까? (0) | 2020.05.18 |
앱 런처 아이콘에 알림 수를 표시하는 방법 (0) | 2020.05.18 |
SQL Server 2005의 한 명령문에서 두 개의 테이블을 업데이트하는 방법은 무엇입니까? (0) | 2020.05.18 |
git stash가 추가 된 파일을 덮어 쓰도록 강제 (0) | 2020.05.18 |