업데이트 확인, 테마 재설치라는 두 가지 기능이 있는 테마용 도구 스크립트를 만들고 있습니다.
메뉴를 선택하는 코드는 다음과 같습니다.
PS3='Choose an option: '
options=("Check for update" "Reinstall theme")
select opt in "${options[@]}"
do
case $opt in
"Check for update")
echo "Checking update"
;;
"Reinstall theme")
echo "Reinstalling"
;;
*) echo invalid option;;
esac
done
실행할 때 이런 일이 발생합니다
1) Check for update
2) Reinstall theme
Choose an option:
1을 입력하고 Enter를 눌러 업데이트 명령 확인을 실행합니다.
문제는 스크립트 실행이 끝나면 메뉴 대신 "옵션 선택:"이 다시 표시된다는 것입니다. 따라서 메뉴가 없으면 사용자가 선택하기 어려울 수 있습니다(특히 매우 긴 스크립트 이후).
1) Check for update
2) Reinstall theme
Choose an option: 1
Checking update
Choose an option:
그러면 옵션을 실행한 후 메뉴를 다시 표시하려면 어떻게 해야 합니까?
답변1
나는 당신이 정말로 다음과 같은 것을 원하는 것 같아요 :
check_update () {
echo "Checking update"
}
reinstall_theme () {
echo "Reinstalling theme"
}
while true; do
options=("Check for update" "Reinstall theme")
echo "Choose an option:"
select opt in "${options[@]}"; do
case $REPLY in
1) check_update; break ;;
2) reinstall_theme; break ;;
*) echo "What's that?" >&2
esac
done
echo "Doing other things..."
echo "Are we done?"
select opt in "Yes" "No"; do
case $REPLY in
1) break 2 ;;
2) break ;;
*) echo "Look, it's a simple question..." >&2
esac
done
done
첫 번째 명령문을 더 작게 유지하기 위해 작업을 별도의 함수로 분할했습니다 case
. 또한 문 $REPLY
에서 옵션 문자열 대신 사용했습니다. 옵션 문자열 case
이 더 짧고 변경하기로 결정했지만 두 곳에서 업데이트하는 것을 잊어버린 경우에도 깨지지 않기 때문입니다. 또한 스크립트의 후속 호출 PS3
에 영향을 미칠 수 있으므로 건드리지 않기로 결정했습니다 . select
다른 프롬프트를 원하면 한 번 설정하고 그대로 두겠습니다(아마도 PS3="Your choice: "
). 이렇게 하면 여러 문제가 포함된 스크립트에 더욱 통일된 느낌을 줄 수 있습니다.
사용자가 작업을 완료할 때까지 모든 것을 반복하는 외부 루프를 추가했습니다. 첫 번째 문장의 질문을 다시 표시하려면 이 루프가 필요합니다 select
.
그렇지 않으면 스크립트를 중단하는 것 외에는 종료할 수 있는 방법 break
이 case
없습니다.
a의 목적은 select
실제로 스크립트의 메인 이벤트 루프(그 자체)가 되는 것이 아니라 사용자로부터 질문에 대한 답변을 얻는 것입니다. 일반적으로 a select
-는 case
실제로 변수를 설정하거나 함수를 호출하고 계속 진행해야 합니다.
첫 번째 버전에 "exit" 옵션이 포함된 더 짧은 버전 select
:
check_update () {
echo "Checking update"
}
reinstall_theme () {
echo "Reinstalling theme"
}
while true; do
options=("Check for update" "Reinstall theme" "Quit")
echo "Choose an option: "
select opt in "${options[@]}"; do
case $REPLY in
1) check_update; break ;;
2) reinstall_theme; break ;;
3) break 2 ;;
*) echo "What's that?" >&2
esac
done
done
echo "Bye bye!"
답변2
do 루프는 무한하며 select 문은 그 외부에 있습니다. 스크립트는 select 문을 한 번 실행한 다음 do 루프 검사 케이스 $opt에 계속해서 머물러 있습니다. 내 제안은 다음과 같이 사례 설명 뒤에 중단을 추가하는 것입니다.
esac
break
done
그런 다음 전체 스크립트를 계속해서 반복하려면 select 문부터 did 문까지 모든 것을 포함하는 또 다른 루프를 만드세요.
답변3
나는 이 트릭을 사용합니다:
options=("First option" "Second option" "Quit")
PS3="So what? "
select opt in "${options[@]}"
do
case $opt in
"First option")
echo "First option"
;;
"Second option")
echo "Second option"
;;
"Quit")
echo "We are done..."
break
;;
*)
PS3="" # this hides the prompt
echo asdf | select foo in "${options[@]}"; do break; done # dummy select
PS3="So what? " # this displays the common prompt
;;
esac
done
답변4
내 방법을 확인할 수도 있습니다. 간단한 루프를 통해 function
처리합니다.for
for((i=0;i<${#opt[@]};i++));do echo "$((i+1))) ${opt[$i]}";done
내 샘플 코드는 다음과 같습니다.
msg="Choose an option:"
opt=("Check_for_update" "Reinstall_theme")
refresh_the_list(){
echo -e "\n$msg"
for((i=0;i<${#opt[@]};i++))
do
echo "$((i+1))) ${opt[$i]}"
done
}
echo $msg
select i in ${opt[@]}
do
case $i in
${opt[0]})
echo "Checking update"
refresh_the_list;;
${opt[1]})
echo "Reinstalling"
refresh_the_list;;
*)
echo "invalid option"
refresh_the_list;;
esac
done