Bash シェルスクリプトのデバッグや入力補完ができる Visual Studio Code 拡張機能（WSL2,mac,Linux対応）

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/a0130cac-313a-8558-0206-b6c88c1d9dc4.png"/>


## シェルスクリプトにも統合開発環境を

Bash のシェルスクリプト (shell script) は Linux はもちろん mac や Windows でも動作します。 シェルスクリプトの文法にはかなりクセがありますが、仕様が安定しているために移植する必要がないという大きなメリットがあります。ただ、一般的なプログラミング言語と異なり、デバッガーが使えないため期待した動作と異なるときに動きが分かりづらいという弱点がありました。 しかし、それはもう過去の話です。

Visual Studio Code の Bash Debug 拡張機能を使えば、シェルスクリプトでもステップ実行や環境変数の値のウォッチができるようになり、動きが分かるようになります。 また、Bash IDE 拡張機能を使えば、パンくずリストに変数や関数を一覧することや関数の定義にジャンプすることやコード入力補完ができるようになります。

本記事では、Windows10 21H1 以降, Windows 11 21H1 以降, mac, SSH接続した Linux のそれぞれで、Visual Studio Code を使った Bash シェルスクリプトのデバッグ環境をセットアップする手順を紹介します。

また、この手順を通して、WSL2 の使い方や、シークレット（パスワード等）の取り扱いも学べます。

## セットアップしたらできること

セットアップする作業に入る前に、セットアップしたらできるようになることを確認しておきましょう。

### D.1. Bash Debug の各種機能

#### ブレークポイント

行番号の左をクリックすると ブレーク ポイント を設定できます。 ブレークした状態で F5 キーを押す（続行する）と、次のブレークポイントの直前まで実行してブレークします。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/ceec59ff-6414-97ec-4b05-5e551ac5fc53.png"/>

このスクショにおけるウィンドウの左半分は、左端にならんだボタンの上から 4つ目のボタンを押して表示される Run and Debug ビューです。 Windows では Shift + Ctrl + D キー、mac では Shift + Command + D キー を押しても Run and Debug ビューが表示されます。
 

#### ステップ実行

ブレークした状態で F10 キーを押すと ステップ オーバー で 1行実行します。F11 キーを押すと ステップ イン で関数の中に入ります。

他のシェルスクリプトを呼び出すところで ステップ イン することはできません。 呼び出した先のシェルスクリプトをデバッグしたくなったときは、次のリンク先を参照してください。 [→ U.6.b. 子プロセスのシェルスクリプトをデバッグできるようにします（オプション）](#u6b-子プロセスのシェルスクリプトをデバッグできるようにしますオプション)


#### ウォッチ

ブレークした状態になると、LOCAL ビューに カレント フォルダー のパス `$PWD` の値と、直前に実行したコマンドの終了ステータス `$?` の値が表示されます。 また、ウォッチに入力しておいた環境変数について、その値が表示されます。 ウォッチに環境変数を追加するには、WATCH ビューにカーソルを合わせて右上の ＋ を押します。 配列を表示する場合、環境変数名の前に `$` をつけないでください。

<img width="60%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/0da1c4e2-ab26-802a-a3ca-7570e2d9dfce.png"/>

マウスカーソルをコード上の変数に合わせて値を表示することもできます。 

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/ff954067-788d-6122-a502-aba32e40238d.png"/>

#### コール スタック

ブレークした状態で、呼び出し元の関数を一覧できます。 上に表示される関数ほど深い位置（呼び出し先）にあります。 呼び出し元の関数名をクリックすると、その関数を呼び出すコードを表示することができます。 一般のプログラミング言語では関数名をクリックすると、その関数の中のコードを表示しますが、それに比べると 1レベルずれているので注意してください。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/06dcf9ab-1f2a-3379-6f9d-f41a3dcbc09f.png"/>


### D.2. Bash IDE の各種機能

Bash IDE 拡張機能をインストールすると、関数や変数を一覧することや、関数の定義にジャンプすることができるようになります。

#### 関数一覧、変数一覧（パンくずリスト）

スクリプトを表示している領域の上端に表示されているファイル名の右をクリックすると、関数名や変数名が一覧されます。 関数名や変数名をクリックすると、その定義を表示します。

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/348da6c6-c706-9471-448e-19abe9aa69ca.png"/>

#### 呼び出し先

Ctrl キー を押しながら呼び出す関数名をクリックすると、その関数の定義にジャンプして表示します。 mac では command キー です。

<img width="20%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/2880def1-d058-f6b6-6e2b-dc71e5ba4732.png"/>

#### コード入力補完

関数名の一部を入力すると、定義済みの関数の一覧が表示され、選択すると完全な関数名を入力できます。

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/f45e28ab-6700-fc75-508f-5af6b0809b24.png"/>


#### 簡易ヘルプ表示

基本的なコマンドに関しては、コマンド名を入力すると簡単なヘルプを表示できます。 英語ですが。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/1495455b-9429-12db-484b-c7eee93070fa.png"/>


## Windows の場合

Windows の Bash Debug 拡張機能は WSL2 (Windows Subsystem for Linux 2) を必要とします。 WSL2 の中に複数のディストリビューションを配置できますが、その中でも既定のディストリビューションを使います。 Bash Debug 専用のディストリビューションを用意する必要はありません。

以前は WSL2 のセットアップが大変でしたが現在では少ないコマンドで WSL2 をインストールできるようになりました。 以下で WSL2 のセットアップ方法も含め、スクリプトをデバッグできる Visual Studio Code のインストール方法を説明します。

なお、Bash Debug 拡張機能は Git bash をインストールしても Git bash では動作しません。 このためパスの書き方が少し異なります。

[→ Windows と WSL2 と Git bash のパスの関係](#windows-と-wsl2-と-git-bash-のパスの関係)


### W.1. WSL2 をインストールします

#### W.1.a. CPU の仮想化支援機能が有効になっていることを確認します

仮想化支援機能(Intel VT-X/AMD-V)が有効になっていることを確認します。 仮想化支援機能は WSL2 を動作させるために必須の CPU の機能です。

スタート ボタン を右クリック >> タスク マネージャー >> 詳細（左下にあれば）>> パフォーマンス タブ >> CPU（左）を選び、仮想化の項目を確認します。

無効になっている場合、有効に設定してください。 設定方法は PC の機種によって異なります。ネットを検索してください。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/a62449a8-0c2b-0980-266f-7a4b4d450a76.png"/>


#### W.1.b. Windows 10 21H1 より前の場合

現在の Windows のバージョンを確認するには、Windows >> 設定 >> システム >> バージョン情報 >> Windows の仕様 を確認します。 

Windows 10 21H1 より前の場合、インストール手順がとても複雑なので Windows 10 21H1 以降にバージョンアップしてください。 どうしても Windows をバージョンアップしたくないときは、WSL2 をインストールする方法がネットを検索すれば見つかりますが、Bash Debug が使えることは確認できていません。 なお、Windows 10 2004 より前のバージョンは、WSL2 をインストールすることができないので、シェルスクリプトのデバッグはできません。

#### W.1.c. Windows 10 21H1 以降の場合

WSL2 をインストールします。

キーボードの Windows キーを押して PowerShell と入力して表示された PowerShell を右クリックして「管理者として実行」を選びます。

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/8a0d2a59-f942-7aa8-86e9-09a2f10d035d.png"/>

以下のコマンドを入力します。

    wsl --list --online

インストールできるディストリビューションが一覧されます。 WSL2 では メジャー バージョン が違うときでも別のディストリビューションとして扱うようです。

    NAME            FRIENDLY NAME
    Ubuntu          Ubuntu
    Debian          Debian GNU/Linux
    kali-linux      Kali Linux Rolling
    openSUSE-42     openSUSE Leap 42
    SLES-12         SUSE Linux Enterprise Server v12
    Ubuntu-16.04    Ubuntu 16.04 LTS
    Ubuntu-18.04    Ubuntu 18.04 LTS
    Ubuntu-20.04    Ubuntu 20.04 LTS

Ubuntu-20.04 をインストールします。 おそらく他のディストリビューション（OSやバージョン）でも構いません。

    wsl --install -d "Ubuntu-20.04"

もし、PC の再起動が要求されたら、PC を再起動してください。 **更新して再起動** が表示されているときはそちらを選んでください。 Windows 10 では、再起動後、自動的にインストールの続きが行われます。 Windows 11 では、再起動後、もう一度上記 `wsl --install` コマンドを管理者として実行します。

    要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。

インストールが完了するまで 1分〜6分かかります。

    Installing, this may take a few minutes...

インストールが完了したら自動的に Linux のユーザー名とパスワードを入力することを要求されるので入力します。 Linux についてよくわからない方は、ユーザー名は user1 などの適当な名前で構いません。 また、WSL の Linux は Windows によって保護されているので、パスワードは user1 のようにバレやすくても覚えやすいもので構いません。

    Enter new UNIX username: user1
    New password: *****
    Retype new password: *****

bash のプロンプトが表示されたら、一度 Linux からログアウトします。

    exit


#### W.1.d. WSL2 の既定のディストリビューションを設定します

もし、WSL2 のディストリビューションが 2つ以上ある場合、既定のディストリビューションを Bash Debug が使うディストリビューションに設定する必要があります。 ただし。既存のディストリビューションを Bash Debug が使っても問題ありません。 Bash Debug 専用のディストリビューションを用意する必要はありません。 既定のディストリビューションを変更する場合、PowerShell で以下のコマンドを入力します。 

    wsl --list                       #// 指定できるディストリビューションを一覧します
    wsl --setdefault "Ubuntu-20.04"  #// 既定のディストリビューションを Ubuntu-20.04 に設定します。 Bash Debug はこれを使います

設定したら PowerShell のウィンドウを閉じます。

（メモ）既定のディストリビューションに設定されている Linux のシェルにログインするには、管理者ではない PowerShell を開き、以下のコマンドを入力します。

    wsl

プロンプトの行頭から PS が消えることで Linux のシェルが開いたことを確認できます。

既定以外のディストリビューションにログインしたい場合は、`wsl --list` または `wsl -l` でディストリビューション名を確認して、以下のコマンドを入力します。

    wsl -d "Ubuntu-20.04"


### W.2. Visual Studio Code をインストールします

https://code.visualstudio.com/ から Visual Studio Code をダウンロードして Windows にインストールします。 インストール オプションは既定のままで構いません。 インストールしたら Visual Studio Code をタスクバーにピン止めしておくことをお勧めします。

Visual Studio Code を開いて、下記の拡張機能(Extensions)をインストールします。 Visual Studio Code の左端にある Extensions ボタンを押して検索してインストールします。

- Bash Debug
- Bash IDE
- Copy Relative Path Posix （オプション）

Copy Relative Path Posix は Visual Studio Code でパスをコピーしたときのフォルダーの区切り記号を \ ではなく / にする拡張機能です。

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/a0b79751-a5a4-d763-9a84-18d23c3ac595.png"/> &nbsp; <img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/994302c6-cc05-e2f2-e4ad-e454f1e7a1d0.png"/>

また、Ctrl + S キーを押したときに全てのファイルを保存するように設定しておくことをお勧めします。

- VSCode >> 歯車アイコン（左下）>> Keyboard Shortcuts >> save all （と入力） >>
    File: Save All （をダブルクリック） >> Ctrl + S キー >> Enter キー

Visual Studio Code のウィンドウを閉じます。

Visual Studio Code を開くフォルダーを作ります（今まではフォルダーを開かずに Visual Studio Code を開いていました）。 新しく PowerShell を開いて下記のコマンドで `/Users/__UserName__/bin` フォルダーを作ります。

    mkdir bin

PowerShell のウィンドウを閉じます。


### W.3. デバッガーを起動します

#### W.3.a. Visual Studio Code を開きます

Visual Studio Code で bin フォルダーを開く場合、新しく PowerShell を開き、以下のコマンドを入力します。

    code bin

2回目以降は、タスク バー にピン留めした Visual Studio Code を右クリックして表示される履歴から開くこともできます。 履歴には Windows のフォルダーだけでなく WSL2 のフォルダーも表示されます。

セキュリティの警告がされますが空のフォルダーなので信頼します(Yes を押します）。 PowerShell のウィンドウは閉じます。

`bin` は Visual Studio Code で開くフォルダーのパスです。 PowerShell を新しく開いた直後の カレント フォルダー は `/Users/__UserName__` なので、`/Users/__UserName__/bin` フォルダーを Visual Studio Code で開きます。

なお、開いたフォルダーを `__Project__` としたとき、以降で行うデバッガーの設定は `__Project__/.vscode/launch.json` ファイルに保存されます。

#### W.3.b. サンプル シェルスクリプト を作ります

デバッグするシェルスクリプトが特になくデバッガーの動きを試したいときは、以下のスクリプトを作ります。

`__Project__/example.sh`

    #!/bin/bash
    Keyword="abc"
    echo "${Keyword}"

    function  EchoArgument() {
        echo  "$1"
    }

    EchoArgument  "ABC"

新しくファイルを作るときは、Visual Studio Code の EXPLORER ビューの何もないところを右クリックして New File を選び、ファイル名を入力します。

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/18858e26-b057-d6e0-1c26-3e7f8f9364ff.png"/>

Linux や mac や Ubuntu (on WSL2) の場合は chmod コマンドで実行属性をファイルに付ける必要があります、`bin` を開いている Visual Studio Code の Terminal メニューから新規ターミナルを開いて、以下のコマンドを実行します。 Windows の Git Bash の場合は、ファイルの 1行目にシェバン `#!/bin/bash` があると自動的に実行属性が付いているものとして扱われます。

    chmod +x example.sh

#### W.3.c. デバッグの設定をします

Visual Studio Code の左にある Run and Debug ボタンを押して、create a launch.json file をクリック、`Bash Debug` を選ぶと、下記に近い内容の設定ファイルが作られます。 このファイルにデバッグの設定を書いてください。 直接下記の JSON ファイルを作っても構いません。 上記の サンプル シェルスクリプト をデバッグする場合、下記 JSON をコピペして Ctrl + S キーで保存すれば、そのまま編集せずに使えます。

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/5946c1eb-1f8b-da6c-801c-f9ea115d7a82.png"/>

`__Project__/.vscode/launch.json`:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "type": "bashdb",
                "request": "launch",
                "name": "Bash-Debug (simplest configuration)",
                "program": "${workspaceFolder}/example.sh",
                "cwd": "${workspaceFolder}",
                "args": []
            }
        ]
    }

Windows の場合、このファイルに設定するパスはすべて **WSL2 でのパス**です。 Bash Debug 拡張機能がデバッグ実行するときは WSL2 で動作するためです。 Visual Studio Code が開いているフォルダーの中のパスを書く場合、下記の program フィールドの説明を参考にしながら設定してください。 Visual Studio Code が開いているフォルダーの外のパスを書く場合、下記のリンク先の説明を参考にしながら設定してください。

[→ Windows と WSL2 と Git bash のパスの関係](#windows-と-wsl2-と-git-bash-のパスの関係)

また、デバッグ実行時の**環境変数は Windows と WSL2 で異なる**ことにも注意が必要です。 Git bash をインストールしてもデバッグ実行時は Git bash で動作しません。 Git bash は Windows の環境変数を継承しますが WSL2 は継承しません。 

| フィールド名 | 説明 | サンプル |
| ---------- | ---- | ------ |
| program | デバッグ実行するシェルスクリプトのパス。`${workspaceFolder}` を書くと Visual Studio Code が開いているフォルダーを指定したことになります。フォルダーの区切り記号は `/`。ファイル名のタブを右クリックして Copy Relative Path (POSIX) を選ぶと `/` 区切りの相対パスをコピーでき、program フィールドにそのまま貼り付けることができます。 `${file}` を書くと現在カーソル（キャレット）があるファイルをデバッグ実行します。 | `${workspaceFolder}/example.sh` |
| cwd | デバッグ実行するときの カレント フォルダー のパス | `${workspaceFolder}/test`, `/home/$USER/_work` |
| args | シェルスクリプトに渡す引数。`$USER` 形式の環境変数は指定できますが、`${USER}` 形式の環境変数は指定できません。 指定できる環境変数は WSL2 の Linux に定義されているものです。 | `[]`, `["1"]`, `["1", "2"]`, `["${workspaceFolder}/test"]`, `["/home/$USER/_work"]`。|


#### W.3.d. デバッグ実行を開始します

F5 キーを押すと、デバッグ実行を開始します。もしくは、Run メニューの Start Debugging を選びます。実行を開始すると、シェルスクリプトの最初に実行するコマンドでブレークします。

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/370d4176-6fff-8be3-b324-37095c0a8638.png"/>

再び F5 キーを押すと続行して次のプレークポイントまたは最後まで実行します。

[→ ブレークポイント](#ブレークポイント)

echo の出力は、DEBUG CONSOLE ビュー に表示されます。 内部で動いている bashdb に対する動作が赤色のメッセージで表示されますが無視できます。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/182d69b6-42bf-b5f0-d32c-86cc62b93093.png"/>

もし、スクリプトを再起動するたびに出力先のフォルダーの内容を元に戻したい場合、つまり、出力する前の内容が入ったフォルダーから出力先のフォルダーにコピーしたい場合は、スクリプトの先頭で出力先のフォルダーの内容を削除して元の内容をコピーするシェルスクリプトを起動するとよいでしょう。

[→ U.5.d. 出力先のフォルダーを元に戻すスクリプトを作ります](#u5d-出力先のフォルダーを元に戻すスクリプトを作りますオプション)


## Ubuntu (on WSL2) の場合

Bash Debug が動作している WSL2 は **Windows に入っているファイルにアクセスするのがかなり遅い**です。 なぜなら、WSL2 の Linux のファイルシステムと Windows のファイルシステムが別々に存在し、ファイルシステムを跨いてファイルにアクセスするときは仮想的なネットワークを経由しているからです。 その遅さを解消したい場合は、WSL2 の上で動いている Ubuntu のフォルダーに必要なファイルをすべてコピーしてからシェルスクリプト等を実行します。

以下では、WSL2 の Ubuntu のフォルダーを開けるように Visual Studio Code に WSL と接続する拡張機能をインストールして軽快にデバッグできるようにする手順を説明します。

### Windows と WSL2 と Git bash のパスの関係

WSL2 では Linux から Windows のフォルダーにアクセスすることや、逆に Windows から Linux のフォルダー（ディレクトリ）にアクセスすることのどちらでもできます。

ただし、同じファイルであっても、アクセスするときのパスが Windows と Linux (on WSL2) で異なることに注意が必要です。 同じ Visual Studio Code のウィンドウであっても、PowerShell のターミナルに入力するフルパスと、Git bash のターミナルに入力するフルパスと、Linux (on WSL2) のターミナルや Bash Debug の設定に入力するフルパスが異なります。

| Windows              | Linux on WSL2 | Git bash             |
| -------------------- | ------------- | -------------------- |
| `C:\` または `c:/`    |  `/mnt/c/`    | `c:/`                |
| `\\wsl$\__Distro__\` |  `/`          | `//wsl$/__Distro__/` |

たとえば、Windows の `C:\Users\User1\a.txt` ファイルに Linux (on WSL2) からアクセスするときは `/mnt/c/Users/User1/a.txt` というパスを Linux に指定します。

Ubuntu Linux の `/home/user1/a.txt` ファイルに Windows からアクセスするときは `\\wsl$\Ubuntu-20.04\home\user1\a.txt` というパスを Windows に指定します。 ディストリビューションが Ubuntu-18.04 の場合は `\\wsl$\Ubuntu-18.04\home\user1\a.txt` というパスを Windows に指定します。 エクスプローラーに `\\wsl$` と入力してディストリビューションの一覧を表示することもできます。

なお、Linux on WSL2 のファイルの実体は、Windows の `"${env:USERPROFILE}\AppData\Local\Packages\${PackageFamilyName}\LocalState"`（設定によっては他の場所）にある仮想HDD ファイルの中にあります。 Git bash だけインストールしたときは、仮想HDD ファイルは無く、Windows のファイルだけ存在します。 

### U.1. WSL2 をインストールしてシェルを開きます

WSL2 をインストールする手順は Windows の場合と同じです。 すでに Windows に WSL2 と Linux がインストール済みならこの手順は不要です。

[→ W.1. WSL2 をインストールします](#w1-wsl2-をインストールします)

Linux にログインできるようになったら次に進みます。
Linux にログインするには Visual Studio Code のターミナル（推奨）、または、管理者ではない PowerShell を開き、以下のコマンドを入力します。

    wsl

プロンプトの行頭から PS が消えることで Linux のシェルが開いたことを確認できます。

### U.2. ターミナルの環境を整備します（オプション）

既定のままではターミナルが少し使いにくいので整備しましょう。 ただ、整備しなくてもデバッガーは動くので、この手順をスキップしても構いません。 必要になったら設定してください。

#### U.2.a. ~/bin に PATH を通します（オプション）

シェルスクリプトのファイルを PATH の通ったフォルダーに入れておくと、カレント フォルダー がどこであってもコマンド名＝ファイル名になります。 もし、PATH が通っていないとシェルスクリプトが入ったフォルダーのパスも入力しなければならなくなり大変です。 慣習として `~/bin` (`$HOME/bin`) に PATH を通すことが多いようなので、そこに PATH を通しましょう。

Ubuntu のシェルから以下のコマンドを入力します。

    nano  ~/.bashrc

開かれたファイルの末尾に、PATH 環境変数に `~/bin` を追加するスクリプトを追記します。

    export  PATH="$HOME/bin:$PATH"

次の設定も `~/.bashrc` ファイルを編集するので開いたままにします。

#### U.2.b. USERPROFILE 環境変数を設定します（オプション）

Windows と WSL2 の Ubuntu では環境変数を共有しません。 USERPROFILE 環境変数に同じフォルダーを指すように設定しておくと便利です。

開いている `~/.bashrc` ファイルの末尾に、USERPROFILE 環境変数の定義を追加して保存します。 `__UserName__` の部分は Windows の USERPROFILE 環境変数の値を参考に設定します。 デスクトップやドキュメントの親フォルダーの名前です。

    export  USERPROFILE=/mnt/c/Users/__UserName__

ちなみに `__UserName__` を自動的に取得するスクリプトは以下のようになりますが、基本的に USERNAME が変わることはないので、以下のスクリプトは不要です。

    export  USERPROFILE="/mnt/c/Users/$( cmd.exe /c 'echo %USERNAME%' )";
    export  USERPROFILE="${USERPROFILE:0:${#USERPROFILE}-1}"  #// Cut last CR

次の設定も `~/.bashrc` ファイルを編集するので開いたままにします。

#### U.2.c. ターミナルの文字を見やすくします（オプション）

Windows 10 の PowerShell から wsl コマンドで Ubuntu にログインすると、フォルダーの文字の色が暗くて見にくいため、シアンという明るい色に変えましょう。 シアンはフォルダーへのシンボリックリンクの色と同じですが問題ありません。 なお、Visual Studio Code のターミナルでは見にくいことはありません。

<img width="35%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/d0b7a49c-a11e-24d1-7ff0-0f6904512fbb.png"/> &nbsp; <img width="35%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/5691ce6f-17f2-54ea-f46c-7865c51f8049.png"/>

開いている `~/.bashrc` ファイルの末尾に、プロンプトの一部の色を変えるスクリプトと、ls コマンドで表示される文字の色を変えるスクリプトを追記します。 下記は、プロンプトの `$` の前に空白を入れるスクリプトも入っています。 

    export PS1="$( echo "$PS1" | sed 's/;34m/;36m/g' )"  #// Change a prompt from blue to cyan
    export PS1="$( echo "$PS1" | sed 's/\\\$/ \\$/' )"   #// Insert a space before $ in a prompt
    eval $( dircolors | sed "s/di=[0-9]*;[0-9]*:/di=01;36:/" )  #// Change ls command color to cyan

#### U.2.ｄ. ~/.bashrc の設定を有効にします

nano コマンドでファイルを開いている場合、Ctrl + X キーと Y Enter で保存・終了します。

以下のコマンドを入力して、保存した設定をすぐに有効にします。 なお、このコマンドは設定を書いたすぐに有効にするときだけ必要で、ターミナルを開き直したときは `~/.bashrc` ファイルが実行され設定が自動的に有効になります。

    source  ~/.bashrc

### U.3. Linux に最新のセキュリティ更新を適用します

シェルスクリプトのデバッグだけであればセキュリティの更新をする必要はないかもしれませんが、更新しておいた方が安全です。 Linux は手動でセキュリティの更新が行うことが好まれているようなので、以下の手順を行わなければ更新は行われません。

#### U.3.a. プロキシがある環境の場合の Ubuntu の設定 (1)

会社など大きな組織の建物の中では、プロキシを経由しないと Linux からインターネットにアクセスできないため、以下の手順が必要です。

まず、sudo したときもプロキシに関する環境変数を継承するように設定します。設定に使う テキスト エディター を開くには、**Linux のシェルで**以下のコマンドを使います。特殊なファイルを安全に扱うため、これ以外のコマンドを使わないでください。

    sudo visudo

env_keep の設定を追加します。

編集前:

    Defaults        env_reset

編集後:

    Defaults        env_reset
    Defaults        env_keep = "http_proxy ftp_proxy ftp_proxy DISPLAY XAUTHORITY"

（Ubuntu の場合）Ctrl + X キーと Y Enter で保存して テキスト エディター を終了します。

#### U.3.b. プロキシがある環境の場合の Ubuntu の設定 (2)

次に、プロキシの URL を設定します。 URL は会社によって異なるので IT 管理者に聞いてください。 以下のコマンドでファイルを開きます。

    sudo nano /etc/apt/apt.conf

追加する内容:

    Acquire::http::Proxy "http://____";

保存して テキスト エディター を終了します。

#### U.3.c. Linux を最新に更新します

（Ubuntu の場合）以下のコマンドを入力します。

    sudo apt update -y && sudo apt upgrade -y

更新が完了するまで 2分〜3分半かかります。


### U.4. Visual Studio Code をインストールします

#### U.4.a. Windows に Visual Studio Code をインストールしていない場合

すでに Windows に Visual Studio Code がインストール済みならこの手順は不要です。

Visual Studio Code をインストールします。 手順は Windows の場合と同じです。

[→ W.2. Visual Studio Code をインストールします](#w2-visual-studio-code-をインストールします)

#### U.4.b. Visual Studio Code と Linux on WSL2 を接続します（プロキシがある環境の初回の場合）

初めて Visual Studio Code と Linux on WSL2 を接続するときは、接続に必要なプログラムを自動的にダウンロードしようとします。

会社など大きな組織の建物の中では、プロキシを経由しないと Linux からインターネットにアクセスできないため、以下の手順が必要です。

Ubuntu のシェルから以下のコマンドを入力します。

    nano  ~/.bashrc

開かれたファイルの末尾に、プロキシの URL などを追加して保存します。 なお、no_proxy の値は書かれているままに設定します。

    export  http_proxy="http://____"
    export  https_proxy="http://____"
    export  no_proxy="127.0.0.1, localhost"

以下のコマンドを入力して、保存した設定をすぐに有効にします。 なお、このコマンドは設定を書いたすぐに有効にするときだけ必要で、以後はこのコマンドの実行は不要です。

    source ~/.bashrc

Visual Studio Code を Linux on WSL2 と接続するためのプログラムをインストールをするには、下記のコマンドをそのままコピペして入力します。 末尾の `~` も入力します。 ちなみに --proxy-server オプションと --proxy-bypass-list オプションは、インストールするときだけ必要です。 末尾の `~` は Linux のホーム `/home/__UserName__` に相当する特殊記号で、インストール直後に開くフォルダーとして指定しています。

    code --proxy-server="http=$http_proxy;https=$https_proxy" --proxy-bypass-list="$no_proxy" ~

#### U.4.c. Visual Studio Code と Linux on WSL2 を接続します（プロキシがない環境の場合、2回目以降の場合）

Ubuntu のシェルから以下のコマンドを入力すると Visual Studio Code を Linux on WSL2 と接続するためのプログラムをインストールして接続します。 引数の `~` は Linux のホーム `/home/__UserName__` に相当する特殊記号で、インストール直後に開くフォルダーとして指定しています。

    code ~

開いた Visual Studio Code の左下に緑色の背景で WSL と表示されていなければ、Visual Studio Code の左端にある Extensions ボタンを押して Remote Development を検索してインストールし、再度 `code ~` を実行します。

- Remote Development

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/f9383854-de08-2073-d8d9-c74748760143.png"/>

#### U.4.d. Visual Studio Code の拡張機能をインストールします

Visual Studio Code を開くフォルダーを作ります。 新しく Linux のシェル を開いて下記のコマンドで `/Users/__UserName__/bin` フォルダーを作ります。 なお、開いたフォルダーを `__Project__` としたとき、以降で行うデバッガーの設定は `__Project__/.vscode/launch.json` ファイルに保存されます。

    mkdir ~/bin

Visual Studio Code を開きます。

    code ~/bin

下記の拡張機能(Extensions)を Linux on WSL2 にインストールします。 Windows にインストール済みであっても Linux on WSL2 へのインストールが必要です。 Visual Studio Code の左端にある Extensions ボタンを押して検索してインストールします。 インストールするボタンが表示されたらインストールしてください。

- Bash Debug
- Bash IDE
- Remote Development  （Ubuntu on WSL2 では必須ですが、この手順ではすでにインストール済み）

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/0700b11f-ffcb-02d4-ac4b-223f53fb89d9.png"/> &nbsp; <img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/ce67afd0-7c4d-aa14-883a-f08db18c8f13.png"/>

Visual Studio Code のウィンドウを閉じます。


### U.5 デバッガーを起動します

#### U.5.a. WSL2 上で動く Linux のシェルを開きます

Ubuntu Linux のフォルダーを Visual Studio Code を開く場合、Ubuntu から Visual Studio Code を起動する必要があります。

Windows の Visual Studio Code のターミナル（推奨）、または、管理者ではない PowerShell を開き、以下のコマンドを入力します。 新しいウィンドウは開きませんが、プロンプトの行頭から `PS` が消えることで Linux のシェルが開いたことを確認できます。

    wsl

#### U.5.b. Visual Studio Code を開きます

Linux のシェルで code コマンドを実行すると Linux のフォルダーを開く Visual Studio Code が起動します。 その際、Visual Studio Code で開きたいプロジェクトのフォルダーのパスを Linux のパスで指定します。（Visual Studio Code のターミナルで実行した場合、履歴によってはすでに開いているかもしれません）

    code ~/bin

[→ Windows と WSL2 と Git bash のパスの関係](#windows-と-wsl2-と-git-bash-のパスの関係)

#### U.5.c. 処理対象のフォルダーを Windows から Linux にコピーします

Visual Studio Code を Linux のフォルダーを開いても、シェルスクリプトがアクセスするフォルダーが Windows にある場合（Linux から見て /mnt 以下に対象のフォルダーがある場合）、そのフォルダーに対するアクセスは遅いままです。 遅くならないようにするには、シェルスクリプトがアクセスするフォルダーを Linux にコピーします。

Windows のエクスプローラーなどでコピーする場合、`\\wsl$` の中にコピーします。

コピー元のサンプル (Windows)

    C:\Users\__UserName__\Desktop\input
    C:\Users\__UserName__\Desktop\output

コピー先のサンプル (Windows) wsl$ の右の Ubuntu-20.04 は WSL2 におけるディストリビューション名です

    \\wsl$\Ubuntu-20.04\home\user1\bin\input
    \\wsl$\Ubuntu-20.04\home\user1\bin\output

Linux でコピーする場合、`/mnt` の外にコピーします。

コピー元のサンプル (Linux)

    /mnt/c/Users/User1/Desktop/input
    /mnt/c/Users/User1/Desktop/output

コピー先のサンプル (Linux)

    ~/bin/input
    ~/bin/output

#### U.5.d. 出力先のフォルダーを元に戻すスクリプトを作ります（オプション）

もし、スクリプトを再起動するたびに出力先のフォルダーの内容を元に戻したい場合、つまり、出力する前の内容が入ったフォルダーから出力先のフォルダーにコピーしたい場合は、スクリプトの先頭で出力先のフォルダーの内容を削除して元の内容をコピーするシェルスクリプト `restore-folders-1` を起動するとよいでしょう。

デバッグ対象のスクリプト `__Project__/example.sh`

    #!/bin/bash
    ./restore-folders-1  # 追加
    （デバッグ対象の処理）

上記の restore-folders-1 シェルスクリプトの中に、コピー元とコピー先のフォルダーを指定します。ケースによっては複数のフォルダーをコピーする必要があるかもしれません。 その場合、下記の RestoreFolder を複数書きます。

`__Project__/restore-folders-1` シェルスクリプト

    function  Main() {
        echo  "Current Folder: ${PWD}"
        RestoreFolder  '/mnt/c/Users/____/Desktop/source'  ${HOME}'/_destination'
        echo  "Target folders have been restored."
    }

RestoreFolder 関数の内容は自作するか、以下からコピーしてください。
https://github.com/Takakiriy/Snippets/blob/main/for-bash/restore-folders/restore-folders-1

なお、上記のリンク先の RestoreFolder 関数は、フォルダーを削除してからフォルダーをコピーするのではなく、フォルダーの内容を削除してからフォルダーの内容をコピーするように工夫されています。 Linux では前者の場合、カレント フォルダー が作り直されたとしても、カレント フォルダー は削除されたフォルダー（ごみ箱に相当する場所に移動したフォルダー）になってしまいます。 つまり、そのシェルでは古い内容が見えます。 後者の場合は最新の内容が見えます。

Windows から Linux にコピーするように RestoreFolder にパスを指定すると少し遅くなります。 シンプルなのでそれでも構わないですが、もし速くしたい場合は、あらかじめ Linux の別の場所にコピーしておき、そのコピーからスクリプトの出力フォルダーにコピーします。


### U.6. デバッグの設定をして、デバッグを開始します

以降の手順は Windows でデバッグする手順と変わりません。

#### U.6.a. デバッグの設定をして、デバッグを開始します

- [→ W.3.b. サンプル シェルスクリプト を作ります](#w3b-サンプル-シェルスクリプト-を作ります)
- [→ W.3.c. デバッグの設定をします](#w3c-デバッグの設定をします)
- [→ W.3.d. デバッグ実行を開始します](#w3d-デバッグ実行を開始します)


#### U.6.b. 子プロセスのシェルスクリプトをデバッグできるようにします（オプション）

Bash Debug は他のシェルスクリプトを呼び出すところで ステップ イン することはできません。 もし、他のシェルスクリプトに ステップ イン した中のデバッグをしたくなったときは、以下の手順を行なってください。 そうでない場合は以下の手順は不要です。

ステップ イン できない理由はおそらく OS のプロセスが別々だからという技術的な制限からです。 なお、呼び出し元のプロセスを親プロセス、呼び出した先のプロセスを子プロセスと呼びます。 以下、親プロセスのシェルスクリプトのファイル名を `parent-script.sh`、子プロセスのシェルスクリプトのファイル名を `child-script` とします。

以下の手順は、どの OS でも共通です。

子プロセスのシェルスクリプトをデバッグしたい場合は、そのシェルスクリプトを起動するようにデバッグの設定を以下のように追加してください。 デバッガーに接続できるプロセスは1つだけですが、親プロセスの起動を Visual Studio Code の WSL または Git bash のターミナルから行ってから、子プロセスをデバッガーに接続することもできます。（もう1つの Visual Studio Code で別のフォルダーを開けば、2つのプロセスをそれぞれのデバッガーに接続できますが、親プロセスのスクリプトを再起動するたびにウィンドウを切り替えなければならなくなるため使いやすくありません。）

[→ W.3.c. デバッグの設定をします](#w3c-デバッグの設定をします)

以下のように設定を 2つ並べれば、デバッガーの接続先の切り替えが簡単になります。

`__Project__/.vscode/launch.json`:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Parent process",
                "type": "bashdb",
                "request": "launch",
                "program": "${workspaceFolder}/parent-script.sh",
                "cwd": "${workspaceFolder}",
                "args": []
            },
            {
                "name": "Child process",
                "type": "bashdb",
                "request": "launch",
                "program": "${workspaceFolder}/child-script",
                "cwd": "/home/user1/bin",
                "args": ["a1", "a2"]
            }
        ]
    }

デバッガーの設定を切り替えるには、Run and Debug ビューの上端にあるプルダウンから選びます。

<img width="35%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/8d1ca89c-9293-5045-5ef6-c2457beec495.png"/>

もし、子プロセスがアクセスするフォルダーが、親プロセスから呼び出されたタイミングでないと存在しない場合や、シェルスクリプトに渡される引数を知りたい場合は、親プロセスが子プロセスを呼び出す直前で一時停止して子プロセスに渡す引数を表示させます。

一時停止させたときの実行例:

    $ parent-script.sh
    "cwd": "/home/user1/bin",
    "args": ["a1", "a2"],
    break point>

このような動作をさせるには、親プロセスから子プロセスを呼び出すシェルスクリプトの代わりに、以下のようなシェルスクリプトを実行するように編集します。

親プロセスのシェルスクリプト parent-script.sh の一部:

編集前

        child-script  argument1  "${argument2}"

編集後

    if [ "${_Dbg_DEBUGGER_LEVEL}" == "" ]; then            
        echo  "\"cwd\": \"${PWD}\","
        echo  "\"args\": [\"argument1\", \"${argument2}\"],"
        read  -p "break point> "  dummyVariable
    else
        child-script  argument1  "${argument2}"
    fi

`argument1` や `${argument2}` を `echo` で表示する部分は、子プロセスのスクリプト `child-script` に渡す引数に応じて編集してください。

ターミナルから親プロセスをデバッガーなしで起動して `break point>` と表示されて一時停止してから、子プロセスのデバッグ実行を開始してください。

子プロセスの処理が完了したら、親プロセスのターミナルで Enter キーを押すと、親プロセスの続きを実行します。

`_Dbg_DEBUGGER_LEVEL` はデバッガーに接続しているときだけ数値が入ります。

#### U.6.c. シークレットを設定します（オプション）

データベースのパスワードやサービスの API キー など秘密情報（シークレット）が必要な場合、シークレットを .env ファイル や ~/.ssh フォルダー の中の環境変数だけに保存して .gitignore に設定することで、Git のリポジトリにシークレットを漏洩させないというベストプラクティスがあります。 シェルスクリプトも当然それに対応する必要があります。

また、シークレットが必要なシェルスクリプトを入手したときは、シークレットを .env ファイル などに書かなければシェルスクリプトは動きません。 以下のシェルスクリプトは、シェルスクリプトがあるフォルダーと同じフォルダーの .env ファイルにシークレットを保存する仕様です。

`.env` ファイル

    DB_USERNAME='my-db-user'
    DB_PASSWORD='SECRETX_AO%1:+<9'

シークレットの漏洩を防ぐには、Git の場合 .gitignore ファイルにファイル名 .env を書きます。

`.gitignore` ファイル

    .env

また、シークレットのパターンにマッチすることで漏洩を防ぐツールに対応するためには、パスワードを SECRETX_ から始めるなどのルールを作っておくと良いでしょう。

.env ファイルをロードするシェルスクリプトは、次のようになります。

`show-pass` シェルスクリプト

    #!/bin/bash
    function  LoadEnvironmentVariables() {
        ScriptPath="$0"
        ScriptFolderPath="${ScriptPath%/*}"

        if [ -e "${ScriptFolderPath}/.env" ]; then
            source  "${ScriptFolderPath}/.env"
        fi
    }

    LoadEnvironmentVariables  "$@"
    echo  "DB_PASSWORD = ${DB_PASSWORD}"

実行属性を付けます。

    chmod +x show-pass

実行

    $ ./show-pass
    SECRETX_DB_PASSWORD = SECRETX_AO%1:+<9
    $ clear

シークレットが表示されること自体良くないのですが、表示されたら clear コマンドでターミナルをクリアしてください。

なお、Windows 版 Bash Debug は `$0` の値がスクリプトへのパスではないことがあります。 その場合、下記のようにデバッグ実行するときだけ正しい値に修正するようにします。 なお、Bash Debug を使わない場合や mac 版 Bash Debug はスクリプトへのパスです。 PATH 環境変数で見つかったスクリプトの場合、フルパスになります。 コマンドから相対パスでスクリプトを指定した場合、その相対パスになります。

    if [ "${_Dbg_DEBUGGER_LEVEL}" != ""  -a  -e "/mnt/c/Windows" ]; then            
        ScriptPath="${USERPROFILE}/Desktop/____/____"
    else
        ScriptPath="$0"
    fi

## mac の場合

mac で Bash Debug 拡張機能を使えるようにセットアップする手順は簡単です。 Visual Studio Code を mac にインストールして Bash Debug 拡張機能を（必要なら Bash IDE 拡張機能も）インストールするだけです。

[→ W.2. Visual Studio Code をインストールします](#w2-visual-studio-code-をインストールします)

ちなみに、mac のシェルはコマンド入力に関しては zsh ですが、スクリプト実行に関しては bash が使われることが多いので、シェルの違いが問題になることはほとんどありません。


## Linux (SSH 接続) の場合

Windows で VirtualBox や Vagrant などを使ってインストールした Linux の VM (Virtual Machine) と SSH 接続した Visual Studio Code でシェルスクリプトをデバッグすることができます。

Linux にセットアップする手順は、Ubuntu on WSL2 にセットアップする手順とほぼ同じです。Visual Studio Code を Windows にインストールして、Linux と SSH 接続した状態で、Bash Debug などの拡張機能をインストールするだけです。 

なお、Visual Studio Code を Linux に SSH 接続するときは、Remote Debug 拡張機能の SSH 接続を使う必要があるので注意してください。 SSH FS などの拡張機能で SSH にログインできたとしてもデバッガーには接続できません。 また、Linux から Windows のフォルダーを参照するには、別途共有フォルダーを設定する必要があります。

- [→ W.2. Visual Studio Code をインストールします](#w2-visual-studio-code-をインストールします)
- [→ U.4.d. Visual Studio Code の拡張機能をインストールします](#u4d-visual-studio-code-の拡張機能をインストールします)


## 参考

- Bash Debug
https://github.com/rogalmic/vscode-bash-debug

- bashdb
https://bashdb.sourceforge.net/bashdb.html

- Bash IDE
https://marketplace.visualstudio.com/items?itemName=mads-hartmann.bash-ide-vscode

- Linux 用 Windows サブシステムで Visual Studio Code の使用を開始する
https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-vscode

- Windows10 2004でWSL2を設定してVSCodeからDockerに接続する
https://qiita.com/cold-wisteria/items/9db8a5560bdec99f428a

- How to run "sudo apt-get update" through proxy in commandline? （プロキシ関連）
https://askubuntu.com/questions/7470/how-to-run-sudo-apt-get-update-through-proxy-in-commandline

- Network Connections in Visual Studio Code （プロキシ関連）
https://code.visualstudio.com/docs/setup/network

- WSL を使用して Windows に Linux をインストールする
https://learn.microsoft.com/ja-jp/windows/wsl/install

- WSL 開発環境を設定する
https://learn.microsoft.com/ja-jp/windows/wsl/setup/environment#set-up-your-linux-username-and-password