Dev containers環境で利用するVS Code拡張機能インストールシェルの作成

# 背景  
このシェルスクリプトを作成した背景としては、  ローカルPCの環境をできる限り汚したくないという思想  
[Visual Studio Code 拡張機能の選定](https://qiita.com/Linux-Recoil/items/07370bd9916cb41fb81d)  
↑前回投稿の記事に基づく  
・開発環境はDockerで整え、自PCにコンパイラやインタプリタを入れずコンテナ内で準備する  
・エディタとしてVS CodeやCursorを使用し拡張機能についても言語依存するものはリモート環境にのみ入れる  

という考えのもと作成したものである。

# リモート環境にVS Code拡張機能をインストールする方法
コンテナ内でVS Code拡張機能をインストールする方法は３つ把握している。  
1. リモート環境に接続後、ボタン押下して１つずつインストール
1. 「.devcontainer.json」に記述し、コンテナ起動時にインストールさせる
1. インストールコマンドをCLIで実行しインストール(codeコマンドなど)


これらのうち  
①は手間すぎて論外  
②はコンテナ初起動時は良いが、起動済みコンテナへのアタッチ時に動かない(自分の場合はそうでした)
③シェルスクリプトにコマンドをまとめれば、一気にインストールできる  

↑このように考え、シェルスクリプトであれば、  
ローカルPCにあるシェルスクリプトをリモート環境にCOPYして持っていき実行すれば  
**起動済みコンテナへのアタッチ時に動かない問題もシェルを実行すれば済む**

# 作成したシェルスクリプト

以下に作成したシェルを記載する  
自分で実施して動作確認済みである  

| アプリ等 | バージョン | 概要 |
|:-----------|------------:|:------------:|
| Windows 10 Home       | 22H2        | OS        |
| Visual Studio Code    | 1.96.3      | エディタ   |
| Docker Desktop        | 4.35.1      | Docker    |


```
#!/bin/bash

# 定数定義
readonly LANGUAGE_LIST="Java, Python, C++"

# 引数が1つ渡されているか確認
if [ $# -ne 1 ]; then
  echo "引数に言語名($LANGUAGE_LIST)を1つ指定してください。"
  exit 1
fi

# 指定された言語名を変数に格納
language="$1"

# インストールに失敗した拡張機能を格納するための配列を定義
fail_extension_array=()

# 配列の要素の拡張機能を順にインストールする関数
install_extension() {

  # ログインユーザ名取得
  user_name=$(whoami)

  # 拡張機能がインストールされているディレクトリ
  if [ "$user_name" = "root" ]; then
    extensions_dir="/root/.vscode-server/extensions"
  else
    extensions_dir="/home/$user_name/.vscode-server/extensions"
  fi

  # インストール済みの拡張機能フォルダ名配列
  directories=($(ls $extensions_dir))
  
  local extensions=("$@")  # 関数内のローカル変数として配列を受け取る
  
  for extension in "${extensions[@]}"
  do
    # インストール済みか確認しフラグを設定
    installed_flag=0
    for element in "${directories[@]}"; do
      if [[ "$element" == *"$extension"* ]]; then
        # 拡張機能ディレクトリに拡張機能名を含むディレクトリあり
        
        # フラグ更新
        installed_flag=1
      fi
    done
    if [ ${installed_flag} -gt 0 ]; then
      echo "$extension はインストール済みです。"
    else
        # 拡張機能のインストール
        echo "Installing extension: $extension"
        code --install-extension $extension
        # インストール結果の確認
        if [ $? -eq 0 ]; then
          echo "拡張機能のインストールが完了しました。"
        else
          fail_extension_array+=($extension)
          echo "拡張機能のインストール中にエラーが発生しました。"
        fi
    fi
  done
}

# 言語ごとのインストールする拡張機能を定義
# 配列はカンマ(,)で区切らないこと!!! インストールに失敗する

## 共通（言語に依存しない拡張機能）
common_extensions=(
  "ms-azuretools.vscode-docker"
  "gruntfuggly.todo-tree"
  "pkief.material-icon-theme"
  "techiecouch.git-essentials"
  "aaron-bond.better-comments"
  "albert.tabout"
  "alefragnani.bookmarks"
  "christian-kohler.path-intellisense"
  "chrmarti.regex"
  "esbenp.prettier-vscode"
  "formulahendry.auto-close-tag"
  "formulahendry.auto-rename-tag"
  "johnpapa.vscode-peacock"
  "mosapride.zenkaku"
  "oderwat.indent-rainbow"
  "shardulm94.trailing-spaces"
  "streetsidesoftware.code-spell-checker"
  "usernamehw.errorlens"
)

## Java
java_extensions=(
  "vscjava.vscode-java-pack"
  "vmware.vscode-boot-dev-pack"
)

## Python
python_extensions=(
  "ms-python.python"
)

## C++
cpp_extensions=(
  "ms-vscode.cpptools-extension-pack"
)


# 指定された言語名に基づいて拡張機能をインストール
case "$language" in
  Java)
    echo "Installing Java extensions..."
    # 関数を呼び出して拡張機能配列の要素をインストール
    install_extension "${java_extensions[@]}"
    ;;
  Python)
    echo "Installing Python extensions..."
    # 関数を呼び出して拡張機能配列の要素をインストール
    install_extension "${python_extensions[@]}"
    ;;
  C++)
    echo "Installing C++ extensions..."
    # 関数を呼び出して拡張機能配列の要素をインストール
    install_extension "${cpp_extensions[@]}"
    ;;
  *)
    echo "無効な言語名です。$LANGUAGE_LISTのいずれかを入力してください。"
    exit 1
    ;;
esac

echo "Installing Common extensions..."
# 関数を呼び出して拡張機能配列の要素をインストール
install_extension "${common_extensions[@]}"

# インストール結果の確認
if [ ${#fail_extension_array[@]} -gt 0 ]; then
  echo "拡張機能のインストールが異常終了しました。"
  echo "失敗した拡張機能は以下です。"
  for extension in "${fail_extension_array[@]}"
  do
    echo "$extension"
  done
else
  echo "拡張機能のインストールが正常終了しました。"
fi
```

# 使用方法

・common_extensionsに必ず入れる拡張機能を記載  
・LANGUAGE_LISTによく扱う言語を記載  
・↑に記載した言語に対応する拡張機能を配列で準備  
・case文を改修  

# 実施時に沼った点
リモート接続したUbuntuの開発環境上で  
sh 作成したシェル  
↑のように実行したが、配列のところでエラーとなった。

shだとシェルの問題で配列が上手くいかないため、Bashで実行するべきです。