Upgrade to Pro — share decks privately, control downloads, hide ads and more …

配列に見る bash と zsh の違い

Avatar for kazzpapa3 kazzpapa3
February 04, 2026

配列に見る bash と zsh の違い

2026年2月4日にクラスメソッドさんの大阪オフィスで開催された「クラメソおおさか IT 勉強会 Midosuji Tech #8 〜レベル300以上限定LT〜」でお話しした内容です。
#midosuji_tech

Avatar for kazzpapa3

kazzpapa3

February 04, 2026
Tweet

More Decks by kazzpapa3

Other Decks in Technology

Transcript

  1. 配列に見る bash と zsh の違い クラメソおおさか IT 勉強会 Midosuji Tech

    #8 〜レベル300以上限定LT〜 (Feb. 4, 2026) Speaker : @kazzpapa3 / JAWS-UG 神戸
  2. Biography { "Bio": { "Name": "ICHINO Kazuaki a.k.a. kazzpapa3", "Organization":

    "A certain AWS partner company", "Role": "Technical Support Engineer", "Favorite AWS Services": [ "AWS CLI", "AWS CloudTrail", "Kiro CLI" ], "Less Favorite AWS Service (as a Support Engineer)": [ "AWS Billing (請求ロジックが難解すぎる)" ], "Personal Interest": "初音ミク", "Socials": { "Twitter/X": "@kazzpapa3", "LinkedIn": "https://www.linkedin.com/in/kazzpapa3/" } } }
  3. 出力結果の例 bash の場合 apple banana cherry zsh の場合 apple banana

    つまり インデックスが予期しない挙動 に @kazzpapa3 / #midosuji_tech 13 / 30
  4. 回避方法 1. zsh 側で bash 互換モード を使う emulate -LR bash

    の宣言を加える 2. zsh 側で KSH_ARRAYS オプション を使う setopt KSH_ARRAYS の宣言を加えることで 0 始まりに変更可能 3. ちゃんと shebang を書く shebang(シバン/シェバン) = シェルスクリプトの1行目にある #!/bin/bash や #!/bin/zsh などのおまじないっぽいやつ 4. そもそもインデックスを使わない @kazzpapa3 / #midosuji_tech 14 / 30
  5. セキュリティグループの設定シーンを想定 sg-config.txt として以下を持っているとします sg_web[name]="web-server-sg" sg_web[description]="Security group for web servers" sg_web[vpc-id]="vpc-0123456789abcdef0"

    sg_web[ingress]="tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0" sg_db[name]="database-sg" sg_db[description]="Security group for database servers" sg_db[vpc-id]="vpc-0123456789abcdef0" sg_db[ingress]="tcp:3306:10.0.0.0/16" @kazzpapa3 / #midosuji_tech 17 / 30
  6. セキュリティグループを作るスクリプトを模したもの create-security-groups.sh として以下のような処理があるとします #!/bin/zsh declare -A sg_web sg_db source sg-config.txt

    echo "=== Security Group Configuration ===" for key in "${(k)sg_web[@]}"; do echo "sg_web[$key] = ${sg_web[$key]}" done for key in "${(k)sg_db[@]}"; do echo "sg_db[$key] = ${sg_db[$key]}" done echo "Creating security groups..." # AWS CLI 呼び出し例(実際には実行しない) echo "aws ec2 create-security-group --group-name ${sg_web[name]} --description \"${sg_web[description]}\" --vpc-id ${sg_web[vpc-id]}" echo "aws ec2 create-security-group --group-name ${sg_db[name]} --description \"${sg_db[description]}\" --vpc-id ${sg_db[vpc-id]}" @kazzpapa3 / #midosuji_tech 18 / 30
  7. zsh で動作させた表示例 zsh で実行させると以下のようになります % ./create-security-groups.sh === Security Group Configuration

    === sg_web[ingress] = tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0 sg_web[vpc-id] = vpc-0123456789abcdef0 sg_web[description] = Security group for web servers sg_web[name] = web-server-sg sg_db[ingress] = tcp:3306:10.0.0.0/16 sg_db[vpc-id] = vpc-0123456789abcdef0 sg_db[description] = Security group for database servers sg_db[name] = database-sg Creating security groups... aws ec2 create-security-group --group-name web-server-sg --description "Security group for web servers" --vpc-id vpc-0123456789abcdef0 aws ec2 create-security-group --group-name database-sg --description "Security group for database servers" --vpc-id vpc-0123456789abcdef0 @kazzpapa3 / #midosuji_tech 19 / 30
  8. bash で動作させた表示例 bash ./create-security-groups.sh としたり、shebang を書き忘れてい たとすると以下のようになります % bash create-security-groups.sh

    create-security-groups.sh: line 4: declare: -A: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...] === Security Group Configuration === create-security-groups.sh: line 14: ${(k)sg_web[@]}: bad substitution create-security-groups.sh: line 20: ${(k)sg_db[@]}: bad substitution Creating security groups... aws ec2 create-security-group --group-name tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0 --description "tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0" --vpc-id tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0 aws ec2 create-security-group --group-name tcp:3306:10.0.0.0/16 --description "tcp:3306:10.0.0.0/16" --vpc-id tcp:3306:10.0.0.0/16 @kazzpapa3 / #midosuji_tech 20 / 30
  9. bash で動作させると何が起きたか declare: -A: invalid option エラーは declare に -A

    オプションが実 装される以前のバージョンでの実行によるものです 現行の macOS でも bash 3.2.57 しかインストールされていない declare -A を認識したとしても ${(k)array[@]} の書き方が zsh 特有 のものとなるため bad substitution エラーが発生する 結果として sg_web 、 sg_db のそれぞれ 最後に読み込んだ ingress のみが保持されている状態 (上書きされている状態)となる つまり sg_web は tcp:80:0.0.0.0/0,tcp:443:0.0.0.0/0 、 sg_db は tcp:3306:10.0.0.0/16 が代入されている状態となっている @kazzpapa3 / #midosuji_tech 21 / 30
  10. 連想配列の違い シェル 連想配列構文 zsh ${(k)array[@]} など () を用いたフラグ構文を採用している 他に、以下のような展開フラグが存在する -

    (v) - values(値)を取得 - (kv) - keys and values(キーと値のペア) - (u) - unique(重複削除) bash ${!array[@]} のように 間接参照演算子 ! を使用する間接参照(indirect expansion)構文が採用されている array[@] が配列の全要素を指し、 ! + 配列名 とすることで その配列のキー(インデックス)を返却する仕組み 上記のような差があるため、先ほどのサンプルスクリプトは zsh が標 準インストールされていない Amazon Linux 2023 などでは正常に動 作しない @kazzpapa3 / #midosuji_tech 22 / 30
  11. macOS も bash にするべきなのか 手元の Kiro CLI がいうには答えは No だそう

    インタラクティブシェルと shebang で指定されたシェルは別である ため 普段使いのインタラクティブシェルには、優れた補完機能や Oh My Zsh などのフレームワークの利便性を考慮して zsh で問題ない shebang を正しく指定する 、 bash -euo pipefail オプションを利用 して bash 互換性を確認する ことで「ローカルの使い勝手」と「本 番環境での動作保証」を両立することが可能 @kazzpapa3 / #midosuji_tech 24 / 30
  12. bash -euo pipefail オプション付きでの実行 % bash -euo pipefail create-security-groups.sh create-security-groups.sh:

    line 4: declare: -A: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...] -e (errexit) コマンドのステータスが 0 以外で終了したらスクリプトを停止 -u (nounset) 未定義の変数を参照したらエラーで停止 -o pipefail パイプライン内のコマンドが 1 つでも失敗したら、パイプライン全 体を失敗とみなす 25 / 30
  13. シェルスクリプト開発時の注意(特に Mac な人) 実行させる環境が変わると動作しない可能性があることを念頭におく 移植性を考えた「シェルスクリプト」として組み立てる際は bash で動 作するように shebang を忘れない

    開発時には bash -euo pipefail オプションを利用して bash 互換性を 確認する インタラクティブシェルの利便性がある、というものの、開発は実機に 近い環境でする、として macOS でやらないという選択肢もありかも Amazon Linux 2023 ベースとなる AWS CloudShell 環境を利用す る、というのはあながち悪い選択肢ではないかもしれない @kazzpapa3 / #midosuji_tech 27 / 30