| author | プレハブ小屋 <2386769+showa-yojyo@users.noreply.github.com> | ||
|---|---|---|---|
| created | 2026-08-05 | ||
| draft | true | ||
| tags |
|
||
| title | Bash 配列ノート |
Bash では一次元の配列が使える。基本的な性質を羅列しておく:
- 添字型と連想型がある。
- 添字型配列では、添字は数とする。添字の最小元は
0とする。 - 連想型配列は、キーとして任意の文字列を使える。
- 添字型配列では、添字は数とする。添字の最小元は
- 命令
declare -aで配列型変数を明示的に宣言することが可能。 - 配列の長さに仕様による制限はない。
添字型配列の添字部分に対しては、次の性質がある:
- 各種展開、命令置換、引用符除去が発生する。
- 添字の値が空文字列の場合、添字
0とみなされる。
連想配列のキー部分に対しては、次の性質がある:
- tilde 展開を含む各種展開、命令置換、引用符が発生する。
- 空文字列はキーとして認められない。
添字型配列を、初期値を指定せずに、その名前だけを宣言するには次の組み込み命令を使え:
declare -anamelocal -anamereadonly -aname
連想配列の宣言については、上の -a の代わりに -A を使え。
配列変数に nameref 属性を指定する (i.e. -n) ことは不可。
Tip
関数内部では local が使いやすい。対話型セッションでは declare がいい。
初期値を指定する場合は次の記法がいい:
name=([sub0]=value0 [sub1]=value1 ... )- 上記の宣言コマンドを用いても用いなくてもいい。
- 添字配列の場合には
[sub]=指定すべてを省くのが普通だ。 - 各 value には任意の文字列を使える。
- 各 value にはシェル展開が適用される。複数の語に展開される場合は、語のそれぞれが個別の値になる。
Note
連想配列には、キーと値を交互に並べた配列で代入する記法もある。本稿では取り扱わない。
標準入力から添字型配列を構築する手段として命令 read -a name が使える。例:
$ read -a browsers
chrome firefox opera # stdin
$ echo ${browsers[@]}
chrome firefox opera組み込みコマンド mapfile or readarray を使うことで、標準入力の各行が要素になるように配列を作成することが可能だ。例:
$ readarray -t users </etc/passwd
$ echo ${users[0]}
root:x:0:0:root:/root:/bin/bash
$ echo ${users[1]}
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin- 通例、オプション
-tを指定して行末の改行文字を落とす。 - オプション
-ufd を指定すれば、標準入力つまりファイル記述子0以外から入力できる。
添字型でも連想型でも、配列変数を全体的に破棄するのに、組み込み命令 unset を用いることができる。
添字配列の例:
$ declare -a browsers=(chrome firefox)
$ unset browsers
$ declare -p browsers
-bash: declare: browsers: not found連想配列の例:
$ declare -A shells=([sh]=1979 [ksh]=1983 [tcsh]=1981 [bash]=1989)
$ unset shells
$ declare -p shells
-bash: declare: shells: not found配列全体を代入する場合は結局先述の初期化方式しかないらしい?
要素の値を代入するには次の記法を使え:
name[sub]=value- sub を指定しなくてもよい。その場合は最後に割り当てられた添字に対応する位置の次に新しい要素を挿し込む。
- 添字型:sub が負の値の場合、Python
listのように、末端からの相対位置に値を代入する。
添字型配列の sub 番目の要素や、連想配列のキー sub に対応する要素を参照するには次の記法を使え:
${name[sub]}- 添字型:負の添字については代入の節で述べたとおり機能する。
- 添字型:
$nameは${name[0]}と同値。
命令の実引数として配列要素を渡す場合、それを囲む引用符の有無が変数展開を決める。例えば
some-command "a[4]"は a[4] を変数展開各種を施してから some-command が走る。一方、
some-command 'a[4]'では、変数展開をいっさい行わないで命令を走らせる。
未定義か空かを区別する必要がない場合には test -v name が手ッとり早く書ける。
if [[ -v name ]]; then
echo name is not empty
else
echo name is empty or unset
fi添字型配列に限り、unset "name[@]" により長さゼロの配列に変更することが可能。
$ declare -a arr=(0 1 2 3)
$ unset 'arr[@]'
$ declare -p arr
declare -a arr=()Note
上記のような操作を連想配列に対して行うと、単純にキーが @ の要素があればそのキーと値の対が削除される。
変数から部分文字列を作るための次の構文を配列に適用することが可能だ:
${name[@]:offset}
${name[@]:offset:length}次の例は Bash Reference Manual Edition 5.3 p. 32 より引用:
$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
$ echo ${array[@]:7}
7 8 9 0 a b c d e f g h
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
-bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}
演算子 += で配列に要素を追加することが可能だ。
連想配列の例:
$ declare -A shells=([sh]=1979 [ksh]=1983 [tcsh]=1981 [bash]=1989 [zsh]=1990 [dash]=1997 [fish]=2005)
$ shells+=([csh]=1978)
$ echo ${shells[*]}
1981 1979 1989 1978 1997 1990 1983 2005
$ declare -p shells標準入力から追加する場合には組み込み命令 mapfile や readarray のオプション -O が有用だ。
readarray -t -O ${#name[@]} name < ...添字型配列または連想配列 name の添字全部またはキー全部を得るには次のように書け:
${!name[@]}${!name[*]}これらの違いは引用符で囲んだときに生じる:
$ declare -A name=([sh]=1977 [bash]=1989 [zsh]=1990)
$ printf "%s\n" "${!name[@]}"
sh
bash
zsh
$ printf "%s\n" "${!name[*]}"
sh bash zsh配列を再利用可能な形式、つまりコピー&ペーストでその配列を再現することが可能な文字列として出力するには、declare -p が使える。
declare -p name添字型配列の例を示す。やや冗長だが正確な表現をする:
$ declare -a browsers=(explorer chrome firefox edge)
$ declare -p browsers
declare -a browsers=([0]="chrome" [1]="firefox" [2]="opera")unset "name[sub]"- 配列変数の最後の要素を削除しても、配列変数自体は消滅しない。
- 添字型:添字はシフトしないらしい。下の例を見ろ。
$ declare -a browsers=(explorer chrome firefox edge)
$ unset "browsers[explorer]"
$ declare -p browsers
declare -a browsers=([1]="chrome" [2]="firefox" [3]="edge")配列の長さを得るには、変数の文字列としての長さを得る構文を使い回せ:
${#name[@]}
${#name[*]}for i in "${name[@]}"; do
echo $i
doneシェル変数展開を配列の要素すべてに適用した配列は容易に得られる。
例として、要素すべての値を大文字に変換した配列を作るには、展開式 @U や ^^ を
${name[@]} に適用すればいい
$ declare -a browsers=(explorer chrome firefox edge)
$ echo ${browsers[@]@U} # or ${browsers[@]^^}
EXPLORER CHROME FIREFOX EDGEshopt -s array_expand_once である場合、Bash は次の頃合いで配列の添字・キーに対する二重評価を避けるようになる:
- 算術式の評価中
- 変数代入を行う組み込み命令の実行中
- 配列を間接参照する組み込み命令の実行中
TODO: 例を見つける
以上