※当サイトの記事には、広告・プロモーションが含まれます。

シェルスクリプトで関数の引数で配列を使う方法が統一されていない問題

www.itmedia.co.jp

 その後の調査で、インデックステーブルは、開発時(環境構築時)にテーブルを生成するプログラムを動かした際、共有メモリ上の作業領域を十分に確保できていなかったために破損していたことが分かった。NTTデータによると「作業領域が不足していてもテーブルは出来てしまう。不足した作業領域にも書き込み、しかし本来は他のプログラムが使用する領域のため、上書きされてしまった」という。

全銀ネット障害、原因は仕様の”見落とし“ 設計者がチェックしていれば防げた可能性も - ITmedia NEWS

 問題は、作業領域が不足した理由だ。今回のようにOSの変更(64bit化)を伴うようなシステムリプレースでは、事前にその差異や周囲への影響を調べる「影響調査」を行うが、その際に仕様の一部を見落とし、生成プログラムが必要とする作業領域を実際より少なく見積もっていた。

全銀ネット障害、原因は仕様の”見落とし“ 設計者がチェックしていれば防げた可能性も - ITmedia NEWS

 「テーブルが作業領域に収まるサイズだったため、(作業領域の)拡張は不要と判断してしまった。しかし実際には、金融機関名テーブルの他に、3つのテーブルを同時に展開する仕様だった」という。

全銀ネット障害、原因は仕様の”見落とし“ 設計者がチェックしていれば防げた可能性も - ITmedia NEWS

⇧ 要件定義の漏れってことかね。

大規模で複雑なシステムになるほど、影響調査は難しいと思うし、今回の改修に関係ない部分だったとしたら、そんな仕様は知らんがな、って気持ちにもなるよね...

結合テストとかをしっかり実施できる環境が構築できていたとしても、そもそもの仕様が把握できていないとテストのしようがないものな...

システムの機能の関連を把握することの難しさを痛感しますな...

そもそも、テスト環境が本番環境と同じ条件じゃなかったら、テストしても事象が再現できない気がするので気付けない気がするんよね...

サーバーのメモリの問題ってことだとすると、非機能要件な気がするんだけど、機能改修でメモリの使用量について調整が必要って話、絶対に周知されてなかった気がする...

改めて、影響調査や見積もりの難しさを痛感しますな...

2023年12月3日(日)追記:↓ ここから

何やら、

it.impress.co.jp

 今回、全銀ネットとNTTデータは原因の詳細を説明した。システムが32ビット環境から64ビット環境に変わったことで、C言語のデータ型のサイズの違いから、テーブル生成プログラムが生成する金融機関名テーブルのサイズが増えた。しかし、テーブル生成プログラムがテーブルの生成のために確保するメモリー領域のサイズについては変更していなかった(図1)。

全銀システム障害の詳細を報告、64ビット化でテーブルサイズが増えて作業領域が不足 | IT Leaders

図1:障害の発生原因。32ビット環境から64ビット環境に変わったことで生成するテーブルのサイズが増えた結果、確保したメモリー領域に収まりきらなくなった(出典:全国銀行資金決済ネットワークNTTデータ
拡大画像表示

全銀システム障害の詳細を報告、64ビット化でテーブルサイズが増えて作業領域が不足 | IT Leaders

 テーブル生成プログラムは、C言語で開発したプログラムである。これまで32ビット環境でコンパイルして動かしていたコードを変更することなく、そのまま64ビット環境で再コンパイルして使っている。全銀システムのOS環境では、金融機関名テーブルで使っているデータ型(long型)のサイズが32ビット環境と64ビット環境で異なることから、生成するテーブルのサイズが増えた。なお、インデックステーブルで使っているデータ型のサイズは32ビット環境と64ビット環境で同じであり、テーブルのサイズにも変化はない。

全銀システム障害の詳細を報告、64ビット化でテーブルサイズが増えて作業領域が不足 | IT Leaders

⇧ ってことらしいので、テスト環境が本番環境と同じ条件になってなかったような気がしますかね。

本番環境と同じプログラムを動かしてたら、テスト環境でも本番環境と同じく異常終了するはずだものね。

それとも、C言語だとエラーハンドリング的なものがされずに、エラーが起きていても気付けなかっただけなのか...

C言語については、全く知見が無いので、何とも言えんけど...

2023年12月3日(日)追記:↑ ここまで

シェルスクリプトの基本構文が不明な件

そもそもとして、Linuxシェルスクリプトの基本構文的なものについて公的なドキュメントのようなものが見当たらないのですと。

一応、

google.github.io

While shell scripting isn’t a development language, it is used for writing various utility scripts throughout Google. This style guide is more a recognition of its use rather than a suggestion that it be used for widespread deployment.

https://google.github.io/styleguide/shellguide.html

Googleさんが、使い方をドキュメント化してくれていますと。

と言うか、シェルスクリプトは開発言語じゃないと...

まぁ、そんなような認識ということで、シェルスクリプトを使うモチベーションが上がらんわな...

で、残念ながら、上記のドキュメントでは、「連想配列」についての説明が全くないので、「MECE(Mutually Exclusive and Collectively Exhaustive)」的な意味では不完全なドキュメントになってしまっていますと。

Bashについては、

www.gnu.org

GNUがマニュアルを公開してくれていますな。

Bash以外のシェルを使ってる場合は、何を正解とすれば良いか謎ですな...

配列(indexed arrays)と連想配列(Associative arrays)

これは、マニュアルの説明が分かり辛いのだけど、

www.gnu.org

6.7 Arrays

Bash provides one-dimensional indexed and associative array variables. Any variable may be used as an indexed array; the declare builtin will explicitly declare an array. There is no maximum limit on the size of an array, nor any requirement that members be indexed or assigned contiguously. Indexed arrays are referenced using integers (including arithmetic expressions (see Shell Arithmetic)) and are zero-based; associative arrays use arbitrary strings. Unless otherwise noted, indexed array indices must be non-negative integers.

https://www.gnu.org/software/bash/manual/bash.html#Arrays

⇧ 説明を見る限りでは、

  • Arrays
    1. one-dimensional indexed arrays
    2. one-dimensional associative array

といった2パターンがある感じか。

keyとか指定しない場合でも、配列のインデックスとして数値が暗黙の裡に設定されてると。

配列(indexed arrays)にしろ、連想配列(Associative arrays)にしろ、1次元の配列(one-dimensional Arrays)しか提供しないとなってるところが厳しいですな...

シェルスクリプトで関数の引数で配列を使う方法が統一されていない問題

何やら、ネット上の情報によると、

glodia.jp

qiita.com

⇧ いろんな書き方がある模様。

配列、連想配列の作り方は、

    1. 配列
      1. declare -a で配列を初期化する
      2. 普通に配列を初期化する(declare -a を使わない)
    2. 連想配列
      1. declare -A で連想配列を初期化する

⇧ のような種類があるっぽいのだけど、初期化の方法によって、関数の引数としての渡し方も変わってくるっぽい、罠過ぎる...

とりあえず、試してみましたが、declareを使って初期化しておいた方が良さそう。

そして、2次元連想配列が作れないとかがやはり辛い...

疑似的な2次元配列も並びが無茶苦茶になるし...

■/home/ts0818/work/test_arr/test_arr.sh

#!/bin/bash

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# ■  出力
# ■    引数
# ■      param $1 出力ファイル(国の配列)
# ■      param $2 出力ファイル(国の人口の連想配列)
# ■      param $3 国の配列
# ■      param $4 国の人口の連想配列(疑似的2次元連想配列用)
# ■    戻り値
# ■      なし
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
function print_arr() {
  local _country="$1"
  local _country_population="$2"
  declare -n ref_country_arr="$3"
  declare -n ref_country_population_arr="$4"
  
  for element in ${ref_country_arr[@]};
  do
    echo "${element}" | tee -a ${_country}
  
  done

  for key in ${!ref_country_population_arr[@]};
  do
    # 疑似的二次元配列の内容を書き込む
    echo "${key}"'='"${ref_country_population_arr[${key}]}" | tee -a ${_country_population}
  done

}

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# ■  疑似的な2次元連想配列を生成する
# ■    引数
# ■      param $1 国の人口の連想配列(疑似的2次元連想配列用)
# ■      param $2 国毎の人口の連想配列
# ■      param $3 国の人口の連想配列(疑似的2次元連想配列用)のインデックス用
# ■    戻り値
# ■      国の人口の連想配列(疑似的2次元連想配列用)
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

function generate_two_dimention_associative_arr() {
  declare -n ref_country_population_arr="$1"
  declare -n ref_country_population_all_arr="$2"
  local _idx_arr="$3"

  for key in ${!ref_country_population_arr[@]};
  do
    ref_country_population_all_arr[${_idx_arr},${key}]="${ref_country_population_arr[${key}]}"
  done

}

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# ■  実処理
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

LOG=test_arr.log

# 配列
declare -a country_arr=(
 "China"
 "India"
 "America"
 "Indonesia"
 "Pakistan"
 "Brazil"
 "Nigeria"
 "Bangladesh"
 "Russia"
 "Mexico"
 "Japan"
)

# 連想配列
#declare -A country_population_arr=(
# ["China"]=("1,425,894" "728,050" "697,843")
# ["India"]=("1,407,564" "726,503" "681,060")
# ["America"]=("336,998" "166,942" "170,056")
# ["Indonesia"]=("273,753" "137,852" "135,901")
# ["Pakistan"]=("231,402" "116,816" "114,586")
# ["Brazil"]=("214,326" "105,291" "109,035")
# ["Nigeria"]=("213,401" "107,827" "105,574")
# ["Bangladesh"]=("169,356" "83,998" "85,358")
# ["Russia"]=("145,103" "67,393" "77,710")
# ["Mexico"]=("126,705" "61,856" "64,849")
# ["Japan"]=("124,613" "60,568" "64,045")
#)


declare -A china_population_arr=(["China"]="1,425,894" ["Men"]="728,050" ["Women"]="697,843")
declare -A india_population_arr=(["India"]="1,407,564" ["Men"]="726,503" ["Women"]="681,060")
declare -A america_population_arr=(["America"]="336,998" ["Men"]="166,942" ["Women"]="170,056")
declare -A indonesia_population_arr=(["Indonesia"]="273,753" ["Men"]="137,852" ["Women"]="135,901")
declare -A pakistan_population_arr=(["Pakistan"]="231,402" ["Men"]="116,816" ["Women"]="114,586")
declare -A brazil_population_arr=(["Brazil"]="214,326" ["Men"]="105,291" ["Women"]="109,035")
declare -A nigeria_population_arr=(["Nigeria"]="213,401" ["Men"]="107,827" ["Women"]="105,574")
declare -A bangladesh_population_arr=(["Bangladesh"]="169,356" ["Men"]="83,998" ["Women"]="85,358")
declare -A russia_population_arr=(["Russia"]="145,103" ["Men"]="67,393" ["Women"]="77,710")
declare -A mexico_population_arr=(["Mexico"]="126,705" ["Men"]="61,856" ["Women"]="64,849")
declare -A japan_population_arr=(["Japan"]="124,613" ["Men"]="60,568" ["Women"]="64,045")

#declare -A country_population_arr=(
# [0]=$(declare -p china_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [1]=$(declare -p india_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [2]=$(declare -p america_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [3]=$(declare -p indonesia_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+"  '{ print  "(" $2 $3 $4 $5 }')
# [4]=$(declare -p pakistan_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+"  '{ print "(" $2 $3 $4 $5 }')
# [5]=$(declare -p brazil_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+"  '{ print "(" $2 $3 $4 $5 }')
# [6]=$(declare -p nigeria_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [7]=$(declare -p bangladesh_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [8]=$(declare -p russia_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [9]=$(declare -p mexico_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
# [10]=$(declare -p japan_population_arr | cut -d ' ' -f 3- | awk -F"[=(]+" '{ print "(" $2 $3 $4 $5 }')
#)

declare -A country_population_arr
#country_population_arr[0]=${!china_population_arr[@]}'='${china_population_arr[@]}
#country_population_arr[1]=${!india_population_arr[@]}'='${india_population_arr[@]}
#country_population_arr[2]=${!america_population_arr[@]}'='${america_population_arr[@]}
#country_population_arr[3]=${!indonesia_population_arr[@]}'='${indonesia_population_arr[@]}
#country_population_arr[4]=${!pakistan_population_arr[@]}'='${pakistan_population_arr[@]}
#country_population_arr[5]=${!brazil_population_arr[@]}'='${brazil_population_arr[@]}
#country_population_arr[6]=${!nigeria_population_arr[@]}'='${nigeria_population_arr[@]}
#country_population_arr[7]=${!bangladesh_population_arr[@]}'='${bangladesh_population_arr[@]}
#country_population_arr[8]=${!russia_population_arr[@]}'='${russia_population_arr[@]}
#country_population_arr[9]=${!mexico_population_arr[@]}'='${mexico_population_arr[@]}
#country_population_arr[10]=${!japan_population_arr[@]}'='${japan_population_arr[@]}

generate_two_dimention_associative_arr china_population_arr country_population_arr 0
generate_two_dimention_associative_arr india_population_arr country_population_arr 1
generate_two_dimention_associative_arr america_population_arr country_population_arr 2
generate_two_dimention_associative_arr indonesia_population_arr country_population_arr 3
generate_two_dimention_associative_arr pakistan_population_arr country_population_arr 4
generate_two_dimention_associative_arr brazil_population_arr country_population_arr 5
generate_two_dimention_associative_arr nigeria_population_arr country_population_arr 6
generate_two_dimention_associative_arr bangladesh_population_arr country_population_arr 7
generate_two_dimention_associative_arr russia_population_arr country_population_arr 8
generate_two_dimention_associative_arr mexico_population_arr country_population_arr 9
generate_two_dimention_associative_arr japan_population_arr country_population_arr 10

declare -p country_population_arr | tee -a ${LOG}

country=country.txt
country_population=country_population.txt

print_arr "${country}" "${country_population}" country_arr country_population_arr

⇧ とりあえず、関数の引数として、配列、連想配列を渡すことができました。

シェルスクリプト、扱い辛さが半端ないんだが...

毎度モヤモヤ感が半端ない...

今回はこのへんで。