소스에서 소프트웨어를 빌드하는 스크립트를 작성 중이며 --platforms
옵션이 있습니다. 사용자가 여러 항목을 선택할 수 있도록 하고 싶지만 실수를 방지하는 방법을 모르겠습니다.
예:
read -p "For what platforms do you wish to build [mac/win/linux32/linux64/all] ? "
if [[ -n "`echo $REPLY | grep 'win\|mac\|linux32\|linux64\|all`" ]] ; then
echo "ok"
else
echo "not ok"
fi
사용자가 대답하면 linux32
괜찮을 것입니다.
사용자가 대답하면 linux32,mac
괜찮을 것입니다.
사용자가 대답하면 lulz
작동하지 않아야 합니다(그리고 작동하지 않습니다).
사용자가 대답하면 linux32,lulz
작동하지 않습니다. (그렇습니다. 그게 제 질문입니다.)
사용자가 원하는 것을 쉼표로 구분하여 입력할 수 있도록 허용하는 방법을 알고 있는지 궁금합니다. 단, 스크립트에서 제공하는 옵션 중 하나인 경우에만 가능합니다. 따라서 이 경우에는 linux32 linux64 mac win all
.
case
여러 입력을 허용하거나 하나를 추가하는 방법 이 있을까요 elif $REPLY contains anything else than what we want
? awk
어떻게 해야할지 모르겠습니다.
답변1
read
입력을 단어로 나누고 결과를 배열에 저장할 수 있습니다. 변수를 IFS
단어 구분 기호로 설정합니다(문자열이 아닌 단일 문자여야 합니다. 값에 IFS
여러 문자가 포함된 경우 각 문자는 단어 구분 기호입니다).
IFS=, read -a platforms
그런 다음 배열의 각 요소를 지원되는 플랫폼 세트와 비교하여 확인합니다.
for p in "${platforms[@]}"; do
case "$p" in
win|mac|linux32|linux64) :;;
all) platforms=(win mac linux32 linux64);;
*) printf 1>&2 "Unsupported platform: %s\n" "$p"; return 2;;
esac
done
여러 플랫폼을 한 번에 비교할 수도 있습니다. 이는 검사 코드에서 지원되는 플랫폼 세트를 하드코딩하지 않으려는 경우 더 편리합니다.
supported_platforms=(win mac linux32 linux64)
IFS=, read -a platforms
bad_platform_names=($(comm -23 <(printf '%s\n' all "${platforms[@]}" | sort -u) \
<(printf '%s\n' "${supported_platforms[@]}" | sort -u)))
if [[ ${#bad_platform_names[@]} -ne 0 ]]; then
printf "Unsupported platform: %s\n" "${bad_platform_names[@]}"
exit 1
fi
if printf '%s\n' "${platforms[@]}" | grep -qx all; then
platforms=("${supported_platforms[@]}")
fi
또 다른 접근 방식은 내장된 기능을 사용하여 한 번에 하나의 플랫폼을 요청하는 것입니다 select
.
1 물론 원한다면 순수 bash에서 이 작업을 수행할 수도 있습니다.
답변2
이 시도!
buildvar=0
read -p "For what platforms do you wish to build [mac/win/linux32/linux64/all] ? " input
IFS=',' read -a options <<< "$input"
for option in "${options[@]}"
do
case "$option" in
linux32)
buildcommand="linux32" && buildvar=1
;;
linux64)
[ $buildvar == 1 ] && buildcommand="$buildcommand",linux64 || buildcommand="linux64" && buildvar=1
;;
mac)
[ $buildvar == 1 ] && buildcommand="$buildcommand",mac || buildcommand="mac" && buildvar=1
;;
win)
[ $buildvar == 1 ] && buildcommand="$buildcommand",win || buildcommand="win" && buildvar=1
;;
all)
buildcommand="all" && buildvar=1
;;
*)
echo "'$option' was ignored."
;;
esac
done
[ $buildvar == "0" ] && echo "Incorrect input. Default build selected." && buildcommand="default"
echo "=> $buildcommand"
그러면 쉼표로 구분된 옵션 목록이 표시됩니다. 그런 다음 이 목록을 배열로 분할하고 요소를 반복하여 각 요소를 개별적으로 확인한 다음 모든 "좋은" 요소를 단일 변수로 결합합니다.
답변3
예를 들어 다음을 사용하여 입력의 한 줄을 읽고 sed
구분 기호를 줄 바꿈으로 변환할 수 있습니다.
% sed 'y/,/\n/;q' /dev/tty
> this,is,a,single,line
##OUTPUT
this
is
a
single
line
sed
결과는 stdout에 텍스트 파일로 기록되므로 eexplicit x
을 사용한 후속 작업은 grep
쉽고 단일 스트림에서 발생합니다. 실제로, 의식적인 파일 기능을 활용하면 sed
똑똑하게 플레이할 수 있으며, 파일 설명자 장치에 쓰면 정의한 규칙에 따라 출력을 분할할 수 있습니다.tee
w
w
입력을 요청하고 stdout에 대한 허용 가능한 인수 목록과 stderr에 대한 오류의 개행으로 구분된 목록만 출력하는 함수는 다음과 같습니다.
_accept_prompt() (
. /dev/fd/0
IFS=${delim-,}
_prompt "$@" >&2
{ _read_split "$@" |
err=all _grep_ok "$@" |
sed '1{$d}' >&2
} 3>&1 | _grep_ok "$@"
) <<\HELPERS
_prompt() {
cat ; printf ' : '
} <<-PROMPT
Choose from : $(printf "'%s' " "$@")
Enter a '$IFS'-delimited selection below...
PROMPT
_read_split() {
y="y/${IFS}/\n/"
sed -ne "H;x;s/^/Invalid input IGNORED:/;${y};p;x" \
-ne "/all/s/.*/$*/;${y};w /dev/fd/3" -ne q
} </dev/tty
_grep_ok() {
grep -${err+v}xF "$(printf '%s\n' "$@" $err)"
}
HELPERS
나는 그것을 분할했다희망주석 대신 도우미 함수에 더 설명적인 이름을 지정하고 이를 기본 함수에 추가합니다. 따라서 프로세스는 모두 처음 몇 줄에서 발생합니다. 나는 이것을 더 명확하게 할 수 있었으면 좋겠다.
_read_split
두 개의 스트림을 출력합니다 - >&1
sum >&3
. _grep_ok
첫 번째 정의된 행을 가져와 위치 인수에 없는 입력에 포함된 모든 행을 $err
씁니다 .>&2
_accept_prompt
_grep_ok
또한 동시에두 번째 스트림을 선택 하고 입력의 모든 라인 >&3
에 씁니다.>&1 stdout
예위치 _accept_prompt
매개변수.
실행하세요:
% _accept_prompt this is the list of acceptable parameters
###PROMPT
Choose from : 'this' 'is' 'the' 'list' 'of' 'acceptable' 'parameters'
Enter a ','-delimited selection below...
###INPUT
: all,invalid
###STDOUT
this
is
the
list
of
acceptable
parameters
###STDERR
Invalid input IGNORED:
invalid
,
전화할 때 기본 쉼표 구분 기호를 변경할 수 있습니다 . 예를 들면 다음과 같습니다.
delim=? _accept_prompt $args
답변4
read -p 'Enter a comma-separated list of platforms to build for [win/mac/linux32/linux64/all]: ' input
IFS=',' read -a options <<< "$input"
shopt -s extglob
for option in "${options[@]}"; do
case "$option" in
win|mac|linux@(32|64)|all)
buildcommand="${buildcommand:+$buildcommand,}$option"
buildvar=1;;
*)
printf 'Invalid option "%s" ignored.\n' "$option" >&2;;
esac
done
IFS=',' read -a options <<< "$buildcommand"
for option in "${options[@]}"; do
if [[ $option == 'all' ]]; then
buildcommand='all'
break
fi
done
if (( !buildvar )); then
echo 'Incorrect input. Default build selected.' >&2
buildcommand='default'
fi