web-dev-qa-db-ja.com

要素がBash配列に存在するかどうかを確認します

要素がBashの配列内に存在するかどうかを確認する効率的な方法があるかどうか疑問に思っていましたか?私はPythonでできることと似たようなものを探しています:

arr = ['a','b','c','d']

if 'd' in arr:
    do your thing
else:
    do something

Bash 4+のbashに連想配列を使用したソリューションを見てきましたが、別のソリューションがあるかどうか疑問に思っています。

些細な解決策は配列を繰り返すことであることは知っていますが、それは望ましくありません。

58
QuantumLicht

あなたができる:

if [[ " ${arr[*]} " == *" d "* ]]; then
    echo "arr contains d"
fi

これにより、たとえば「a b」を検索した場合に誤検出が発生します。そのサブストリングは結合されたストリング内にありますが、配列要素としてではありません。このジレンマは、選択した区切り文字のすべてで発生します。

最も安全な方法は、要素が見つかるまで配列をループすることです。

array_contains () {
    local seeking=$1; shift
    local in=1
    for element; do
        if [[ $element == $seeking ]]; then
            in=0
            break
        fi
    done
    return $in
}

arr=(a b c "d e" f g)
array_contains "a b" "${arr[@]}" && echo yes || echo no    # no
array_contains "d e" "${arr[@]}" && echo yes || echo no    # yes

すべての要素ではなく、配列名を渡すだけの「よりクリーンな」バージョンです。

array_contains2 () { 
    local array="$1[@]"
    local seeking=$2
    local in=1
    for element in "${!array}"; do
        if [[ $element == $seeking ]]; then
            in=0
            break
        fi
    done
    return $in
}

array_contains2 arr "a b"  && echo yes || echo no    # no
array_contains2 arr "d e"  && echo yes || echo no    # yes
84
glenn jackman

明らかな注意点は別として、もしあなたの配列が実際に上の配列のようであれば、あなたはできる

if [[ ${arr[*]} =~ d ]]
then
  do your thing
else
  do something
fi
27
Steven Penny

1)配列arrを初期化し、要素を追加します

2)SEARCH_STRINGを検索する変数を設定します

3)配列に要素が含まれているかどうかを確認します

arr=()
arr+=('a')
arr+=('b')
arr+=('c')

SEARCH_STRING='b'

if [[ " ${arr[*]} " == *"$SEARCH_STRING"* ]];
then
    echo "YES, your arr contains $SEARCH_STRING"
else
    echo "NO, your arr does not contain $SEARCH_STRING"
fi
14
Marcin Wasiluk

配列要素にスペースが含まれていない場合、別の(おそらく読みやすい)ソリューションは次のようになります。

if echo ${arr[@]} | grep -q -w "d"; then 
    echo "is in array"
else 
    echo "is not in array"
fi
11
jesjimher
array=("Word" "two words") # let's look for "two words"

grepおよびprintfを使用:

(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>

forを使用:

(for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) && <run_your_if_found_command_here>

not_found結果の場合は|| <run_your_if_notfound_command_here>を追加

2
Qwerty

計算時間の点で、反復するよりも速い別の方法があります。わからない。アイデアは、配列を文字列に変換し、切り捨て、新しい配列のサイズを取得することです。

たとえば、「d」のインデックスを見つけるには:

arr=(a b c d)    
temp=`echo ${arr[@]}`
temp=( ${temp%%d*} )
index=${#temp[@]}

これを次のような関数に変えることができます。

get-index() {

    Item=$1
    Array="$2[@]"

    ArgArray=( ${!Array} )
    NewArray=( ${!Array%%${Item}*} )

    Index=${#NewArray[@]}

    [[ ${#ArgArray[@]} == ${#NewArray[@]} ]] && echo -1 || echo $Index

}

次に電話することができます:

get-index d arr

また、3をエコーバックし、次のように割り当て可能です。

index=`get-index d arr`
2
Jasonovich

Bashには組み込みのvalueinarray演算子と=~演算子または[[ "${array[@]" == *"${item}"* ]]表記は混乱を招きます。通常、grepとhere-stringを組み合わせます。

colors=('black' 'blue' 'light green')
if grep -q 'black' <<< "${colors[@]}"
then
    echo 'match'
fi

注意ただし、これは、検索するアイテムが完全に含まれているが別のア​​イテムと等しくない場合に発生する他の多くの回答と同じ誤検出の問題に苦しんでいることに注意してください。

if grep -q 'green' <<< "${colors[@]}"
then
    echo 'should not match, but does'
fi

それがユースケースの問題である場合、おそらく配列のループを回避することはできません。

for color in "${colors[@]}"
do
    if [ "${color}" = 'green' ]
    then
        echo "should not match and won't"
        break
    fi
done

for color in "${colors[@]}"
do
    if [ "${color}" = 'light green' ]
    then
        echo 'match'
        break
    fi
done
2
ssc

FWIW、私が使用したものは次のとおりです。

expr "${arr[*]}" : ".*\<$item\>"

これは、配列項目または検索ターゲットに区切り文字がない場合に機能します。アプリケーションの一般的なケースを解決する必要はありませんでした。

0
Edward Falk