【脱！GUI】開発に必要なリンクにターミナルからアクセスする方法

## 目的

開発中にWebページを参照するタイミングは複数回発生すると思います。
例えば、以下のページは常に必要になるのではないでしょうか？

- 要件定義書が格納されたGoogle Drive
- スケジュール管理のためのasana
- ドメイン知識がまとまったNotion
- GitHubレポジトリ
- AWS環境

これらのページにアクセスする際、Webブラウザのブックマークから選択するのではなく、
ターミナルからコマンドを叩いて直接アクセスすることで生産性が向上します。


### 実際の挙動

例えば今、Google DriveとNotionへのリンク集を作成し、そのどちらかにアクセスするとします。
`doc.sh`というスクリプトにプログラムを作成し、実行したときの挙動は以下のようになります。

```bash
$ ./doc.sh
1) Google Drive
2) Notion Documents
3) Quit
開きたいページの番号を選択してください: 1
URL: https://drive.google.com
```

ターミナル上のURLを`command + クリック`することでアクセスすることができます。

### こんなことで生産性が向上するの？

我々がブラウザからWebページにアクセス際に立ちはだかる障壁は、ページにアクセスする目的を見失わせます。
やっとページにアクセスした頃には「何のためにページを開いたんだっけ？」という状態になってしまいます。
具体的に、開発中にブラウザからWebページへアクセスする場合、以下の手順を踏む必要があります。

1. **エディタからブラウザへ移動する**
    障壁: 現在開かれているページに目を奪われて目的を見失う（Twitterならなおさら）
1. **新しいタブを開く**
    障壁: ついでにタブを整理したくなり、その間に目的を見失う
1. **ブックマークフォルダを開く**
    障壁: フォルダ階層が複雑である場合、迷路を解いているうちに目的を見失う
1. **アクセスしたいリンクを選択する**
    障壁: 複数の文字列やアイコンが目に入ると目的を見失う
1. **ページにアクセスする**
    障壁: この頃には何のためにページを開いたのか忘れている

一方で、ターミナルから直接アクセスする場合は手順がシンプルで障壁も少なく済みます。

1. **エディタからターミナルへ移動**（エディタ内のターミナルを使用している場合はこの作業は不要）
1. **コマンド実行**
1. **アクセスしたいページを選択**
1. **ページにアクセスする**

このようにターミナルから直接リンクへアクセスすることで、
単純に操作数を減らすだけではなくスイッチングコストを削減して脳のメモリにかかる負担を減らすことができます。
これによって生産性を向上することができます。

:::note
これはあまり大きな声で言える例ではないかもしれませんが、、
みなさんのほとんどがgit管理をコマンドでおこなっているかと思います（こんなニッチな記事に興味を持つくらいですから）。

git管理をコマンドでおこなっている方が、SouceTreeの操作画面を見ているともどかしい気持ちになりませんか？
「マウスでうろちょろ画面上を移動したり、ポチポチボタンを押すのダルいよ！！」と。
それのブラウジング版が本記事って訳です。
:::

## 実装

今回はプロジェクト内にシェルスクリプトを作成し、それを実行します。
スクリプト名は`doc.sh`のようなシンプルなものが良いでしょう。

### `xdg-open`コマンドを使える場合

> 「xdg-open」は指定したファイルをデフォルトアプリケーションで開くコマンドです。 デスクトップ環境でファイルのアイコンにダブルクリック操作をした場合と同じように、デフォルトアプリケーションを起動します。
引用元: [ITメディア](https://atmarkit.itmedia.co.jp/ait/articles/1906/06/news007.html)

```bash
#!/bin/bash

# リンクのリストを定義
declare -A links
links=(
  ["Google Drive"]="https://drive.google.com"
  ["Notion Documents"]="https://notion.so"
  # ここに他のリンクを追加
)

options=("${!links[@]}")

# ユーザーに選択させる
PS3='開きたいページを選択してください: '
select opt in "${options[@]}" "Quit"; do
  case $opt in
    "Quit")
      echo "終了します。"
      break
      ;;
    *)
      url="${links[$opt]}"
      if [[ -n $url ]]; then
        xdg-open "$url"
        break
      else
        echo "無効な選択肢です。"
      fi
      ;;
  esac
done
```


### `xdg-open`コマンドが使えない場合

`xdg-open`コマンドが使えない場合は、URLを出力させます。
`command + クリック`でページを開くことができます。

```bash
#!/bin/bash

# リンクのリストを定義
declare -A links
links=(
  ["Google Drive"]="https://drive.google.com"
  ["Notion Documents"]="https://notion.so"
  # ここに他のリンクを追加
)

options=("${!links[@]}")

# ユーザーに選択させる
PS3='開きたいページの番号を選択してください: '
select opt in "${options[@]}" "Quit"; do
  case $opt in
    "Quit")
      echo "終了します。"
      break
      ;;
    *)
      url="${links[$opt]}"
      if [[ -n $url ]]; then
        # 選択されたURLを表示
        echo "URL: $url"
        break
      else
        echo "無効な選択肢です。"
      fi
      ;;
  esac
done
```

### `declare: -A: invalid option`が発生した場合（Bashのバージョンが4.0未満）

このエラーメッセージは、使用しているシェルが連想配列をサポートしていないことを示しています。
連想配列は、Bashのバージョン4.0以降で使用することができます。
このエラーはお使いのBashのバージョンが古いか、または別のシェルを使用していることを示唆しています。

bashのバージョンアップをせずにこの問題を解決する場合は、以下のように配列を設定するようにします。

```bash
#!/bin/bash

# URLのリストを定義
urls=("https://drive.google.com" "https://notion.so")

# メニューの選択肢を作成
options=("Google Drive" "Notion Documents")

# ユーザーに選択させる
PS3='開きたいページを選択してください: '
select opt in "${options[@]}" "Quit"; do
  if [[ $REPLY -ge 1 && $REPLY -le ${#options[@]} ]]; then
    echo "URL: ${urls[$REPLY-1]}"
    break
  else
    if [[ $REPLY == $((${#options[@]} + 1)) ]]; then
      echo "終了します。"
      break
    else
      echo "無効な選択肢です。"
    fi
  fi
done
```


## おわりに

このアイデアは、エンジニア交流会の会話の中で生まれました。
人と会話するのって良いですね。