변수에 내가 원하는 것만 포함되어 있고 다른 것은 포함되어 있지 않은지 확인하세요.

변수에 내가 원하는 것만 포함되어 있고 다른 것은 포함되어 있지 않은지 확인하세요.

소스에서 소프트웨어를 빌드하는 스크립트를 작성 중이며 --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똑똑하게 플레이할 수 있으며, 파일 설명자 장치에 쓰면 정의한 규칙에 따라 출력을 분할할 수 있습니다.teeww

입력을 요청하고 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두 개의 스트림을 출력합니다 - >&1sum >&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

단순화/개선된 버전anefm~의답변:

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

관련 정보