トラック
/
Bash
Bash
/
シラバス
/
配列をもっと詳しく
配列

配列をもっと詳しく の Bash

{other: "%{count}個の演習"}

配列をもっと詳しくについて

配列の章で、配列について紹介しました。 このドキュメントでは、配列のさらに多くの使い方を紹介します。

配列の要素を1つの文字列に連結する

前の配列の章では、@インデックスを付けた"${myarray[@]}"で、配列を個々の要素に展開する方法を見ました。 しかし、すべての要素を1つの文字列にまとめたいこともあります。 そのようなときは、*インデックスを使います。

echo "${myarray[*]}"

展開はダブルクォートで囲む必要があります。

Bashは、組み込み変数IFSの_最初の文字_を区切り文字として使います。 デフォルトでは、$IFSはスペース、タブ、改行で構成されています。

myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"

IFS変数を操作して、別の区切り文字を使うこともできます。

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
これは関数にまとめることができます。 詳細を表示するにはクリックしてください。
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

join ":" "${myarray[@]}"     # note, the "@" index
# => "one:two:three:four"

関数内でIFSをローカル化すれば、グローバルスコープで古い値を保存して元の値に戻す必要がありません。

さらに洗練させるなら、特殊パラメーター"$*"はダブルクォートで囲むと同じ働きをするので、関数の引数のコピーを保存する必要はありません。

join() {
    local IFS=$1
    shift
    echo "$*"
}
関数を使わずに、サブシェル内でIFSを変更するのも、現在のシェルでの変更を避けるよい方法です。 詳細を表示するにはクリックしてください。
(IFS=","; echo "${myarray[*]}")

括弧(())はサブシェル(現在のシェルのコピー)を作ります。括弧内のコマンドが完了するとサブシェルが終了し、変更されたIFS変数は消えます。

ただし、これはうまくいきません。IFS="," echo "${myarray[*]}"では、シェルが変更されたIFS変数をechoコマンドに適用する_前に_、パラメーター展開が実行されるからです。

配列のスライス

変数の値の_部分文字列_に展開する"${variable:offset:length}"のパラメーター展開を見たことがあるかもしれません。 配列でも同じことができ、配列の一部を展開できます。

myarray=(one two three four)

subarray=("${myarray[@]:0:2}")
declare -p subarray
# => declare -a subarray=([0]="one" [1]="two")

subarray=("${myarray[@]:1:3}")
declare -p subarray
# => declare -a subarray=([0]="two" [1]="three" [2]="four")

長さの部分を省略すると、「オフセットから配列の末尾まで」という意味になります。

subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")

配列を関数に渡す

これは、知っているかもしれない他の言語ほど単純ではありません。 配列を関数に渡すには、主に2つの方法があります。

要素を渡す

1つ目の方法では、配列のすべての値を渡し、関数内のローカル配列にまとめます。

myfunc() {
    local array_copy=("$@")
    # do stuff with array_copy
    declare -p array_copy
}

array_original=(11 22 33 44)
myfunc "${array_original[@]}"

関数内の配列は値の_コピー_を保持します。 関数内で配列に加えた変更は、外側のスコープには反映されません。

配列の名前を渡す

この方法は、他の言語で知られている「参照渡し」に近いものです。 配列の_名前_を文字列として渡します。 関数は、nameref属性を持つローカル変数を作成します。 このローカル配列と、(名前を渡した)グローバル配列は_同じ配列_です。

myfunc() {
    # note the `-n` option
    local -n local_array=$1

    # do stuff with local_array
    for i in "${!local_array[@]}"; do
        printf '%d => %s\n' "$i" "${local_array[i]}"
    end

    # we can mutate it
    local_array+=(55 66 77)
}

array_original=(11 22 33 44)
myfunc "array_original"

# show the mutated array
declare -p array_original
# => declare -a array_original=([0]="11" [1]="22" [2]="33" [3]="44" [4]="55" [5]="66" [6]="77")

namerefは連想配列や、(文字列の値を保持する)「スカラー」変数でも機能します。

Note

関数内でdeclare -p local_arrayを実行しても、あまり役には立ちません。 declare -n local_array="array_original"と出力されるだけです。 渡した配列の名前を調べれば、その配列の詳しい情報を取得できます。declare -p "$1"

Caution

ローカル配列には、渡した配列とは異なる名前を付けるよう注意してください。 コード自体は動作しますが、次のような「circular name reference」の警告が出力されます。

myfunc() {
    local -n a=$1
    local IFS=,
    echo "${a[*]}"
}

# same name as the function's local variable
a=(one two three)
myfunc a
bash: local: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
one,two,three

位置パラメーターは「配列のようなもの」

POSIX標準のみに準拠しようとするシェル(ashやdashなど)には、配列がありません。 もっとも近いのは、位置パラメーターを使うことです。

  • 位置パラメーターには、インデックスでアクセスします。$1、$2などです。
  • "$@"で個々の要素に展開されます。
  • "$*"で1つの文字列に連結されます。
  • パラメーターの数は$#です。

値の代入にはsetコマンドを使います。

set -- one two three
set -- "$@" four

for item in "$@"; do
    echo "do something with $item"
done

「移植性の高い」シェルスクリプトを書きたいなら、値の「リスト」を保存するために位置パラメーターを使うことになります。

GitHubで編集 リンクは新しいウィンドウまたはタブで開きます