BASH의 목록에 변수가 있는지 확인하는 방법


137

사용자 입력의 유효성을 확인하는 스크립트를 bash로 작성하려고합니다.
입력 (변수 x)을 유효한 값 목록 과 일치시키고 싶습니다 .

내가 지금 생각해 낸 것은 :

for item in $list
do
    if [ "$x" == "$item" ]; then
        echo "In the list"
        exit
    fi
done

내 질문은 더 간단한 방법이 있다면
list.contains(x) 대부분의 프로그래밍 언어 와 같은 것 입니다.

덧셈:
Say list is :

list="11 22 33"

내 코드는 list문자열이 아닌 배열로 취급 되므로 해당 값에 대해서만 메시지를 에코합니다 . 모든 문자열 조작은 유효성 1을 검사 하지만 실패 할 것입니다.

답변:


143
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'

또는 함수를 작성하십시오.

contains() {
    [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}

그것을 사용하려면 :

contains aList anItem
echo $? # 0: match, 1: failed

37
해야[[ $list =~ (^| )$x($| ) ]] && echo 'yes' || echo 'no'
맷비 Aksenov

12
사용자 입력 예를 들어, 정규 표현식의 특수 문자가 포함 된 경우 위양성을 줄 수 있음x=.
글렌 잭맨

4
이렇게하면 오 탐지 / 부정이 발생하지 않습니다 contains () { [[ "$1" =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; }.
skozin

6
더 간결한 해결책 : [[ " $list " =~ " $x " ]] && echo 'yes' || echo 'no'. 공간이 구분자이고 $x공간을 포함하지 않는다고 가정하는 것이 맞습니다.
Tianren Liu

2
"is in"기능을 사용하는 것이 낫다고 생각합니다 isIn(). 따라서 항목을 먼저 매개 변수로 쓸 수 있습니다. 또한 다음 과 같이 echo사용하는 대신 무언가를 할 수 있습니다 exit. [[ $2 =~ (^|[[:space:]])$1($|[[:space:]]) ]] && echo 1 || echo 0따라서 다음 과 같이 함수를 사용할 수 있습니다.result=$(isIn "-t" "-o -t 45") && echo $result
hayj

34

Matvey는 옳지 만 $ x를 인용하고 모든 종류의 "공백"(예 : 줄 바꾸기)을 고려해야합니다.

[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no' 

그래서, 즉

# list_include_item "10 11 12" "2"
function list_include_item {
  local list="$1"
  local item="$2"
  if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
    # yes, list include item
    result=0
  else
    result=1
  fi
  return $result
}

그런 다음 종료

`list_include_item "10 11 12" "12"`  && echo "yes" || echo "no"

또는

if `list_include_item "10 11 12" "1"` ; then
  echo "yes"
else 
  echo "no"
fi

""변수의 경우에 사용해야 합니다.

`list_include_item "$my_list" "$my_item"`  && echo "yes" || echo "no"

3
이 솔루션은 다음 $item과 같은 특수 문자 가 포함되어 있어도 작동합니다 .(그러나 $list변수는 테스트 내부에서 인용해야합니다). 그리고 함수는 더 간단하게 정의 될 수 있습니다 contains () { [[ "$1" =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; }.
skozin

다음 list="aa bb xx cc ff"과 같은 경우에는 작동하지 않습니다 : andx="aa bb"
creativeChips

안녕하세요. bashscript 기본 사항을 배우려고하는데 목록 문자열을 목록으로 구문 분석하고 해당 목록에서 기존 검사를 수행하는 방법을 알고 싶었습니다. 공간을 사용하여 분할하는 것을 이해할 수는 있지만 표현을 완전히 이해할 수는 없습니다. 이 표현의 기본 사항을 Google에 키워드를 제공해 주시겠습니까 $list =~ (^|[[:space:]])"$item"($|[[:space:]])? 또는 시간이 있다면이 표현에 대한 당신의 설명을 듣고 기쁠 것입니다. 참고 : 정규 표현식 (^ 등으로 시작)이라고 생각하지만 = ~의 의미를 모릅니다. P : 나는 전체 설명 싶어요 그래서
알리 마즈

28

IMHO 가장 쉬운 해결책은 원래 문자열 앞에 공백을 추가하고 추가하여 정규 표현식을 확인하는 것입니다. [[ ]]

haystack='foo bar'
needle='bar'

if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
    ...
fi

이것은 바늘을 서브 스트링으로 포함하는 값이있는 값 (예 : 건초 더미)에 대해서는 오 탐지가 아닙니다. foo barbaz .

(이 개념은 JQuery의 hasClass()-Method에서 뻔뻔스럽게 도난 당했습니다.)


4
분리기가 공간이 아닌 경우 솔루션이 더 분명합니다. 그것은 또한 정규식없이 수행 할 수 있습니다 haystack="foo:bar"[[ ":$haystack:" = *:$needle:* ]]
phiphi

25

어때?

echo $list | grep -w $x

출력을 확인하거나 $? 위의 줄을 확인하여 결정을 내릴 수 있습니다.

grep -w 전체 단어 패턴을 확인합니다.


1
것없는 그 이후이 검증 "발" "값이"(목록에서 예) 유효한 경우는 문자열입니다
피르 Farchy

예, 받아 들인 대답과 마찬가지로 그렇습니다. @glennjackman은 효과적인 솔루션을 제공합니다.
f.ardelian

3
grep -q를 사용하여 grep을 조용하게 만들 수 있습니다
Amir

이것은 또한 부분적인 일치를 허용하는데, 이는 사용자가 원하는 것이 아닐 수도 있습니다
carnicer

3
@carnicer는 grep -w $ x를 사용하여 정확히 일치합니다.
user1297406

18

이중 괄호를 사용하는 경우 case 문 외부에서 (* 와일드 카드)를 사용할 수도 있습니다.

string='My string';

if [[ $string == *My* ]]
then
echo "It's there!";
fi

3
간단하고 우아함, +1
João Pereira

14
"My"가 다른 문자열의 하위 문자열 인 경우, 예를 들어 string = 'MyCommand string'인 경우 가양 성이됩니다.
Luke Lee

와일드 카드 ( *My*)는 테스트 오른쪽에 있어야합니다.
Jacob Vanus

8

스크립트에서 값 목록을 하드 코딩해야하는 경우을 사용하여 테스트하는 것이 매우 간단합니다 case. 다음은 요구 사항에 적응할 수있는 간단한 예입니다.

for item in $list
do
    case "$x" in
      item1|item2)
        echo "In the list"
        ;;
      not_an_item)
        echo "Error" >&2
        exit 1
        ;;
    esac
done

런타임에 목록이 배열 변수이면 다른 답변 중 하나가 더 적합합니다.


7

목록이 스크립트에 고정되어 있으면 다음이 가장 좋습니다.

validate() {
    grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}

그런 다음 허용 validate "$x"여부를 테스트 하는 데 사용하십시오 $x.

한 줄짜리를 원하고 항목 이름의 공백을 신경 쓰지 않으면 이것을 사용할 수 있습니다 ( -w대신에 통지 -x).

validate() { echo "11 22 33" | grep -F -q -w "$1"; }

노트:

  • 이것은 POSIX를 sh준수합니다.
  • validate하위 문자열을 허용 하지 않습니다 ( -x원하는 경우 grep 옵션을 제거하십시오 ).
  • validate인수를 정규식이 아닌 고정 문자열로 해석합니다 ( -F원하는 경우 grep 옵션을 제거하십시오 ).

기능을 수행하는 샘플 코드 :

for x in "item 1" "item2" "item 3" "3" "*"; do
    echo -n "'$x' is "
    validate "$x" && echo "valid" || echo "invalid"
done

6

연관 배열 의 키 활용을 고려하십시오 . 프로파일 링하지는 않았지만 정규 표현식 / 패턴 일치 및 루핑 모두를 능가한다고 가정합니다.

declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
    echo -n "$value is "
    # a missing key expands to the null string, 
    # and we've set each interesting key to a non-empty value
    [[ -z "${list[$value]}" ]] && echo -n '*not* '
    echo "a member of ( ${!list[*]} )"
done

산출:

one is a member of ( one two three )
two is a member of ( one two three )
three is a member of ( one two three )
four is *not* a member of ( one two three )

2
... echo -n매개 변수를 창의적으로 사용하여 교체를 단순화 할 수 있습니다 (의존하지 않음 ) do is="${list[$value]+is }"; echo "$value ${is:-is *not* }a member of ( ${!list[*]} )"; done.
Toby Speight

`list = "one two three xyz ..."와 같은 (긴) 목록이 있다면 그러한 배열을 만드는 쉬운 방법이 있습니까?
Ott Toomet

5

echo $LIST | xargs -n1 echo | grep $VALUE아래 그림과 같이 양식을 사용하는 것이 더 쉽다는 것을 알았습니다 .

LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
    ...
fi

이것은 공백으로 구분 된 목록에서 작동하지만 :다음을 수행하여 다른 구분 기호 (예 :)에 적용 할 수 있습니다 .

LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
   ...
fi

"테스트가 작동 하려면 이 사항이 필요합니다.


이 발생할 수 LIST="SOMEITEM1 ITEM2"있지만 진정한도를 반환하는 ITEM1것이 아닌
피르 Farchy

잘 잡았습니다. 부분 일치를 제외하기 위해 grep -e로 예제를 업데이트했습니다.
세바스티앙 피에르

나는 "if"진술의 끝에 추가`가 있다고 믿는다. 올바른 형식은 다음과 같습니다. [-n "`echo $ LIST | xargs -n1 echo | grep -e \"^ $ VALUE $ \ "]
Elad Tabak

3

내 솔루션을 목록에 추가한다고 생각했습니다.

# Checks if element "$1" is in array "$2"
# @NOTE:
#   Be sure that array is passed in the form:
#       "${ARR[@]}"
elementIn () {
    # shopt -s nocasematch # Can be useful to disable case-matching
    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}

# Usage:
list=(11 22 33)
item=22

if elementIn "$item" "${list[@]}"; then
    echo TRUE;
else
    echo FALSE
fi
# TRUE

item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE

1

$ in_list super test me out
NO

$ in_list "super dude" test me out
NO

$ in_list "super dude" test me "super dude"
YES

# How to use in another script
if [ $(in_list $1 OPTION1 OPTION2) == "NO" ]
then
  echo "UNKNOWN type for param 1: Should be OPTION1 or OPTION2"
  exit;
fi

in_list

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH_FOR {ITEM1} {ITEM2} {ITEM3} ...

  e.g. 

  a b c d                    -> NO
  a b a d                    -> YES
  "test me" how "test me"    -> YES

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

if [ "$#" -eq 0 ]; then
  show_help
fi

SEARCH_FOR=$1
shift;

for ITEM in "$@"
do
  if [ "$SEARCH_FOR" == "$ITEM" ]
  then
    echo "YES"
    exit;
  fi
done

echo "NO"

1

TARGET 변수가 '이항'또는 '회귀'일 수 있다고 가정하면 다음과 같습니다.

# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
    echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
    usage
fi

|로 분리하여 더 많은 문자열을 목록에 추가 할 수 있습니다. (파이프) 캐릭터.

egrep을 사용하면 대소 문자를 구분하지 않고 (-i) 쉽게 추가하거나 정규식으로보다 복잡한 시나리오를 확인할 수 있다는 장점이 있습니다.


1

이것은 거의 원래의 제안이지만 거의 1 라이너입니다. 다른 유효한 답변만큼 복잡하지 않으며 bash 버전에 따라 다릅니다 (이전 bash와 함께 사용할 수 있음).

OK=0 ; MP_FLAVOURS="vanilla lemon hazelnut straciatella"
for FLAV in $MP_FLAVOURS ; do [ $FLAV == $FLAVOR ] && { OK=1 ; break; } ; done
[ $OK -eq 0 ] && { echo "$FLAVOR not a valid value ($MP_FLAVOURS)" ; exit 1 ; }

제안서의 길이와 스타일을 모두 향상시킬 수 있다고 생각합니다.


0

너무 길지 않으면; 논리 OR 비교에 따라 평등 사이에 문자열을 묶을 수 있습니다.

if [ $ITEM == "item1" -o $ITEM == "item2" -o $ITEM == "item3" ]; then
    echo In the list
fi 

나는이 정확한 문제가 있었고 위의 내용은 추악한 반면 다른 일반화 된 솔루션보다 진행중인 일이 더 분명합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.