PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

ユーザーフレンドリーなシェル「fish」に乗り換えてみた

こんにちは、プラットフォーム技術部第一グループのワンです。

コマンドラインの世界って、ちょっと取っ付きにくいって思っていませんか?黒い画面にずらっと並ぶ白い文字… なんだか難しそうに見えますよね。でも、fishは、そんなコマンドラインに対するイメージを変えてくれるかもしれません。

fishは、「friendly interactive shell」の略です。つまり、他のシェルと比較すると、使いやすくて、対話的に操作できるのが特徴なんです。 例えば、コマンドを入力していくと、候補を予測して表示してくれたり、過去の履歴を参考に見せてくれたりします。これなら、タイピングが減るし、コマンドを覚えるのも楽になりますよね。さらに、プラグインシステムを利用することで、さまざまな拡張機能を導入できます。

今年から私もそんなユーザーフレンドリーなシェルfishに乗り換えてみましたので、今回の記事ではfishについて紹介したいと思います。本記事の内容はMacでの操作を想定しています。

fish公式ドキュメント fishshell.com

便利な機能で快適な操作を実現

fishは、コマンドライン初心者から上級者まで、幅広いユーザーに使いやすい機能が満載です。

オートコンプリート

コマンドやファイル名を入力すると、候補を自動的に表示してくれるので、タイピングが楽になります。

auto complete

コマンド履歴

Ctrl+R キーを押すと、過去の入力履歴から候補を絞り込むこともできます。よく使うコマンドをいちいち入力する必要はありません。

command history

エイリアス

長いコマンドや複雑なオプションを、短いエイリアスに置き換えることができます。

alias 1

例えば、git loggl といったエイリアスに設定すれば、二文字で実行できます。 そして、alias コマンドには便利な -s フラグ (オプション) があります。-s フラグ (オプション) は、エイリアスを定義する際に一緒に使うと、そのエイリアスを自動的に保存してくれます。保存先は、fishの設定ディレクトリにある functions フォルダ内です。

alias 2

これで、すべてのセッションで gl コマンドを使用できるようになります。もし、エイリアスが保存されている場所を見たい場合は、以下のディレクトリを開いてください。

~/.config/fish/functions

このディレクトリには、先ほど gl という名前で保存されたエイリアス定義ファイル (gl.fish) が存在しているはずです。ファイルの中身は、次のような形式になっています。

gl.fish

この -s フラグ (オプション) を活用することで、いちいち設定ファイルを編集しなくても、簡単にエイリアスを保存し、永続的に使用することができます*1

テーマ

fishは、見た目も結構カスタマイズできます。豊富なテーマから好きなものを選ぶと、自分だけのオリジナルなコマンドライン環境を作ることができます。

fishは24ビットTrueColorをサポートしているので、ターミナルが TrueColor に対応している場合は、1677万色を表示することができます。 一方、ターミナルが TrueColor に対応していない場合には、256 色しか表示できませんが、できるだけ近い色を表示するように工夫されていますので、色に対してこだわりがある方も自分なりのテーマが設定できるでしょう。

fishのインストール

まずは、fishをインストールしましょう。主なインストール方法は次の通りです。

macOSの場合: Homebrew パッケージマネージャーが利用できます。

brew install fish

Linuxの場合: 主要なディストリビューションのパッケージリポジトリに含まれています。例えば、Ubuntu/Debian 系なら:

sudo apt-get install fish

その他の環境の場合: 公式サイトからパッケージをダウンロードすることも可能です。

デフォルトシェルを変更

インストールが完了したら、chsh コマンドを使ってデフォルトシェルをfishに変更しましょう。

Bash

chsh -s /usr/local/bin/fish 

(パスはインストール環境によって異なる場合があります)

基本的な設定

fishの設定は ~/.config/fish/config.fish ファイルで行います。このファイルに、エイリアスやテーマ設定、使用するプラグインなどに関する記述を追加することができます。

例えば、自分はこのような設定をしています:

大した理由ではないですが、業務ではsidekiqを使っていて、毎回exitの際に、sidekiqに"Bye!"って挨拶されていることが好きですので、 fishにも退出の挨拶を設定してみました :)

設定を変更したら、fishを再起動して反映させましょう。

Terminalで設定のほか、webのUIで直感的に設定することもできますよ。 fish_config を実行すると、web画面に遷移します。

テーマも容易的にカスタマイズできる以外に、関数や変数の一覧と履歴の操作も便利です。

豊富なプラグインで機能を拡張

fishには、プラグインを簡単に管理できる「fisher」というツールが存在します。

curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher

github.com

例えば、 fisher install jethrokuan/fzfと入力すると、強力な検索支援プラグイン fzf を導入できます。 listコマンドでインストール済みのプラグインを確認します。

$ fisher list
jorgebucaran/fisher
ilancosman/tide@v5
jorgebucaran/nvm.fish
/home/jb/path/to/plugin

次はプラグインを紹介します。

fzf: fishにもたらされる高速ファジー検索

コマンドライン環境は強力ですが、ファイルやディレクトリ、コマンド履歴の中から目的のものを探すのは時として面倒ですよね。そんなときに、劇的に操作体験を向上してくれるfishのプラグインがあります。それが「fzf」です。

fzfは "fuzzy finder" の略称で、その名の通りファジー検索を提供してくれます。ファジー検索とは、入力した文字列に部分的に合致する項目を探し出してくれる機能です。例えば、「fish configuration」というファイルがあった場合、「f con」といった部分文字列でマッチさせることができます。これが、通常の検索よりもはるかに素早く、直感的な体験をもたらしてくれるのです。

ファイルやディレクトリの検索: 統合された検索機能を利用することで、ファイル名やディレクトリ名を素早く見つけ、開いたり編集したりできます。

コマンド履歴検索: 過去のコマンド履歴を効率的に絞り込み、再実行できます。

その他の統合機能: fzf は高度な操作にも対応しており、例えば Git のコミット一覧から特定のコミットを探したりといったことも可能です。 さらに、fzf はfishの強力なキーバインド機能と組み合わせることで、真価を発揮します。例えば、Ctrl + R を押すと、コマンド履歴のファジー検索が開始され、目的のコマンドに素早くアクセスできます。

fzf を導入することで、コマンドライン上での検索にかかる時間やストレスが大幅に軽減されます。ファイルの場所やコマンド名がすぐに思い出せずとも、おおよそのキーワードさえ入力できれば、目的の対象にたどり着けるのです。

fzf 公式サイト:

github.com

z: fishでのディレクトリ移動を超効率化

ディレクトリ間の移動は頻繁に行う基本操作ですよね。頻繁であるがゆえに、その操作が少しでも速く、簡単になれば、作業全体の効率化につながります。それを実現してくれるのが「z」プラグインです。

「z」は、あなたのディレクトリ移動の行動を学習し、最適な移動先を提案してくれるプラグインです。移動頻度や直近の使用頻度などを元にして、少ない文字数で目的のディレクトリにジャンプできるようになるのです。

例えば、頻繁にアクセスするプロジェクトディレクトリが /workspace/awesome-project だったとしましょう。通常なら cd /workspace/awesome-project と入力するところを、「z」プラグインがあるとしたら z aw といった短縮入力だけで済むかもしれません。

z 公式リポジトリ:

GitHub - jethrokuan/z: Pure-fish z directory jumping

fish-nvm: fishでの Node.js 開発を快適に

Web アプリケーションやサーバーサイド開発に欠かせないランタイム、Node.js。プロジェクトごとに異なる Node.js のバージョン管理が必要になることも多いでしょう。そんなときに役立つfishのプラグインが「fish-nvm」です。

通常、Node.js のバージョン管理には「nvm」というツールが使われます。しかし、nvm は POSIX 準拠のシェル用に設計されているため、fishで直接利用することはできません。そこで fish-nvm が登場します。

fish-nvm は、fish環境に nvm の機能を提供してくれるプラグインです。fishの直感的な文法や機能と nvm のバージョン管理力を組み合わせることで、快適な Node.js 開発環境構築をサポートします。 fish-nvm のコマンドは nvm の使い方と非常に似ています。例えば...

  • Node.js のインストール: nvm install <バージョン>
  • 使用する Node.js バージョンの切り替え: nvm use <バージョン>
  • インストール済み Node.js バージョンの確認: nvm ls

に加えて、プロジェクトディレクトリ内にある .nvmrc ファイルを読み込んで、自動的に必要なバージョンに切り替えるといったことも可能です。

fish-nvm 公式リポジトリ:

github.com

done: 長時間実行タスク? 放っておいても大丈夫

コマンドラインで長時間かかる処理を実行したとき、結果がいつ出るかわからず、他の作業に移れないことってありますよね。そんな、ちょっとモヤモヤする状況を解消してくれるのがfishのプラグイン「done」です。

done は、長時間実行されるコマンドが完了したときに、自動で通知してくれるプラグインです。例えば、バックアップ処理や動画ファイルの変換、大規模なデータ解析などをバックグラウンドで実行しながら、安心して別の作業に集中することができます。

使い方は驚くほど簡単です。普段通り実行したいコマンドを打つだけで、タスク終了時にfishが通知を出してくれます。

例えば、sleep 6 と入力した場合は、6秒後に通知が届きます。通知にはコマンドの実行状態(成功・失敗)も表示されます。

done プラグインは、fishユーザーに限らず、コマンドラインを多用して複数のタスクを並行して進める方に特に役立ちます。

done 公式リポジトリ:

github.com

fishを彩る、Base16 の世界へようこそ

長時間の作業でも目が疲れにくく、スタイリッシュなターミナル環境は、気持ちよく作業する上で意外と大事ですよね。fishには、そんなターミナルの見た目を手軽にカスタマイズできるプラグイン「Base16 Fish Shell」が存在します。

Base16は、さまざまなターミナルやテキストエディタで利用できる配色テーマの規格です。明暗やコントラスト、色合いの異なる多様なテーマが揃っています。Base16 Fish Shell は、そのBase16のカラーテーマをfishに適用してくれるプラグインです。洗練されたカラーパレットが数多く用意されており、お好みのテーマを簡単に入れ替えられます。

インストール後、base16 コマンドでテーマの切り替えができます。例えば、base16 default と入力すると「default」というテーマが適用されます。

Base16 Fish Shell公式リポジトリ: github.com

bash/zsh との違い

ただ、bashとzshユーザーが注意すべき点として、fishはPOSIX非互換となっています。

POSIX とは、UNIX 系のオペレーティングシステムにおける標準化されたインターフェイスの仕様です。多くのシェル、例えば bash や zsh は、この POSIX 規格に準拠しています。このため、POSIX 互換のシェルスクリプトは、異なる UNIX 系の環境でも問題なく動作することが期待できます。

fishは独自の構文やコマンド体系を持っており、POSIX に完全に準拠しているわけではありません。 そのため、bash や zsh で書かれたシェルスクリプトが、fishでは動作しない可能性があります。 構文の違いによって、スクリプトを修正する必要があるかもしれません。

POSIX非互換の例としては、次のようなものがあります。

括弧によるコマンド実行

fishではバッククォート ` の代わりに括弧(parentheses)() を使用することです。バッククォートはfishでサポートされていません。

# bashの例
gzcat `ls | grep ".gz"` | awk 'BEGIN{FS=" "} $9 ~ /50/ {print $0}'

# fishの例
gzcat (ls | grep ".gz") | awk 'BEGIN{FS=" "} $9 ~ /50/ {print $0}'

変数の設定と削除

POSIX 標準シェル:
変数を設定するには、VAR=VALUE という形式で直接代入します。 変数を削除するには、unset VAR コマンドを使用します。

fish:
変数を設定するには、set コマンドを使用します。 set コマンドには、変数の スコープ (有効範囲) や エクスポート (外部環境への公開) を指定するオプションが用意されています。

  • -g: グローバル変数 (すべての関数で利用可能) として設定し、エクスポートします (POSIX の export コマンド相当)
  • -l: ローカル変数 (設定した関数内のみで利用可能) として設定します (POSIX の local コマンド相当)

代わりに、VAR=VALUE 形式でコマンド実行時に一時的に環境変数をオーバーライドする ことができます。

GIT_DIR=somerepo git log

この場合、git log コマンドの実行中のみ、GIT_DIR 環境変数が somerepo に置き換えられます。

そして、変数を削除するには、set -e VAR という形式で set コマンドを使用します。

if set -q my_var
    set -e my_var
    echo "Variable unset."
else
    echo "Variable does not exist."
end

このスクリプトは、変数 my_var が存在するかどうかを確認します。もし存在する場合は、その変数をアンセット(unset)します。存在しない場合は、変数が存在しないことを示すメッセージを表示します。

変数の展開とワードスプリット

POSIX 標準シェルでは、変数展開時にワードスプリット (空白文字で区切られたトークン分割) が行われます。そのため、変数内に空白文字が含まれている場合、展開時に分割されてしまう可能性があります。これを防ぐには、変数展開を二重引用符で囲む必要があります。

Bash

# 変数内に空白文字を含む
foo="bar baz"

# 展開時に分割されてしまう (POSIX 標準シェル)
printf "%s\n" $foo

# 二重引用符で囲むことで分割を抑制
printf "%s\n" "$foo"

fishでは、ワードスプリットが基本的に行われません。 よって、変数内に空白文字が含まれていても、展開時に分割されません。そのため、ほとんどの場合、変数展開を二重引用符で囲む必要はありません。

つまり、fishの構文に慣れる必要があります。 他のシェルから fishへ移行する際、fish独自の書き方やコマンドを覚える必要があります。 bash/zshユーザーが下記公式ドキュメントをご参考してください。 fishshell.com

まとめ

fishの世界は奥深く、拡張性も高いため、今回紹介した情報以外にも、さまざまな機能やカスタマイズが可能です。自分の好みに合わせてfishをカスタマイズし、快適なコマンドライン環境を構築することで、作業効率やモチベーションアップにもつながるでしょう。ぜひ fishを使いこなし、自分だけの“とっておき”のターミナル環境を築き上げてください。

fishへようこそ!

*1:bash や zsh にも alias コマンドはありますが、シェルを開くたびに自動的にエイリアスを適用するためには、自分で .bashrc や .zshrc などの設定ファイルを編集しなければなりません。