web-dev-qa-db-ja.com

Bash配列の値のインデックスを取得します

bashに何かあります

myArray=('red' 'orange' 'green')

そして、私は次のようなことをしたいと思います

echo ${myArray['green']}

この場合、2。これは達成可能ですか?

48
user137369

これはそれを行います:

#!/bin/bash

my_array=(red orange green)
value='green'

for i in "${!my_array[@]}"; do
   if [[ "${my_array[$i]}" = "${value}" ]]; then
       echo "${i}";
   fi
done

明らかに、これを関数(例えばget_index())に変えると-ジェネリックにすることができます

70
Steve Walsh

使用する前に配列を宣言する必要があります

declare -A myArray
myArray=([red]=1 [orange]=2 [green]=3)
echo ${myArray['orange']}
28
Olaf Dietsche

いいえ。bashの整数を持つ単純な配列にのみインデックスを付けることができます。連想配列(bash 4で導入)は、文字列によってインデックスを付けることができます。ただし、特別に構成された連想配列なしでは、要求するタイプの逆ルックアップには提供されません。

$ declare -A myArray
$ myArray=([red]=0 [orange]=1 [green]=2)
$ echo ${myArray[green]}
2
13
chepner

トリッキーな方法も1つあります。

echo ${myArray[@]/green//} | cut -d/ -f1 | wc -w | tr -d ' '

そして、あなたは2を取得します ここに参考文献があります

9
PiotrO

私はその解決策が好きです:

let "n=(`echo ${myArray[@]} | tr -s " " "\n" | grep -n "green" | cut -d":" -f 1`)-1"

変数nには結果が含まれます!

2
user3680055

これは、chepnerが示したように、連想配列を初期化する別の方法です。 declareを明示的に、または-A属性を持つ連想配列をタイプセットする必要があることを忘れないでください。

i=0; declare -A myArray=( [red]=$((i++)) [orange]=$((i++)) [green]=$((i++)) )
echo ${myArray[green]}
2

これにより、値をハードコーディングする必要がなくなり、重複する可能性が低くなります。

追加する値がたくさんある場合は、それらを別々の行に配置すると役立つ場合があります。

i=0; declare -A myArray; 
myArray+=( [red]=$((i++)) )
myArray+=( [orange]=$((i++)) )
myArray+=( [green]=$((i++)) )
echo ${myArray[green]}
2

数字と小文字の配列が必要な場合(メニュー選択の場合など)、次のようなこともできます。

declare -a mKeys_1=( {{0..9},{a..z}} );
i=0; declare -A mKeys_1_Lookup; eval mKeys_1_Lookup[{{0..9},{a..z}}]="$((i++))";

次に実行する場合

echo "${mKeys_1[15]}"
f
echo "${mKeys_1_Lookup[f]}"
15
2
sbts

これは配列に対してのみ機能する可能性があり、

my_array=(red orange green)
echo "$(printf "%s\n" "${my_array[@]}")" | grep -n '^orange$' | sed 's/:orange//'

出力:

2

Tsvファイルでヘッダーインデックスを検索する場合は、

head -n 1 tsv_filename | sed 's/\t/\n/g' | grep -n '^header_name$' | sed 's/:header_name//g'
1
Manish Sharma

別のトリッキーなワンライナー:

_index=$((-1 + 10#0$(IFS=$'\n' echo "${my_array[*]}" | grep --line-number --fixed-strings -- "$value" | cut -f1 -d:)))
_

特徴:

  • スペースを含む要素をサポート
  • 見つからない場合は_-1_を返します

警告:

  • valueが空でないことを要求します
  • 読みにくい

実行順に分類することによる説明:

_IFS=$'\n' echo "${my_array[*]}"
_

配列展開セパレーター(IFS)を改行charに設定し、配列を展開します

_grep --line-number --fixed-strings -- "$value"
_

マッチのgrep:

  • 行番号を表示(_--line-number_または_-n_)
  • 固定文字列を使用します(_--fixed-strings_または_-F_;正規表現を無効にします)
  • _-_で始まる要素を許可する(_--_)

    cut -f1 -d:

行番号のみを抽出します(形式は_<line_num>:<matched line>_です)

_$((-1 + 10#0$(...)))
_

行番号には1のインデックスが付けられ、配列には0のインデックスが付けられるため、1を引く

  • $(...)が一致しない場合:

    • 何も返されず、デフォルトの_0_が使用されます(_10#0_)
  • $(...)が一致する場合:
    • 行番号が存在し、先頭に_10#0_が付いています。すなわち_10#02_、_10#09_、_10#014_など
    • _10#_プレフィックスは、8進数ではなく10進数/ 10進数を強制します


awkgrepおよびbash算術演算の代わりにcutを使用します。

_IFS=$'\n'; awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}" <<< "${my_array[*]}"
_

特徴:

  • スペースを含む要素をサポート
  • 空の要素をサポート
  • サブシェルで開かれたコマンドが少ない

警告:

  • 見つからないときに戻ります

実行順に分類することによる説明:

_IFS=$'\n' [...] <<< "${my_array[*]}"
_

配列展開セパレーター(IFS)を改行charに設定し、配列を展開します

_awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
_

行全体と一致し、0から始まる行番号を出力します

  • _${value//\"/\\\"}_は、_$value_の二重引用符をエスケープバージョンに置き換えます
  • 変数の置換が必要なため、このセグメントは必要以上にエスケープされています
1
srbs

Bash 3.xではもう少し簡潔で機能します。

my_array=(red orange green)
value='green'

for i in "${!my_array[@]}"; do
   [[ "${my_array[$i]}" = "${value}" ]] && break
done

echo $i
0
cmcginty

Zshでできること

xs=( foo bar qux )
echo ${xs[(ie)bar]}

zshparam(1)のサブセクションの添え字フラグを参照してください

0
yaccz

簡単なソリューション:

my_array=(red orange green)
echo ${my_array[*]} | tr ' ' '\n' | awk '/green/ {print NR-1}'
0
Nikhil Gupta