配列を作成する関数があり、配列を呼び出し元に返したい:
create_array() {
local my_list=("a", "b", "c")
echo "${my_list[@]}"
}
my_algorithm() {
local result=$(create_array)
}
これにより、拡張文字列のみが取得されます。グローバルを使用せずにmy_listを「返す」にはどうすればよいですか?
グローバルの何が問題になっていますか?
配列を返すことは実際には実用的ではありません。落とし穴はたくさんあります。
そうは言っても、変数に同じ名前を付けても問題ない場合に機能する1つの手法を次に示します。
$ f () { local a; a=(abc 'def ghi' jkl); declare -p a; }
$ g () { local a; eval $(f); declare -p a; }
$ f; declare -p a; echo; g; declare -p a
declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found
declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found
declare -p
コマンド(f()
のコマンドを除く)は、デモの目的で配列の状態を表示するために使用されます。f()
では、配列を返すメカニズムとして使用されます。
配列に別の名前を付ける必要がある場合、次のようなことができます。
$ g () { local b r; r=$(f); r="declare -a b=${r#*=}"; eval "$r"; declare -p a; declare -p b; }
$ f; declare -p a; echo; g; declare -p a
declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found
-bash: declare: a: not found
declare -a b='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found
Bashバージョン4.3以降では、 nameref を使用して、呼び出し元が配列名を渡し、呼び出し先が名前付き配列を使用して名前付き配列間接的に。
#!/usr/bin/env bash
create_array() {
local -n arr=$1 # use nameref for indirection
arr=(one "two three" four)
}
use_array() {
local my_array
create_array my_array # call function to populate the array
echo "inside use_array"
declare -p my_array # test the array
}
use_array # call the main function
出力を生成します。
inside use_array
declare -a my_array=([0]="one" [1]="two three" [2]="four")
関数で既存の配列を更新することもできます。
update_array() {
local -n arr=$1 # use nameref for indirection
arr+=("two three" four) # update the array
}
use_array() {
local my_array=(one)
update_array my_array # call function to update the array
}
コマンド置換$()
は呼び出されている関数の標準出力を取得する必要がないため、これはよりエレガントで効率的なアプローチです。 。また、関数が複数の出力を返す場合にも役立ちます。出力の数と同じ数の名前参照を単純に使用できます。
Bash Manual がnamerefについて述べていることは次のとおりです。
変数にnameref属性を割り当てるには、declareまたはlocal組み込みコマンド(Bash Builtinsを参照)の-nオプションを使用して、namerefまたは別の変数への参照を作成します。これにより、変数を間接的に操作できます。 nameref変数の参照、割り当て、設定解除、または属性の変更(nameref属性自体の使用または変更以外)が行われるたびに、実際には、nameref変数の値で指定された変数に対して操作が実行されます。 namerefは一般的にシェル関数内で使用され、関数に引数として渡される名前の変数を参照します。たとえば、変数名が最初の引数としてシェル関数に渡された場合、次を実行します
関数内のdeclare -n ref = $ 1は、値が最初の引数として渡された変数名であるnameref変数refを作成します。 refへの参照と割り当て、およびその属性の変更は、名前が$ 1として渡された変数への参照、割り当て、および属性の変更として扱われます。
Bashはデータ構造を戻り値として渡すことはできません。戻り値は、0〜255の終了ステータスである必要があります。ただし、必要に応じて、コマンドまたはプロセス置換を使用して、コマンドをevalステートメントに渡すことができます。
これはめったにトラブルの価値はありません、私見。 Bashでデータ構造を渡す必要がある場合は、グローバル変数を使用します-それが目的です。ただし、何らかの理由でこれを行いたくない場合は、位置パラメータの観点から考えてください。
例は、グローバル変数の代わりに位置パラメータを使用するように簡単に書き直すことができます。
use_array () {
for idx in "$@"; do
echo "$idx"
done
}
create_array () {
local array=("a" "b" "c")
use_array "${array[@]}"
}
ただし、これにより、ある程度の不必要な複雑さが生じます。通常、bash関数は、副作用のあるプロシージャのように処理し、順番に呼び出すと最も効果的に機能します。
# Gather values and store them in FOO.
get_values_for_array () { :; }
# Do something with the values in FOO.
process_global_array_variable () { :; }
# Call your functions.
get_values_for_array
process_global_array_variable
心配しているのがグローバル名前空間を汚染している場合、 nset builtin を使用して、完了後にグローバル変数を削除することもできます。元の例を使用して、my_listを(localキーワードを削除して)グローバルにし、unset my_list
をmy_algorithmの末尾に移動して、自分の後をクリーンアップします。
Matt McClureが開発した手法を使用します。 http://notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html
グローバル変数を回避することは、パイプ内で関数を使用できることを意味します。以下に例を示します。
#!/bin/bash
makeJunk()
{
echo 'this is junk'
echo '#more junk and "b@d" characters!'
echo '!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'"'"
}
processJunk()
{
local -a arr=()
# read each input and add it to arr
while read -r line
do
arr[${#arr[@]}]='"'"$line"'" is junk';
done;
# output the array as a string in the "declare" representation
declare -p arr | sed -e 's/^declare -a [^=]*=//'
}
# processJunk returns the array in a flattened string ready for "declare"
# Note that because of the pipe processJunk cannot return anything using
# a global variable
returned_string=`makeJunk | processJunk`
# convert the returned string to an array named returned_array
# declare correctly manages spaces and bad characters
eval "declare -a returned_array=${returned_string}"
for junk in "${returned_array[@]}"
do
echo "$junk"
done
出力は次のとおりです。
"this is junk" is junk
"#more junk and "b@d" characters!" is junk
"!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'" is junk
元のソリューションではそれほど遠くありませんでした。いくつかの問題があり、カンマを区切り記号として使用し、返されたアイテムをリストにキャプチャできませんでした。これを試してください:
my_algorithm() {
local result=( $(create_array) )
}
create_array() {
local my_list=("a" "b" "c")
echo "${my_list[@]}"
}
埋め込みスペースに関するコメントを考慮すると、IFS
を使用したいくつかの微調整で解決できます。
my_algorithm() {
oldIFS="$IFS"
IFS=','
local result=( $(create_array) )
IFS="$oldIFS"
echo "Should be 'c d': ${result[1]}"
}
create_array() {
IFS=','
local my_list=("a b" "c d" "e f")
echo "${my_list[*]}"
}
このアプローチには、次の3つのステップが含まれます。
myVar="$( declare -p myArray )"
declare -p
_ステートメントの出力を使用して、配列を再作成できます。たとえば、_declare -p myVar
_の出力は次のようになります。declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
${myVar#*=}
_例1-関数から配列を返す
_#!/bin/bash
# Example 1 - return an array from a function
function my-fun () {
# set up a new array with 3 fields - note the whitespaces in the
# 2nd (2 spaces) and 3rd (2 tabs) field
local myFunArray=( "1st field" "2nd field" "3rd field" )
# show its contents on stderr (must not be output to stdout!)
echo "now in $FUNCNAME () - showing contents of myFunArray" >&2
echo "by the help of the 'declare -p' builtin:" >&2
declare -p myFunArray >&2
# return the array
local myVar="$( declare -p myFunArray )"
local IFS=$'\v';
echo "${myVar#*=}"
# if the function would continue at this point, then IFS should be
# restored to its default value: <space><tab><newline>
IFS=' '$'\t'$'\n';
}
# main
# call the function and recreate the array that was originally
# set up in the function
eval declare -a myMainArray="$( my-fun )"
# show the array contents
echo ""
echo "now in main part of the script - showing contents of myMainArray"
echo "by the help of the 'declare -p' builtin:"
declare -p myMainArray
# end-of-file
_
例1の出力:
_now in my-fun () - showing contents of myFunArray
by the help of the 'declare -p' builtin:
declare -a myFunArray='([0]="1st field" [1]="2nd field" [2]="3rd field")'
now in main part of the script - showing contents of myMainArray
by the help of the 'declare -p' builtin:
declare -a myMainArray='([0]="1st field" [1]="2nd field" [2]="3rd field")'
_
例2-配列を関数に渡す
_#!/bin/bash
# Example 2 - pass an array to a function
function my-fun () {
# recreate the array that was originally set up in the main part of
# the script
eval declare -a myFunArray="$( echo "$1" )"
# note that myFunArray is local - from the bash(1) man page: when used
# in a function, declare makes each name local, as with the local
# command, unless the ‘-g’ option is used.
# IFS has been changed in the main part of this script - now that we
# have recreated the array it's better to restore it to the its (local)
# default value: <space><tab><newline>
local IFS=' '$'\t'$'\n';
# show contents of the array
echo ""
echo "now in $FUNCNAME () - showing contents of myFunArray"
echo "by the help of the 'declare -p' builtin:"
declare -p myFunArray
}
# main
# set up a new array with 3 fields - note the whitespaces in the
# 2nd (2 spaces) and 3rd (2 tabs) field
myMainArray=( "1st field" "2nd field" "3rd field" )
# show the array contents
echo "now in the main part of the script - showing contents of myMainArray"
echo "by the help of the 'declare -p' builtin:"
declare -p myMainArray
# call the function and pass the array to it
myVar="$( declare -p myMainArray )"
IFS=$'\v';
my-fun $( echo "${myVar#*=}" )
# if the script would continue at this point, then IFS should be restored
# to its default value: <space><tab><newline>
IFS=' '$'\t'$'\n';
# end-of-file
_
例2の出力:
_now in the main part of the script - showing contents of myMainArray
by the help of the 'declare -p' builtin:
declare -a myMainArray='([0]="1st field" [1]="2nd field" [2]="3rd field")'
now in my-fun () - showing contents of myFunArray
by the help of the 'declare -p' builtin:
declare -a myFunArray='([0]="1st field" [1]="2nd field" [2]="3rd field")'
_
function Query() {
local _tmp=`echo -n "$*" | mysql 2>> zz.err`;
echo -e "$_tmp";
}
function StrToArray() {
IFS=$'\t'; set $1; for item; do echo $item; done; IFS=$oIFS;
}
sql="SELECT codi, bloc, requisit FROM requisits ORDER BY codi";
qry=$(Query $sql0);
IFS=$'\n';
for row in $qry; do
r=( $(StrToArray $row) );
echo ${r[0]} - ${r[1]} - ${r[2]};
done
[注:この答え for 私にとって意味のない理由)の編集として以下が拒否されました (編集はnotであるため、投稿の著者に対応することを意図していました!)、私はそれを別のものにする提案を取っています回答。]
Steve ZobellによるMatt McClureの手法の適応 のより単純な実装では、bashビルトインを使用します( version == 4 )readarray
提案どおり) RastaMatt により、実行時に配列に変換できる配列の表現を作成します。 (readarray
とmapfile
の両方が同じコードに名前を付けていることに注意してください。)グローバルを回避し(パイプで関数を使用できるようにする)、厄介な文字を処理します。
より完全に開発された(たとえば、よりモジュール化された)が、まだちょっとおもちゃの例については、 bash_pass_arrays_between_functions を参照してください。以下に、簡単に実行可能ないくつかの例を示します。外部リンクに関するモデレーターのb!tchingを回避するためにここに記載されています。
次のブロックを切り取り、bashターミナルに貼り付けて/tmp/source.sh
および/tmp/junk1.sh
を作成します。
FP='/tmp/source.sh' # path to file to be created for `source`ing
cat << 'EOF' > "${FP}" # suppress interpretation of variables in heredoc
function make_junk {
echo 'this is junk'
echo '#more junk and "b@d" characters!'
echo '!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'"'"
}
### Use 'readarray' (aka 'mapfile', bash built-in) to read lines into an array.
### Handles blank lines, whitespace and even nastier characters.
function lines_to_array_representation {
local -a arr=()
readarray -t arr
# output array as string using 'declare's representation (minus header)
declare -p arr | sed -e 's/^declare -a [^=]*=//'
}
EOF
FP1='/tmp/junk1.sh' # path to script to run
cat << 'EOF' > "${FP1}" # suppress interpretation of variables in heredoc
#!/usr/bin/env bash
source '/tmp/source.sh' # to reuse its functions
returned_string="$(make_junk | lines_to_array_representation)"
eval "declare -a returned_array=${returned_string}"
for elem in "${returned_array[@]}" ; do
echo "${elem}"
done
EOF
chmod u+x "${FP1}"
# newline here ... just hit Enter ...
/tmp/junk1.sh
を実行します:出力は
this is junk
#more junk and "b@d" characters!
!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'
注lines_to_array_representation
は空白行も処理します。次のブロックをbashターミナルに貼り付けてみてください。
FP2='/tmp/junk2.sh' # path to script to run
cat << 'EOF' > "${FP2}" # suppress interpretation of variables in heredoc
#!/usr/bin/env bash
source '/tmp/source.sh' # to reuse its functions
echo '`bash --version` the normal way:'
echo '--------------------------------'
bash --version
echo # newline
echo '`bash --version` via `lines_to_array_representation`:'
echo '-----------------------------------------------------'
bash_version="$(bash --version | lines_to_array_representation)"
eval "declare -a returned_array=${bash_version}"
for elem in "${returned_array[@]}" ; do
echo "${elem}"
done
echo # newline
echo 'But are they *really* the same? Ask `diff`:'
echo '-------------------------------------------'
echo 'You already know how to capture normal output (from `bash --version`):'
declare -r PATH_TO_NORMAL_OUTPUT="$(mktemp)"
bash --version > "${PATH_TO_NORMAL_OUTPUT}"
echo "normal output captured to file @ ${PATH_TO_NORMAL_OUTPUT}"
ls -al "${PATH_TO_NORMAL_OUTPUT}"
echo # newline
echo 'Capturing L2AR takes a bit more work, but is not onerous.'
echo "Look @ contents of the file you're about to run to see how it's done."
declare -r RAW_L2AR_OUTPUT="$(bash --version | lines_to_array_representation)"
declare -r PATH_TO_COOKED_L2AR_OUTPUT="$(mktemp)"
eval "declare -a returned_array=${RAW_L2AR_OUTPUT}"
for elem in "${returned_array[@]}" ; do
echo "${elem}" >> "${PATH_TO_COOKED_L2AR_OUTPUT}"
done
echo "output from lines_to_array_representation captured to file @ ${PATH_TO_COOKED_L2AR_OUTPUT}"
ls -al "${PATH_TO_COOKED_L2AR_OUTPUT}"
echo # newline
echo 'So are they really the same? Per'
echo "\`diff -uwB "${PATH_TO_NORMAL_OUTPUT}" "${PATH_TO_COOKED_L2AR_OUTPUT}" | wc -l\`"
diff -uwB "${PATH_TO_NORMAL_OUTPUT}" "${PATH_TO_COOKED_L2AR_OUTPUT}" | wc -l
echo '... they are the same!'
EOF
chmod u+x "${FP2}"
# newline here ... just hit Enter ...
/tmp/junk2.sh
@コマンドラインを実行します。出力は私のものに似ているはずです:
`bash --version` the normal way:
--------------------------------
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
`bash --version` via `lines_to_array_representation`:
-----------------------------------------------------
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
But are they *really* the same? Ask `diff`:
-------------------------------------------
You already know how to capture normal output (from `bash --version`):
normal output captured to file @ /tmp/tmp.Ni1bgyPPEw
-rw------- 1 me me 308 Jun 18 16:27 /tmp/tmp.Ni1bgyPPEw
Capturing L2AR takes a bit more work, but is not onerous.
Look @ contents of the file you're about to run to see how it's done.
output from lines_to_array_representation captured to file @ /tmp/tmp.1D6O2vckGz
-rw------- 1 me me 308 Jun 18 16:27 /tmp/tmp.1D6O2vckGz
So are they really the same? Per
`diff -uwB /tmp/tmp.Ni1bgyPPEw /tmp/tmp.1D6O2vckGz | wc -l`
0
... they are the same!
外部配列参照およびIFS操作のないソリューションを次に示します。
# add one level of single quotes to args, eval to remove
squote () {
local a=("$@")
a=("${a[@]//\'/\'\\\'\'}") # "'" => "'\''"
a=("${a[@]/#/\'}") # add "'" prefix to each Word
a=("${a[@]/%/\'}") # add "'" suffix to each Word
echo "${a[@]}"
}
create_array () {
local my_list=(a "b 'c'" "\\\"d
")
squote "${my_list[@]}"
}
my_algorithm () {
eval "local result=($(create_array))"
# result=([0]="a" [1]="b 'c'" [2]=$'\\"d\n')
}
私は最近、関数が呼び出しスタックの上位の関数で宣言された変数に直接アクセスできるという点で、BASHの奇妙な点を発見しました。この機能を活用する方法を考え始めたばかりですが(利点と危険の両方を約束します)、1つの明らかなアプリケーションはこの問題の精神に対する解決策です。
また、配列の作成を委任するときにグローバル変数を使用するのではなく、戻り値を取得することをお勧めします。私の好みにはいくつかの理由がありますが、その中には、既存の値を乱す可能性を避けるためと、後でアクセスしたときに無効になる可能性のある値を残さないためです。これらの問題には回避策がありますが、最も簡単なのは、コードが終了したときに変数をスコープ外にすることです。
私のソリューションでは、必要なときに配列が使用可能になり、関数が戻ったときに破棄され、同じ名前のグローバル変数をそのまま残します。
#!/bin/bash
myarr=(global array elements)
get_an_array()
{
myarr=( $( date +"%Y %m %d" ) )
}
request_array()
{
declare -a myarr
get_an_array "myarr"
echo "New contents of local variable myarr:"
printf "%s\n" "${myarr[@]}"
}
echo "Original contents of global variable myarr:"
printf "%s\n" "${myarr[@]}"
echo
request_array
echo
echo "Confirm the global myarr was not touched:"
printf "%s\n" "${myarr[@]}"
関数request_arrayがget_an_arrayを呼び出すとき、get_an_arrayはmyarrrequest_arrayに対してローカルな変数。 myarrはdeclare
で作成されるため、request_arrayに対してローカルであり、したがってrequest_arrayが戻ります。
このソリューションは文字通り値を返しませんが、全体として考えると、真の関数の戻り値の約束を満たしていることをお勧めします。
さまざまな実装を試みましたが、スペースを含む要素を持つ配列は保存されませんでした...すべてがecho
を使用しなければならなかったからです。
# These implementations only work if no array items contain spaces.
use_array() { eval echo '(' \"\${${1}\[\@\]}\" ')'; }
use_array() { local _array="${1}[@]"; echo '(' "${!_array}" ')'; }
それから私は デニスウィリアムソンの答え に出会いました。私は彼の方法を以下の関数に組み込んで、a)任意の配列を受け入れ、b)配列の受け渡し、複製、および追加に使用できるようにしました。
# Print array definition to use with assignments, for loops, etc.
# varname: the name of an array variable.
use_array() {
local r=$( declare -p $1 )
r=${r#declare\ -a\ *=}
# Strip keys so printed definition will be a simple list (like when using
# "${array[@]}"). One side effect of having keys in the definition is
# that when appending arrays (i.e. `a1+=$( use_array a2 )`), values at
# matching indices merge instead of pushing all items onto array.
echo ${r//\[[0-9]\]=}
}
# Same as use_array() but preserves keys.
use_array_assoc() {
local r=$( declare -p $1 )
echo ${r#declare\ -a\ *=}
}
その後、他の関数は、キャッチ可能な出力または間接引数を使用して配列を返すことができます。
# catchable output
return_array_by_printing() {
local returnme=( "one" "two" "two and a half" )
use_array returnme
}
eval test1=$( return_array_by_printing )
# indirect argument
return_array_to_referenced_variable() {
local returnme=( "one" "two" "two and a half" )
eval $1=$( use_array returnme )
}
return_array_to_referenced_variable test2
# Now both test1 and test2 are arrays with three elements
最近、同様の機能が必要になったため、以下は RashaMatt と Steve Zobell による提案を組み合わせたものです。
私が見る限り、文字列はそのまま保持され、空白は保持されます。
#!bin/bash
function create-array() {
local somearray=("aaa" "bbb ccc" "d" "e f g h")
for elem in "${somearray[@]}"
do
echo "${elem}"
done
}
mapfile -t resa <<< "$(create-array)"
# quick output check
declare -p resa
いくつかのバリエーション…
#!/bin/bash
function create-array-from-ls() {
local somearray=("$(ls -1)")
for elem in "${somearray[@]}"
do
echo "${elem}"
done
}
function create-array-from-args() {
local somearray=("$@")
for elem in "${somearray[@]}"
do
echo "${elem}"
done
}
mapfile -t resb <<< "$(create-array-from-ls)"
mapfile -t resc <<< "$(create-array-from-args 'xxx' 'yy zz' 't s u' )"
sentenceA="create array from this sentence"
sentenceB="keep this sentence"
mapfile -t resd <<< "$(create-array-from-args ${sentenceA} )"
mapfile -t rese <<< "$(create-array-from-args "$sentenceB" )"
mapfile -t resf <<< "$(create-array-from-args "$sentenceB" "and" "this words" )"
# quick output check
declare -p resb
declare -p resc
declare -p resd
declare -p rese
declare -p resf
これは、単に配列変数を関数に渡し、この変数に配列値を割り当ててから、関数の外部でこの変数を使用することでも実行できます。例えば。
create_array() {
local __resultArgArray=$1
local my_list=("a" "b" "c")
eval $__resultArgArray="("${my_list[@]}")"
}
my_algorithm() {
create_array result
echo "Total elements in the array: ${#result[@]}"
for i in "${result[@]}"
do
echo $i
done
}
my_algorithm
ソースデータが各リスト要素で別々の行にフォーマットされている場合、mapfile
ビルトインはリストを配列に読み込む簡単でエレガントな方法です。
$ list=$(ls -1 /usr/local) # one item per line
$ mapfile -t arrayVar <<<"$list" # -t trims trailing newlines
$ declare -p arrayVar | sed 's#\[#\n[#g'
declare -a arrayVar='(
[0]="bin"
[1]="etc"
[2]="games"
[3]="include"
[4]="lib"
[5]="man"
[6]="sbin"
[7]="share"
[8]="src")'
read
ビルトインと同様に、割り当てられた配列変数は後続のステートメントで使用できないため(* bashジョブ制御が無効にされていない限り)、通常*パイプライン(またはサブシェル)でmapfile
を使用しませんおよびshopt -s lastpipe
が設定されます)。
$ help mapfile
mapfile: mapfile [-n count] [-O Origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
Read lines from the standard input into an indexed array variable.
Read lines from the standard input into the indexed array variable ARRAY, or
from file descriptor FD if the -u option is supplied. The variable MAPFILE
is the default ARRAY.
Options:
-n count Copy at most COUNT lines. If COUNT is 0, all lines are copied.
-O Origin Begin assigning to ARRAY at index Origin. The default index is 0.
-s count Discard the first COUNT lines read.
-t Remove a trailing newline from each line read.
-u fd Read lines from file descriptor FD instead of the standard input.
-C callback Evaluate CALLBACK each time QUANTUM lines are read.
-c quantum Specify the number of lines read between each call to CALLBACK.
Arguments:
ARRAY Array variable name to use for file data.
If -C is supplied without -c, the default quantum is 5000. When
CALLBACK is evaluated, it is supplied the index of the next array
element to be assigned and the line to be assigned to that element
as additional arguments.
If not supplied with an explicit Origin, mapfile will clear ARRAY before
assigning to it.
Exit Status:
Returns success unless an invalid option is given or ARRAY is readonly or
not an indexed array.