fish shellが結構良かった話

> Fishermanは名前を変更しFisherとなったため、それにともない内容を修正しました。
> Yaourtはすでに開発が終了しているため、Yayを使うよう修正しました。
> Fisherのインストール方法やコマンド体系の情報が古くなっています。プラグイン紹介以下もすべて修正する必要があるため、修正していません。[FisherのREADME](https://github.com/jorgebucaran/fisher)を参考にしてください。

「fishいいよ」みたいな話は何度かちらっと聞いていたんですけど、ちょっと調べてみたところ**POSIX非互換**ということで、あまり興味を持てずにいました。

しかし最近Twitterで勧められて試しに使ってみたところ、すごく良かったので導入方法とかおすすめプラグインとか紹介してみたいと思います。

僕も入門したところなので、あんまり詳しくはないですけど。

似たような内容ですが、目的を絞った記事も書いたので興味があれば読んでみてください。

~~こっちの方がわかりやすいかもです。~~

~~[ローカルリポジトリの管理方法](https://qiita.com/hennin/items/77a5afe0078256ae55f3)~~

上の記事は内容が古いままです。

> [awesome-fish](https://github.com/jorgebucaran/awesome-fish)に情報がまとめられているので、見てみるといいと思います。

# fishとは

Friendly interactive shellの略称だそうです。

**ユーザーフレンドリさと対話的利用、わかりやすさ**を重要視しているようですね。

今までのシェルと同じように**直感的に使えて、かつ古い悪習(`case`の終了が`esac`とか)を捨て去っている**という感じです。

なので**POSIX非互換**となっています。

**POSIX**というのは、**シェルスクリプトの標準仕様**のようなものです。

**sh**は**POSIX互換のシェル**ですね。

Bourne Shellを単にshと呼んだりするそうですが、UnixやLinuxにある`/bin/sh`は`sh`そのものであったり、`bash --posix`へのリンクであったりするそうです。

`bash --posix`はBashの機能で、POSIX互換の機能のみ使用してスクリプトを動かすモードです。

自分の環境のshが本当にshなのか別のシェルなのか気になる方は`ls -l $(which sh)`を実行すると見ることができるらしいです。
`ls`の`-l`オプションはリンクが張られているかを表示するために付けてます。

閑話休題。

BashとかZshとかは、POSIX互換ではなく**POSIX準拠**となっています。

というのも、POSIXの仕様で決められたものは全て動かせますけど、それ以外の拡張機能もあるのです。

互換ならどちらで書いてもどちらでも動きますけど、準拠は違います。

**shで書いたものはBashで動きますけど、Bashで書いたものはshで動かないかも**しれません。

Bashの拡張機能を使っているとshでは動きませんからね。

ちなみに非互換は完全に別物という意味です。

fishはこのPOSIX非互換が問題になるかもと思っていたんですけど、
コピペしてきたスクリプトとか動かすときだけshなりBashなり使えばいいですし、[プラグイン紹介](#プラグイン紹介)に書いてますけどBash互換のスクリプトを動かせるようなプラグインもあります。

そこまで困ることもないかもしれませんね。

以上、半分以上POSIXの話になっていた気もしますけど、fishについてでした。

# fishのここが良かった

- **デフォルトで色々いい感じ**なので、**ほぼ設定いらず**
- **シンタックスハイライトの機能がすごい**
  - **入力中のコマンドにも**シンタックスハイライトが効く
  - コマンドやオプションが合っているかがひと目でわかる
- コマンド履歴からの補完
  - **コマンド入力中にインタラクティブに補完**が見える

![Screenshot at 2018-04-26 22-56-57.png](https://qiita-image-store.s3.amazonaws.com/0/225715/b2fef6a7-926b-c307-43e3-6621c1e7516d.png)

スクリーンショットはちょっと見た目をいじったあとのものです。

あと[公式サイト](https://fishshell.com/)にもアピールポイントが書いてありますね。

- **履歴から自動で補完候補を表示**
- カラフルでわかりやすい
- **シンタックスがシンプル**でわかりやすい
- ブラウザで**グラフィカルに設定をいじれる**
- わざわざ補完のためのコードを書かなくても**manページから補完できる**
- 他のシェルでも使えるTabでの補完やシンタックスハイライトを強化しているだけなので、**特別に新しいことを覚える必要がない**

かなり雑な意訳ですがこんな感じでしょうか。

# 設定

基本的には`~/.config/fish/config.fish`に書いていきます。

でも設定ファイルを直接書くのって不安ですよね。

そこで、fishには**ブラウザでグラフィカルに設定をいじる**方法が用意されています。

fishで`fish_config`を実行してみてください。

![Screenshot at 2018-04-27 01-53-59.png](https://qiita-image-store.s3.amazonaws.com/0/225715/85104306-afc9-ac37-1894-6c8b32097845.png)

上のスクリーンショットのようにURLが表示されているので、アクセスしてみましょう。

![Screenshot at 2018-04-27 01-55-29.png](https://qiita-image-store.s3.amazonaws.com/0/225715/9776902a-e9bb-a984-a3be-0a864e0f68ae.png)

これなら簡単に設定をいじれそうですね。

あとブラウザで変更した設定は`~/.config/fish/config.fish`ではなく`~/.config/fish/fishd.<hostname>`に保存されています。

`<hostname>`はLinuxに設定されたホストネームですね。
コンピュータの名前とも呼ばれます。

たぶんLinuxのインストールのときに、コンピュータの名前を設定してユーザを作ってユーザ名を設定して、みたいなことをしていますよね。きっと。

この`~/.config/fish/fishd.<hostname>`ですけど、自動生成されるものなので中身は書き換えないように注意してください。


# Fisher

[Fisher](https://github.com/jorgebucaran/fisher)はfishのプラグインの管理ツールです。

似たようなツールとして[Oh My Fish](https://github.com/oh-my-fish/oh-my-fish)がありますけど、Fisherの方が後発なのと、FisherはOh My Fishのプラグインもインストールできるためこちらを使いたいと思います。

## インストール

インストール方法は[FisherのGithubのページ](https://github.com/jorgebucaran/fisher)にありますけど、ワンライナーです。

まず、それぞれのパッケージマネージャとかを使ってfishを入れてください。

```sh:ArchLinuxの例
yay -S fish
```

そして`fish`を起動後、以下のインストール用のワンライナーを実行してください。

```sh
curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish
```

#### おまけ

Fisherはfishスクリプトで書かれています。

fishには関数(コマンド)が呼び出されたとき、その関数と同名のファイルを`~/.config/fish/functions/`以下から探し、その中の同名の関数を実行するという仕様があります。

`fisher`コマンドはこの仕様を利用して実装されているんですね。

つまり、上記のインストールスクリプトでは単に`https://git.io/fisher`というfishスクリプトを`~/.config/fish/functions/fisher.fish`に持ってきているだけです。

なのでブラウザで`https://git.io/fisher`にアクセスするとFisherのコードを見ることができますね。

### fishをログインシェルにする

ログインシェル、またはデフォルトシェルとも呼ばれますね。

いきなりですけど**Arch Linuxではfishをデフォルトシェルにしないことが推奨**されています。
詳しくは[ArchWikiのfish](https://wiki.archlinux.jp/index.php/Fish)読んでください。

そんな事情もあり、他のLinuxディストリビューションでもfishをログインシェルにするかどうかは各自の判断に任せたいと思います。
ログインシェルにしたい人は以下のスクリプトを実行してください。

```sh:sh
chsh -s $(which fish)
```

```sh:fish
chsh -s (which fish)
```

ちなみにですけど、`chsh`は`change shell`で`$()`はコマンドの実行結果を取得するものです。
fishでは`()`ですね。

## Fisherの使い方

`fisher -h`(`fisher --help`)でサブコマンドの一覧を見ることができます。

![Screenshot_2019-01-19_01-18-49.png](https://qiita-image-store.s3.amazonaws.com/0/225715/522066a3-83f8-78d0-70e4-bf083bea4d8c.png)

ちなみにですけど、**`fish`起動してないと`fisher`コマンドは使えません**。
[インストール](#インストール)の[おまけ](#おまけ)で書いた通りの理由ですね。

基本的には`fisher add user/foo`でGitHubで公開されているプラグインをインストールすることができます。

削除するときは`fisher rm foo`です。

インストール済みのプラグインの一覧は`fisher ls`で見られます。

詳しいことは[プラグイン紹介](#プラグイン紹介)で書きますけど、僕が入れてるのはこんな感じですね。

![Screenshot_2019-01-19_01-24-37.png](https://qiita-image-store.s3.amazonaws.com/0/225715/15d4a545-bf2f-0f19-d4a7-96359e613c7c.png)

# プラグイン紹介

> [awesome-fish](https://github.com/jorgebucaran/awesome-fish)に色々あるので、一度ながめてみてください。
> そんなに数は多くないですし。

個人的なおすすめプラグインです。

まだfishを使い始めたところなので、それくらいの意識で読んでいただけるとちょうど良いかと思います。

## [oh-my-fish/theme-bobthefish](https://github.com/oh-my-fish/theme-bobthefish)

```sh
fisher add oh-my-fish/theme-bobthefish
```

Vimに[Powerline](https://github.com/powerline/powerline)というプラグインがあるんですけど、それのfish版です。

**Gitのブランチとかステータスをわかりやすく表示してくれる**ツールですね。

[Powerline Fonts](https://github.com/powerline/fonts)を使っていますので、文字化けする人はインストールしてください。

```sh:ArchLinuxの例
yay -S powerline-fonts
```

また上記のリンクにもインストール方法が書かれています。

それでも文字化けするという人は、[Cica](https://github.com/miiton/Cica)というフォントを入れてみて、それぞれのターミナルで設定してみてください。

```sh:ArchLinuxの例
yay -S ttf-cica
```

Cicaは**様々なアイコンフォントがデフォルトで使える**プログラミング用フォントです。
もちろん日本語にも対応しています。

元はRictyというフォントで、そこにNerd FontsやNoto Emojiなどを合成したものになりますね。

Noto Emojiはそのまま絵文字、Nerd FontsはPowerlineを含む様々なアイコンフォントをまとめたフォントです。

ちなみにですけど、グリフ(文字)をまとめたものをフォントと呼んで、さらにフォント同士を合成することを**パッチを当てる**、と言ったりします。

RictyにNerd Fontsのパッチを当てる、みたいな感じです。

あとこれは蛇足なので聞き流してほしいんですけど、グリフってあんまり聞き慣れない言葉ですよね。
でもファンタジーが好きな人や中学生くらいで病にかかった人なら神聖文字(ヒエログリフ)とか聞いたことあるかもしれません。

閑話休題。

bobthefishの良さを知ってもらうため、少しデモを行いたいと思います。

まずGitのリポジトリのディレクトリに行きます。

![Screenshot at 2018-04-27 00-05-20.png](https://qiita-image-store.s3.amazonaws.com/0/225715/f54bf1d9-9285-e33a-f2ff-02bcd35c06f6.png)

カレントディレクトリの横に、**gitでよく見かけるアイコン**が見えますね。
ブランチのアイコンです。

次に、**ファイルを変更**してみます。
ここではREADME.mdを削除してみます。

![Screenshot at 2018-04-27 00-12-35.png](https://qiita-image-store.s3.amazonaws.com/0/225715/97036048-e207-34f2-aa33-c7f0dc93e461.png)

表示が**赤色**に変わりましたね。
変更されたファイルがあるよ、という警告みたいです。

では、先ほどの変更を`git add`で**ステージング**してみます。

![Screenshot at 2018-04-27 00-15-28.png](https://qiita-image-store.s3.amazonaws.com/0/225715/ddc9acb2-bcdf-43c9-be8e-e61381e6126b.png)

今度は**黄色**になりました。
コミットしていないステージングがあるよ、というのがひと目でわかりますね。

次は**コミット**を行ってみます。

![Screenshot at 2018-04-27 00-17-13.png](https://qiita-image-store.s3.amazonaws.com/0/225715/1159e624-a1f9-9b77-4929-507d763e11d5.png)

コミットを行うと、緑色の表示に戻りましたけど、何やら**`+`記号**が付いていますね。

これは**`Your branch is ahead of 'origin/master' by 1 commit.`**をグラフィカルに示しているようです。

リモートブランチから進んだコミットがあるよ、という意味ですね。

面倒なのでpushはしませんけど、こんな感じです。

便利ですね。

あとこれは余談なんですけど、`oh-my-fish/theme-bobthefish`は実はOh My Fishのプラグインです。

名前を見て「あれ？」と思った方もいるかと思いますけど、[https://github.com/oh-my-fish](https://github.com/oh-my-fish/)がOh My Fishのプラグイン用のGitHubアカウントになっているんですね。

[Fisher](#fisher)のところでも書いたように、FisherではこれらOh My Fishのプラグインもインストールすることができます。

以上、`bobthefish`プラグインの説明のつもりだったんですけど、余談ばっかりだった気がしますね。

ところで`bobthefish`ってなんて読むんでしょう。

Bob the fish？


## [jethrokuan/z](https://github.com/jethrokuan/z)

```sh
fisher add jethrokuan/z
```

移動系のプラグインです。

簡単に言うと、**すべてのディレクトリへ直接移動できる**プラグインですね。

以下は`z fish`で`~/.config/fish`に移動する例です。

![Screenshot at 2018-04-26 23-56-46.png](https://qiita-image-store.s3.amazonaws.com/0/225715/380ac6e9-0110-3889-8711-d5eb614476d1.png)

`z fish`では**カレントディレクトリに関係のない相対パス**を指定しているのに、ちゃんと`~/config/fish`に移動できていますね。

原理としては、コマンドの履歴のパスから**指定された相対パスに部分一致するパス**を検索しています。

なので**行ったことあるディレクトリにしか行けない**です。

もちろん**Tabでの補完**もできます。

ちなみにですけど、部分一致なので`z foo`で`/hoge/foo/bar`に移動したりもします。


## [FabioAntunes/fish-nvm](https://github.com/FabioAntunes/fish-nvm)

NVM使ってない人はいらないですね。

これは何のためにあるのかといいますと、NVMってBashに依存している部分があるんですよね。

なので、そのままではfishでは動きません。

それに対応するためのプラグインです。

ちなみに内部では[edc/bass](https://github.com/edc/bass)という、**Bash互換のスクリプトをfishで実行するためのプラグイン**を利用しています。

## [jethrokuan/fzf](https://github.com/jethrokuan/fzf)

[fzf](https://github.com/junegunn/fzf)というコマンドのラッパーです。
fish用の便利なキーバイドを提供してくれます。

そもそもfzf自体を使ったことがないという人が多そうですけど、使いましょう。

とても便利です。

fzf自体は、**入力された行データからインタラクティブに曖昧(fuzzy)検索を行ってくれるコマンド(fuzzy finder)**です。

ちなみにGo言語製のツールです。

似たようなツールに同じくGo言語製の[peco](https://github.com/peco/peco)がありますけど、~~こちらはfzfとは違い部分検索です。~~

最近はpecoでも曖昧検索ができるみたいです。

今回はfzfを使ってみたいと思います。

まずはfzfをそれぞれのパッケージマネージャなどで入れましょう。

```sh:ArchLinuxの例
yay -S fzf
```

次に、Fisherでfzfを入れます。

```sh
fisher add jethrokuan/fzf
```

そして、`~/.config/fish/config.fish`(fishの設定ファイル、[設定](#設定)を参照)がなければ作成し、以下の設定を書き込んでください。

```sh
set -U FZF_LEGACY_KEYBINDINGS 0
```

これはこのプラグインの**古いキーバインドを使わないための設定**です。
なぜキーバインドが新しくなったかというと、**fish 2.4.0でキーバイドがコンフリクトしたから**だそうです。

詳しい説明や使い方は[jethrokuan/fzf](https://github.com/jethrokuan/fzf)のREADMEに書いてあります。

`Ctrl+f`で**ファイルの曖昧検索**ができます。

![Screenshot at 2018-04-27 00-42-44.png](https://qiita-image-store.s3.amazonaws.com/0/225715/68b60c52-fac4-7b15-2b56-a2d45d5ef6af.png)

これは今回の記事で使うのに撮ったスクリーンショットですね。

`Ctrl+r`で**コマンド履歴の曖昧検索**です。

![Screenshot at 2018-04-27 00-44-50.png](https://qiita-image-store.s3.amazonaws.com/0/225715/36a2ccdd-44b1-69ce-2e4c-38210fa14cdc.png)

**`ci`と入力してるのに`config`とかひっかかって**ますね。

曖昧検索すごい。

最後に、`Alt+o`で**ディレクトリを検索して移動**ですね。
`Alt+Shift+o`で隠しファイルも検索できるようです。

あれ、これ[z](#jethrokuanz)の存在意義……？

![Screenshot at 2018-04-27 01-04-14.png](https://qiita-image-store.s3.amazonaws.com/0/225715/5163a94c-dba1-3c89-c4de-92911ee3d331.png)

`fsh`なんていう**タイポ検索でも安心**ですね。

あとこれは余談なんですけど、`fzf`、**fish関係ないところでも結構使いやすい**です。

例えばホームディレクトリで`ls -a`とかすると、**ものすごい量の隠しファイル**が表示されたりしますよね。

![Screenshot at 2018-04-27 01-35-18.png](https://qiita-image-store.s3.amazonaws.com/0/225715/2d1d3263-d1c8-d9ff-7adb-c2f098ffa950.png)

こういうとき、grepを使って`ls -al | grep bash`とする人が多いかもしれません。

![Screenshot at 2018-04-27 01-37-26.png](https://qiita-image-store.s3.amazonaws.com/0/225715/d8f07c32-3645-d07b-91df-11fddece0795.png)

そこでgrepの代わりに`fzf`を使うと……

![Screenshot at 2018-04-27 01-39-40.png](https://qiita-image-store.s3.amazonaws.com/0/225715/644e2d9b-c43c-10ba-8cf1-79c74ca3ba48.png)

**インタラクティブな上にファジーに検索**できますね。

## [decors/fish-ghq](https://github.com/decors/fish-ghq)

[ghq](https://github.com/motemen/ghq)というコマンドのラッパーです。
補完とキーバインドを提供してくれます。

「あれ？fishはデフォルトでmanから補完できるんじゃなかったっけ？」と思った人がいるかもしれませんけど、いくつか追加で補完を入れてくれてるみたいです。

これもそもそもghqを使ったことがないという人が多いかもしれないですね。

でもとても便利なのでぜひ使いましょう。

そしてこれもまたGo言語製のツールです。
Go言語ってコマンドラインツール作るのにいい言語なんでしょうかね。

ghqは**git cloneを一箇所で管理してくれる**ツールです。

まずはお使いのパッケージマネージャでghqを入れましょう。
Go言語の環境がある人は`go get`して`make`でもいいですけど。

```sh:ArchLinuxの例
yay -S ghq
```

そしてFisherでfish-ghqを入れます。

```sh
fisher add decors/fish-ghq
```

使い方は簡単です。

まず`ghq get url`でリポジトリを持ってくることができます。

ここでは`https://github.com/utatatata/sushi`をクローンしてみます。

![スクリーンショット_2019-06-03_01-00-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225715/99c3b9e0-b7f8-b812-4a02-dbebe27f10cd.png)

`git clone`そのまんまです。

`~/.ghq/github.com/utatatata/sushi`に入っていますね。

 どうやら`~/.ghq`以下に`<git host name>/<username>/<repository>`という形でクローンされているみたいですね。
`<git host name>`は`github.com`、`gitlab.com`、`bitbucket.org`などです。

ちなみにですけど`ghq root`でクローンされるディレクトリを確認できます。
デフォルトでは`~/.ghq`ですね。

これはghqの設定で変えることができます。
ghqの設定はGitの設定ファイルである`~/.gitconfig`に書き込むみたいですね。

```toml:.gitconfig
[ghq]
  root = ~/Repositories
  root = ~/.roswell/local-projects
```

`ghq.root`は複数指定することができて、`ghq get`したときリポジトリは一番上のパスの下にcloneされます。

そしてfishでghqを使う利点ですけど、とりあえず`Ctrl+g`を押してみてください。

![スクリーンショット_2019-06-03_01-22-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225715/a6237c1b-4b6a-aa2f-460f-25efe9da88d8.png)


見たことある表示ですね。

これは**fzfで`ghq get`してきたリポジトリを曖昧検索**しています。

これは`decor/fish-ghq`が、fzfやpecoが入っていると`Ctrl+g`で検索を行ってくれるようになっているからですね。

とどのつまり、これを使えば**`Ctrl+g`で目的のリポジトリに素早く移動できる**わけですね。

# まとめ

fish、どうでしたでしょうか。

ほとんどのプラグインで**設定ファイルを書いていません**でしたよね。

そして設定も**簡単にいじれます**。

またこの記事を読みながら手を動かしてくださっていた人ならもうわかっていただけたと思いますけど、**補完とサジェストとシンタックスハイライト、とても強力**ですよね。

とにかく楽だ……

しばらくはfishを使っていきたいと思います。

# 参考文献

[Public Domain Lisp Logo Set](http://lisperati.com/logo.html)
[POSIX - Wikipedia](https://ja.wikipedia.org/wiki/POSIX)
[Unixシェル - Wikipedia](https://ja.wikipedia.org/wiki/Unix%E3%82%B7%E3%82%A7%E3%83%AB#Bourne_Shell)
[Friendly interactive shell - Wikipedia](https://ja.wikipedia.org/wiki/Friendly_interactive_shell)
[h・bash・zsh等, shellの違いでハマりやすい部分とか - 水底](https://amaya382.hatenablog.jp/entry/2017/04/17/011928)