array-is-array.sh (5409B)
1 #!/usr/bin/env bash 2 3 if [[ ! ${BLE_VERSION-} ]]; then 4 source ../../src/benchmark.sh 5 _ble_bash=$((BASH_VERSINFO[0]*10000+BASH_VERSINFO[1]*100+BASH_VERSINFO[2])) 6 fi 7 8 arr1[0]=1234 9 10 #------------------------------------------------------------------------------ 11 # 1 declare +a を用いる方法 12 13 # broken この実装は呼び出し元のローカル変数が見えない。 14 # また現在の関数のローカル変数も見えない。 15 # 更に、bash-4.2 以降でないと動かない。 16 function ble/is-array1 { ! declare -g +a "$1" &>/dev/null; } 17 18 ble-measure 'ble/is-array1 arr1' # 55.20 usec/eval 19 ble-measure 'ble/is-array1 arr2' # 51.80 usec/eval 20 ble-measure 'ble/is-array1 arr' # 51.00 usec/eval 21 22 #------------------------------------------------------------------------------ 23 # 2 compgen -A arrayvar を用いる方法 (不完全) 24 25 # broken 指定した名前で "始まる" 配列があれば真と判定されてしまう。 26 function ble/is-array2 { compgen -A arrayvar "$1" &>/dev/null; } 27 28 ble-measure 'ble/is-array2 arr1' # 1439.90 usec/eval 29 ble-measure 'ble/is-array2 arr2' # 1429.90 usec/eval 30 ble-measure 'ble/is-array2 arr' # 1439.90 usec/eval 31 32 #------------------------------------------------------------------------------ 33 # 3 compgen -A arrayvar を用いる方法 (完全) 34 35 function ble/is-array3 { 36 compgen -A arrayvar "$1" >| "$_ble_util_assign_base" 2>/dev/null || return 1 37 local REPLY; read -r < "$_ble_util_assign_base" 38 [[ $REPLY == "$1" ]] 39 } 40 41 ble-measure 'ble/is-array3 arr1' # 1519.90 usec/eval 42 ble-measure 'ble/is-array3 arr2' # 1469.90 usec/eval 43 ble-measure 'ble/is-array3 arr' # 1549.90 usec/eval 44 45 # 結論として compgen を使うのが一番のボトルネックになっているので、 46 # 一時ファイルに書き出してそれを読み出してチェックするというのは速度的な問題にはならない。 47 # それでも 1.5ms もかかっていることには注意する。例えば 600 の配列を確認すると 1 秒になる。 48 49 #------------------------------------------------------------------------------ 50 # 4 compgen -A arrayvar -X ! を用いる方法 (完全) 51 52 function ble/is-array4 { compgen -A arrayvar -X \!"$1" "$1" 2>/dev/null; } 53 54 ble-measure 'ble/is-array4 arr1' # 1439.90 usec/eval 55 ble-measure 'ble/is-array4 arr2' # 1439.90 usec/eval 56 ble-measure 'ble/is-array4 arr' # 1439.90 usec/eval 57 58 # 実は出力を確認しなくても良い。こちらの方が速い。 59 60 #------------------------------------------------------------------------------ 61 # 4 bash-4.4 ${parameter@a} を用いる方法 62 63 # 2018-07-15 bash-bug メーリングリストで ${param@a} の存在を知った。 64 # bash-4.4 以降の機能の様だ。これを使えば簡単に配列属性を確認できる。 65 66 if ((_ble_bash>=40400)); then 67 function ble/is-array5 { [[ ${!1@a} == *a* ]]; } 68 ble/is-array5 arr1 || echo 'error: 5 arr1' 69 ble/is-array5 arr2 && echo 'error: 5 arr2' 70 ble/is-array5 arr && echo 'error: 5 arr' 71 72 ble-measure 'ble/is-array5 arr1' # 24.80 usec/eval 73 ble-measure 'ble/is-array5 arr2' # 23.30 usec/eval 74 ble-measure 'ble/is-array5 arr' # 23.10 usec/eval 75 fi 76 77 #------------------------------------------------------------------------------ 78 # 5 declare -p の結果を参照する? 79 80 arr3=({1..1000}) 81 function ble/is-array6 { 82 local __name=$1 __def 83 ble/util/assign __def 'declare -p "$name" 2>/dev/null' 84 local rex='^declare -[b-zA-Z]*a' 85 [[ $__def =~ $rex ]] 86 } 87 ble-measure 'ble/is-array6 arr1' # 24.80 usec/eval 88 ble-measure 'ble/is-array6 arr2' # 23.30 usec/eval 89 ble-measure 'ble/is-array6 arr3' # 23.10 usec/eval 90 91 # 2020-04-12 の計測結果 @ chatoyancy bash-5.0 92 # この結果を見ると実は declare -p をしてしまった方が 93 # compgen に頼るよりも高速な様である。 94 # Cygwin では余り違いが見られないが、Cygwin ならば 95 # 恐らく bash-4.4 以降に保たれているので 96 # ${var@a} を使う事ができるのでそれほど気にしなくても良い? 97 # 98 # 481.398 usec/eval: ble/is-array4 arr1 (x500) 99 # 479.936 usec/eval: ble/is-array4 arr2 (x500) 100 # 479.532 usec/eval: ble/is-array4 arr (x500) 101 # 4.422 usec/eval: ble/is-array5 arr1 (x20000) 102 # 4.038 usec/eval: ble/is-array5 arr2 (x20000) 103 # 4.023 usec/eval: ble/is-array5 arr (x20000) 104 # 164.238 usec/eval: ble/is-array6 arr1 (x1000) 105 # 165.432 usec/eval: ble/is-array6 arr2 (x1000) 106 # 165.417 usec/eval: ble/is-array6 arr3 (x1000) 107 # 108 # chatoyancy bash-4.3 109 # 389.800 usec/eval: ble/is-array4 arr1 (x500) 110 # 387.800 usec/eval: ble/is-array4 arr2 (x500) 111 # 389.800 usec/eval: ble/is-array4 arr (x500) 112 # 203.800 usec/eval: ble/is-array6 arr1 (x500) 113 # 201.800 usec/eval: ble/is-array6 arr2 (x500) 114 # 201.800 usec/eval: ble/is-array6 arr3 (x500) 115 # 116 # chatoyancy bash-3.2 117 # 401.200 usec/eval: ble/is-array4 arr1 (x500) 118 # 401.200 usec/eval: ble/is-array4 arr2 (x500) 119 # 401.200 usec/eval: ble/is-array4 arr (x500) 120 # 213.200 usec/eval: ble/is-array6 arr1 (x500) 121 # 211.200 usec/eval: ble/is-array6 arr2 (x500) 122 # 211.200 usec/eval: ble/is-array6 arr3 (x500) 123 # 124 # letsnote2019 bash-4.4 125 # 1478.000 usec/eval: ble/is-array4 arr1 (x100) 126 # 1408.000 usec/eval: ble/is-array4 arr2 (x100) 127 # 1518.000 usec/eval: ble/is-array4 arr (x100) 128 # 1448.000 usec/eval: ble/is-array6 arr1 (x100) 129 # 1468.000 usec/eval: ble/is-array6 arr2 (x100) 130 # 1478.000 usec/eval: ble/is-array6 arr3 (x100)