シェルスクリプトでカーソルメニューつくる

shellscript


この記事は、 PMOB Advent Calendar 2017 の記事です。

経緯

dotfilesのインストールスクリプトって書いてますか。 単純なもので、シンボリックリンクを貼りまくるスクリプトでも用意しておくと便利ですよ。

私のdotfilesのインストールスクリプトは

  1. dotfilesのリポジトリをclone
  2. dotfilesのシンボリックリンク張る
  3. 開発ツールをインストール
  4. vimやらzshやら、ツールのプラグインをインストール

をいっぺんにやるようになっているのですが、 先日OS爆破してdotfilesを新しい環境にインストールした際、 とりあえずプラグインは無視してすぐに使える設定ファイル(.gitignore_globalみたいな)だけを使いたいなーという時に若干不便だということに気づきました。 リポジトリをクローンするのも、今は丸ごと落としてますが、shallowでいい時もありました。

なので、インストール時にどこまで・どうインストールするかのオプションを選択させたい。 しかもせっかくだしvue-initみたいなCLIのカーソルメニューを実装してみたい。

カーソルメニューって何

まず、私が想像しているものが「カーソルメニュー」という名前で合っているのかいまいちわかりません。

  First Option.
> Second Option.
  Third Option.

こういうやつです。正式名称あるのかしら。

シェルスクリプトで実装してみる

dialogコマンド(LinuxCommand.org: Dialog) が使えたらこれで良さそうですが、とりあえずmacOSと私が使うディストリには標準でインストールされていないので、 dotfilesの起動時のプログラムとしては使いづらいです。 なので、カーソルメニューをシェルスクリプトでANSIエスケープシーケンスを使って実装してみました。 ANSIエスケープシーケンスとか触るの高校以来だぜ。

ANSIエスケープシーケンス

ANSIエスケープシーケンスは、ターミナルのカーソル位置操作、 ターミナルに出力するテキストの色情報などを制御をするための文字列です。 エスケープシーケンスは、Escから始まる文字列になります

code 制御
Esc[<r>;<c>H カーソルをr行c列に置く
Esc[<n>A カーソルをn行上に進める
Esc[<n>B カーソルをn行下に進める
Esc[<n>C カーソルをn行右に進める
Esc[<n>D カーソルをn行左に進める
Esc[s カーソルの位置を記憶する
Esc[u Esc[sで記憶した位置にカーソルを戻す
Esc[2J スクリーンをクリアする
Esc[K カーソル位置から行末までをクリアする
Esc[<value>;...;<value>m 以下の表にしたがって、Graphic Modeを設定する

Graphic Mode

Esc[<value>mによってターミナルに出力されるテキストの装飾を設定することができます。

value 意味
0 全てのattributeを無効化
1 太字
4 アンダーライン
7 カラー反転
30 - 37 文字色を変更
40 - 47 背景色を変更

こんなことができます。 たとえば、

# クリアスクリーン
printf "\e[2J\e[1;1H"
# 黒文字 / 下線付き / 黄色背景でHello world
printf "\e[4;30;43mHello world\e[m"

詳しくはこれが見やすかった。 試してみてね。

実際のやつ

で、これ使って作った奴がこんな感じです。

以下スクリプトです。説明はコメントアウトで

パイプで入力を受けて選択文字列or番号を出力するっていうのが実用的だと思うので、 今度暇な時そういう感じに改良します。

注意点

スクリプト内でキー入力を読むのにreadコマンドを使用していますが、 これは一応bash用のシンタックスで、zshだとn文字読むというオプションを指定するのに -kオプションを使います。ですのでzsh専用にするなら、read部分のオプションは -sk としてください。 bash/zsh両立するなら、read部分を

if [ `echo $0` = "-zsh" ]; then read -sk1 answer; else read -sn1 answer; fi

としてください。実行シェルがzshならkオプション、それ以外ならnオプションって感じです。

と、エスケープシーケンスで書いてみちゃったけどこんなんでいいのかしら。 もっとかっこいいやり方あるのかしら。かっこいいシェルスクリプトの書き方気になります。

あと返り値に選択したオプションを返すために、 返り値以外の出力先をstderrにしてるんだけどこれもいいのかしら。 モヤっとしている。

あとdotfiles系の記事調べると2015年とかのばっかでて来て不安になるんですけど。 dotfilesってもう古いの?みんな使ってます?不安になるわー。おしまい