Check if a variable exists in a list in Bash

后端 未结 17 466
囚心锁ツ
囚心锁ツ 2020-11-29 17:08

I am trying to write a script in bash that check the validity of a user input.
I want to match the input (say variable x) to a list of valid values.

<
相关标签:
17条回答
  • 2020-11-29 17:53

    An alternative solution inspired by the accepted response, but that uses an inverted logic:

    MODE="${1}"
    
    echo "<${MODE}>"
    [[ "${MODE}" =~ ^(preview|live|both)$ ]] && echo "OK" || echo "Uh?"
    

    Here, the input ($MODE) must be one of the options in the regular expression ('preview', 'live', or 'both'), contrary to matching the whole options list to the user input. Of course, you do not expect the regular expression to change.

    0 讨论(0)
  • 2020-11-29 17:55

    If the list is fixed in the script, I like the following the best:

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

    Then use validate "$x" to test if $x is allowed.

    If you want a one-liner, and don't care about whitespace in item names, you can use this (notice -w instead of -x):

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

    Notes:

    • This is POSIX sh compliant.
    • validate does not accept substrings (remove the -x option to grep if you want that).
    • validate interprets its argument as a fixed string, not a regular expression (remove the -F option to grep if you want that).

    Sample code to exercise the function:

    for x in "item 1" "item2" "item 3" "3" "*"; do
        echo -n "'$x' is "
        validate "$x" && echo "valid" || echo "invalid"
    done
    
    0 讨论(0)
  • 2020-11-29 17:55

    Prior answers don't use tr which I found to be useful with grep. Assuming that the items in the list are space delimited, to check for an exact match:

    echo $mylist | tr ' ' '\n' | grep -F -x -q "$myitem"
    

    This will return exit code 0 if the item is in the list, or exit code 1 if it isn't.

    It's best to use it as a function:

    _contains () {  # Check if space-separated list $1 contains line $2
      echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
    }
    
    mylist="aa bb cc"
    
    # Positive check
    if _contains "${mylist}" "${myitem}"; then
      echo "in list"
    fi
    
    # Negative check
    if ! _contains "${mylist}" "${myitem}"; then
      echo "not in list"
    fi
    
    0 讨论(0)
  • 2020-11-29 17:57
    [[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'
    

    or create a function:

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

    to use it:

    contains aList anItem
    echo $? # 0: match, 1: failed
    
    0 讨论(0)
  • 2020-11-29 17:57

    Consider exploiting the keys of associative arrays. I would presume this outperforms both regex/pattern matching and looping, although I haven't profiled it.

    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
    

    Output:

    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 )
    
    0 讨论(0)
提交回复
热议问题