Bashシェルスクリプトで配列要素を 1 つ 1 つ置換する

2023-03-27Bash

はじめに

Bash では、配列を作成し、変数に代入できます。

例えば、1〜3 の要素を持つ配列変数は以下のように定義できます。

# 以下のいずれかで定義できる
$ declare -a NUMS=(11 12 13)

$ typeset -a NUMS=(11 12 13)

$ NUMS=(11 12 13)

ここで、 変数 NUMS の各要素の 1 という文字列を x に置換したいとします。

ループで置換していけばよいのですが、ループを記述子なくても置換できます。

検証環境

$ uname -moi
aarch64 aarch64 GNU/Linux

$ head -n 3 /etc/os-release
PRETTY_NAME="Ubuntu Kinetic Kudu (development branch)"
NAME="Ubuntu"
VERSION_ID="22.10"

$ bash -version | head -n 1
GNU bash, バージョン 5.2.0(1)-release (aarch64-unknown-linux-gnu)

変数の置換記法を使う

Bash には 変数を参照する際にパターンマッチで置換する機能があります。

# 変数 HELLO を定義
$ declare HELLO="My name is genzouw"

ここで作成した変数 HELLO を、参照するタイミングで置換できます。

# genzouw から taro に出力内容がかわっている
$ echo ${HELLO/genzouw/taro}
My name is taro

${変数/検索文字列/置換文字列} の形式で記述します。

配列変数に対して展開時の置換機能を適用する

先の例では、「文字列」変数に対して置換しました。

「配列」変数に対して同様の置換記法を利用すると、配列の各要素が個別に置換されます。

まずは配列変数を作成します。

$ declare -a WORDS=(ABC BCA CAB ACB "A B C")

置換してみます。配列変数を参照する際の記法に注意です。

$ echo "${WORDS[*]/A/@}"
@BC BC@ C@B @CB

このようにすべての要素が置換されました。

前方一致で置換させるためには置換文字列の最初に # を記述します。

$ echo "${WORDS[*]/#A/@}"
@BC BCA CAB @CB

後方一致で置換させるためには置換文字列の最初に # を記述します。

$ echo "${WORDS[*]/%A/@}"
ABC BC@ CAB ACB

このように記述することで、ループを書かずに配列の要素を1つずつ置換していくことができます。

ちなみに、 * を使うか、 @ を使うかについては、後述します

シェルスクリプトや関数の引数に対しても各要素の置換ができる

配列変数の各要素を置換した記法ですが、シェルスクリプトや関数の引数に対しても適用できます。

ただし、各要素を置換した新たな配列で for ループを実現したい場合には、 * ではなく @ を使わなければなりません

# 受け取った引数からカンマを取り除く
function exclude_comma {
  echo "${*/,/}"
}

$ exclude_comma 1,234 567 89,100
1234 567 89100

# カンマを取り除くはループ外で実行
function sum {
  declare -i sum=0
  # 配列でループするときは @ を使う点に注意
  for n in "${@/,/}"; do ((sum+=n)); done
  echo $sum
}

$ sum 1,234 567 89,100
90901

各要素を置換した結果で新しい配列を作成する

置換後の要素を持つ新たな配列を定義することもできます。

for ループと同様、この場合には添字に * ではなく @ を使用します。

# 要素を置換した後、新たな配列を定義
$ declare -a NEWWORDS=("${WORDS[@]/A/@}")

# 要素数を確認
$ echo "${#NEWWORDS[*]}"
5

$ echo "${#NEWWORDS[@]}"
5

$ echo "${NEWWORDS[0]}"
@BC

$ echo "${NEWWORDS[1]}"
BC@

$ echo "${NEWWORDS[2]}"
C@B

$ echo "${NEWWORDS[3]}"
@CB

$ echo "${NEWWORDS[4]}"
@ B C

ひとこと

では、今回紹介した記法を使うのかというとほとんど使った事がありません。

2023-03-27Bash