Bashは動的配列名を使用できません(しかし理解しています)。

Bashは動的配列名を使用できません(しかし理解しています)。

Bashでスクリプトを作成していて、ループ内で配列を宣言する必要があるため、次のようにします。

variable=suffix
declare -a prefix_$variable='(item1 item2)'

これは "prefix_$variable" を使用できるようにする必要がありますが、使用できないため失敗します。

しかし、宣言はうまくいきます。宣言後にecho ${prefix_sufix[@]}アイテムをエコーするからです。唯一の問題は、配列名を直接作成する必要があることです。

この例を見てください。

mint@ubuntu ~ $ variable=suffix
mint@ubuntu ~ $ declare -a prefix_$variable='(item1 item2)'
mint@ubuntu ~ $ echo ${prefix_suffix[@]}
item1 item2
mint@ubuntu ~ $ echo ${prefix_$variable[@]}
bash: ${prefix_$variable[@]}: bad substitution
mint@ubuntu ~ $ prefix_$variable[2]='none'
bash: prefix_suffix[2]=none: command not found

エラーメッセージに「prefix_suffix」と書かれているため、変数名を理解していますが、正しく実行されていないことが明らかにわかるので、これは意味がありません。

どうなりますか?この問題をどのように解決できますか?

結果に何の変更もなく最後の部分を、、、、"prefix_${variable}"[2]='none'prefix_${variable}[2]='none'書き直してみました。$(prefix_$variable[2]='none')

答え1

解決策はnamerefを使用することです。

$ variable=suffix
$ declare -n shortname=prefix_$variable
$ declare -a prefix_$variable='(item1 item2)'
$ echo ${prefix_suffix[@]}
item1 item2
$ echo "${shortname[@]}"
item1 item2
$ shortname[2]='none'
$ echo ${prefix_suffix[@]}
item1 item2 none

答え2

「ここで何が起こっているのか」はシェル操作であり、機能は魔法のようには発生しません。 bashを含むすべてのPOSIXシェルには、次のものが必要です。決定されたシーケンスを実行する柔軟性が限られています。

abc_def=heffalump

最初のトークンに解析すると ASSIGNMENT_WORD であり、複合命令には含まれないため、次のように処理される。簡単なコマンド:割り当てを保存し、残りを拡張し(空であるため何も起こらない)、割り当てが拡張され(何もしない)、コマンド名(または引数)がないため、現在の環境の変数に値が再割り当てされます。 (サブシェルではなく)「メイン」シェルと呼ばれ、プログラムを実行しようとしません。

abc_$xyz=heffalump

abc_$xyz無効な変数名(数字以外の文字で始まる文字、数字、および下線のみ)はASSIGNMENT_WORDで解析することができます。結果:

  1. シェル構文規則に従って変数の割り当てまたはリダイレクトによって識別された単語は、ステップ3と4の処理のために保存されます。

割り当てやリダイレクトは解決されないため、何もしません。

  1. 変数の割り当てやリダイレクト以外の単語は拡張する必要があります。拡張後に残りのフィールドがある場合、最初のフィールドはコマンド名として扱われ、残りのフィールドはコマンドの引数です。

単語は(say)に展開されますabc_eeyore=heffalump。単語は1つだけで、コマンド名として扱われます。

  1. リダイレクトは、リダイレクトで説明されているように実行する必要があります。

リダイレクトがないため、何もしません。

  1. チルダ拡張、パラメータ拡張、コマンド置換、算術拡張、および引用符の削除を割り当てる前に、すべての変数割り当てを拡張する必要があります。

仕事がないので何もしません。

単純なコマンドがコマンド名とオプションの引数リストを生成する場合[および] 1.コマンド名にスラッシュが含まれておらず、[組み込みの特殊ユーティリティまたは関数の名前ではない] PATH 環境変数を使用して検索する必要があります。 [見つかったらプログラムを実行し、そうでなければ失敗します。]

declare簡単に言えば、一般的なシェルの解析や準備ロジックではなく単一のコマンドで実行される変数参照などの操作を実行するためにシェルが必要な順序であるため、特定の組み込みコマンドでのみアイデアが機能します。

すべてのPOSIXシェルで使用される伝統的な大きなハンマーソリューションはeval

eval abc_$xyz=heffalump

最初に2つの単語に解析され、2番目の単語がに展開されますabc_eeyore=heffalumpそれからeval(単一)引数として渡し、最初から始めて有効な割り当てに解析し(現在は)実行します。

しかしeval実際にすべてabc_$xyz=heffalumpこれ以外にも、abc_; rm -fr all_valuable_data自分rm -fr /evalしていることを正確に知らない限り、使用するのは安全ではありません。知っていれば質問はしません。

より具体的で安全な解決策はbashでのみ可能です。名前参照

suffix=eeyore
declare -n ref=abc_$suffix
ref=(1 2 3)
echo ${ref[@]} ${abc_eeyore[@]}
-> 1 2 3 1 2 3

また、スカラーのbashには(必要な配列ではない)次のものがあります。間接的な:

suffix=eeyore
ind=abc_$suffix
declare abc_$suffix=123 # or declare $ind=123
echo ${!ind}
-> 123

関連情報