Differences between revisions 3 and 4
Revision 3 as of 2008-05-08 07:56:00
Size: 3400
Editor: Lhunath
Comment:
Revision 4 as of 2008-05-08 12:52:11
Size: 3757
Editor: GreyCat
Comment: clean up
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
First of all, let's get the terminoligy straight. Bash has no notion of 'lists' or 'sets' or any such. Bash has strings and arrays. Strings are a 'list' of '''characters''', arrays are a 'list' of '''strings'''. If your real question was ''How do I check whether one of my parameters was -v?'' then please see [:BashFAQ/035:FAQ #35] instead.
Line 6: Line 6:
'''NOTE:''' A string can not possibly contain a list of other strings because there is no way to reliably tell where each of those other strings end and the next other string starts. First of all, let's get the terminology straight. Bash has no notion of "lists" or "sets" or any such. Bash has strings and [:BashFAQ/005:arrays]. Strings are a "list" of '''characters''', arrays are a "list" of '''strings'''.

'''NOTE:''' In the general case, a string cannot possibly contain a list of other strings because there is no reliable way to tell where each substring begins and ends.
Line 10: Line 12:
   # Bash
Line 16: Line 19:
   # Bash
Line 17: Line 21:
       pattern=$1        local pattern="$1" element
Line 36: Line 40:
   # Bash 3.0 or higher
Line 37: Line 42:
       pattern=$1        local pattern=$1
       local index list
Line 45: Line 51:
               return                return 0
Line 56: Line 62:
   else
       echo "Jacob is not on the list."
Line 59: Line 67:
If your 'list' is contained in a string, and for some half-witted reason you choose not to heed warning to the note above, you can use the following code to search through 'words' in a string; where a word is defined by any substring that is delimited by whitespace (or more specifically, the characters currently in IFS): If your "list" is contained in a string, and for some half-witted reason you choose not to heed the warnings above, you can use the following code to search through "words" in a string. (The only real excuse for this would be that you're stuck in Bourne shell, which has no arrays.)
Line 61: Line 69:
   # Bourne
Line 62: Line 71:
      [[ $element = $bar ]] && echo "Found $bar."       if test x"$element" = x"$bar"; then
        echo "Found $bar."
      fi
Line 64: Line 75:
Here, a "word" is defined as any substring that is delimited by whitespace (or more specifically, the characters currently in IFS).
Line 65: Line 77:
Here's a shorter way of doing it: Here's a hack that you shouldn't use, but which is presented for the sake of completeness:
Line 67: Line 79:
   # Bash
Line 71: Line 84:
And, if for some reason you don't know the syntax of for well enough, here's how to check your script's parameters for an element. For example, '-v': That same hack, for Bourne shells:
Line 73: Line 86:
   for element; do
      [[ $element = '-v' ]] && echo "Switching to verbose mode."
   done}}}
   # Bourne
   case " $foo " in
      *" $bar "*) echo "Found $bar.";;
   esac}}}
Line 82: Line 96:
Line 91: Line 106:
Since this "feature" of GNU grep is both non-portable and poorly defined, we recommend '''not''' using it. It is simply mentioned here for the sake of completion.
   
Since this "feature" of GNU grep is both non-portable and poorly defined, we recommend '''not''' using it. It is simply mentioned here for the sake of completeness.

Anchor(faq46)

I want to check to see whether a word is in a list (or an element is a member of a set).

If your real question was How do I check whether one of my parameters was -v? then please see [:BashFAQ/035:FAQ #35] instead.

First of all, let's get the terminology straight. Bash has no notion of "lists" or "sets" or any such. Bash has strings and [:BashFAQ/005:arrays]. Strings are a "list" of characters, arrays are a "list" of strings.

NOTE: In the general case, a string cannot possibly contain a list of other strings because there is no reliable way to tell where each substring begins and ends.

The only proper way to do this is to loop over all elements in your array and check them for the element you are looking for. Say what we are looking for is in bar and our list is in the array foo:

  •    # Bash
       for element in "${foo[@]}"; do
          [[ $element = $bar ]] && echo "Found $bar."
       done

If you need to perform this several times in your script, you might want to extract the logic into a function:

  •    # Bash
       isIn() {
           local pattern="$1" element
           shift
       
           for element
           do
               [[ $element = $pattern ]] && return 0
           done
       
           return 1
       }
       
       if isIn "jacob" "${names[@]}"
       then 
           echo "Jacob is on the list."
       fi

Or, if you want your function to return the index at which the element was found:

  •    # Bash 3.0 or higher
       indexOf() {
           local pattern=$1
           local index list
           shift
       
           list=("$@")
           for index in "${!list[@]}"
           do
               [[ ${list[index]} = $pattern ]] && {
                   echo $index
                   return 0
               }
           done
       
           echo -1
           return 1
       }
       
       if index=$(indexOf "jacob" "${names[@]}")
       then
           echo "Jacob is the ${index}th on the list."
       else
           echo "Jacob is not on the list."
       fi

If your "list" is contained in a string, and for some half-witted reason you choose not to heed the warnings above, you can use the following code to search through "words" in a string. (The only real excuse for this would be that you're stuck in Bourne shell, which has no arrays.)

  •    # Bourne
       for element in $foo; do
          if test x"$element" = x"$bar"; then
             echo "Found $bar."
          fi
       done

Here, a "word" is defined as any substring that is delimited by whitespace (or more specifically, the characters currently in IFS).

Here's a hack that you shouldn't use, but which is presented for the sake of completeness:

  •    # Bash
       if [[ " $foo " = *" $bar "* ]]; then
          echo "Found $bar."
       fi

That same hack, for Bourne shells:

  •    # Bourne
       case " $foo " in
          *" $bar "*) echo "Found $bar.";;
       esac

GNU's grep has a \b feature which allegedly matches the edges of words. Using that, one may attempt to replicate the shorter approach used above, but it is fraught with peril:

  •    # Is 'foo' one of the positional parameters? 
       egrep '\bfoo\b' <<<"$@" >/dev/null && echo yes
    
       # This is where it fails: is '-v' one of the positional parameters?
       egrep '\b-v\b' <<<"$@" >/dev/null && echo yes
       # Unfortunately, \b sees "v" as a separate word.
       # Nobody knows what the hell it's doing with the "-".
    
       # Is "someword" in the array 'array'?
       egrep '\bsomeword\b' <<<"${array[@]}"
       # Obviously, you can't use this if someword is '-v'!

Since this "feature" of GNU grep is both non-portable and poorly defined, we recommend not using it. It is simply mentioned here for the sake of completeness.

BashFAQ/046 (last edited 2019-05-20 20:45:14 by GreyCat)