web-dev-qa-db-ja.com

要素がbashの配列にあるかどうかをテストします

配列にbashの要素があるかどうかをチェックする素晴らしい方法はありますか?

または、数値または文字列が事前定義された定数のセットのいずれかに等しいかどうかを確認する別の方法はありますか?

18
Tgr

Bash 4では、連想配列を使用できます。

# set up array of constants
declare -A array
for constant in foo bar baz
do
    array[$constant]=1
done

# test for existence
test1="bar"
test2="xyzzy"

if [[ ${array[$test1]} ]]; then echo "Exists"; fi    # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi    # doesn't

最初に配列を設定するには、直接割り当てを行うこともできます。

array[foo]=1
array[bar]=1
# etc.

またはこのように:

array=([foo]=1 [bar]=1 [baz]=1)

古い質問ですが、最も簡単な解決策はまだ現れていないと思います:test ${array[key]+_}。例:

declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"

出力:

a is set
b is set

この動作を確認するには、 this を確認してください。

10
tokland

連想配列の要素が存在する(設定されていない)かどうかをテストする方法があります。これは空とは異なります。

isNotSet() {
    if [[ ! ${!1} && ${!1-_} ]]
    then
        return 1
    fi
}

次にそれを使用します:

declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
  echo "${KEY} is not set."
fi
5
Diego F. Durán

配列の内容をgrepにパイプして、エントリが存在するかどうかを確認できます。

_ printf "%s\n" "${mydata[@]}" | grep "^${val}$"
_

エントリのインデックスをgrep -nで取得することもできます。これは、一致の行番号を返します(0から始まるインデックスを取得するには、1を減算することを忘れないでください)これは、非常に大きな配列を除いて、かなり高速です。

_# given the following data
mydata=(a b c "hello world")

for val in a c hello "hello world"
do
           # get line # of 1st matching entry
    ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )

    if [[ -z $ix ]]
    then
        echo $val missing
    else
         # subtract 1.  Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0 
        echo $val found at $(( ix-1 ))
    fi
done

a found at 0
c found at 2
hello missing
hello world found at 3
_

説明:

  • $( ... )は、バックティックを使用してコマンドの出力を変数にキャプチャするのと同じです
  • printfはmydataを1行に1要素出力します
  • (_@_ではなく_*._とともにすべての引用符が必要です。これにより、「hello world」が2行に分割されるのを回避できます)
  • grepは正確な文字列を検索します:_^_と_$_は行の最初と最後に一致します
  • _grep -n_は4:hello worldの形式で行#を返します
  • _grep -m 1_は最初の一致のみを検索します
  • cutは行番号のみを抽出します
  • 返された行番号から1を引きます。

もちろん、減算をコマンドに組み込むことができます。しかし、-1がないかどうかをテストします。

_ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))

if [[ $ix == -1 ]]; then echo missing; else ... fi
_
  • $(( ... ))は整数演算を行います
3
kane

very配列内のデータが限られている場合を除き、ループせずに適切に実行できるとは思いません。

ここに1つの単純なバリアントがあります。これは"Super User"が配列に存在します。しかし、それは"uper Use"は配列にあります。

MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' );
FINDME="Super User"

FOUND=`echo ${MyArray[*]} | grep "$FINDME"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

#
# If you where to add anchors < and > to the data it could work
# This would find "Super User" but not "uper Use"
#

MyArray2=('<Super User>' '<Stack Overflow>' '<Server Fault>' '<Jeff>' );

FOUND=`echo ${MyArray2[*]} | grep "<$FINDME>"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

問題は、配列をループ処理する以外に、(私が考えることができる)アンカーを追加する簡単な方法がないことです。配列に入れる前に追加できない限り...

1
Nifle
#!/bin/bash
function in_array {
  ARRAY=$2
  for e in ${ARRAY[*]}
  do
    if [[ "$e" == "$1" ]]
    then
      return 0
    fi
  done
  return 1
}

my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
  then
    echo "Found"
  else
    echo "Not found"
fi
1
Cong Nguyen