fishしたい(fish)

1$ brew install fish

Bash や Zsh のようなシェルの仲間です。 デフォルトでいい感じに表示してくれるので、パソコンを買い替えた場合に便利です。

注釈

このページの例は主に fish シェルでの操作を想定しています。 インストール手順(brew install fish)は bash/zsh で実行してください。

bash/zshとの共通点・相違点を知りたい

fishはPOSIXシェルではありません。 bash/zshはPOSIX互換の文法(sh系)を採用していますが、fishは独自の文法を採用しており、sh向けに書かれたスクリプトをそのまま実行することはできません。

共通点

  • リダイレクト(< / > / 2> / 2>&1)は同じ書き方です

  • 変数の展開($変数名)やコマンド置換((コマンド))の考え方は共通しています

相違点

項目

bash / zsh(POSIX系)

fish

変数の定義

export 変数名=値

set -gx 変数名 値

条件分岐(連結)

&& / ||

and / or(&& / ||もv3.0以降エイリアスとして使用可)

ワイルドカード

マッチしない場合は文字列がそのまま渡る

マッチしない場合は必ずエラーになる

ワイルドカードの再帰

**はshopt -s globstar等が必要(bash)

**は標準で再帰マッチ

関数定義

function 名前 { ... }

function 名前 ... end

細かい違いは各セクションで補足します。

ログインシェルを fish にしたい

1$ which fish
2# /usr/local/bin/fish
3# /opt/homebrew/bin/fish
4$ sudo vi /etc/shells
5$ chsh -s /opt/homebrew/bin/fish

上記のコマンドは bash/zsh で実行します。

fishをデフォルトシェルに設定する手順の内容は以下のとおりです。

  1. /etc/shells に fish のパスを追記する

  2. chsh -s コマンドでデフォルトシェルを変更する

fish のパスは OS やインストール方法で異なるため、which fish で確認しておきましょう。 /etc/shells の編集には管理者権限が必要です。 chsh -s を実行する際に管理者パスワードを確認されます。

fishを設定したい(fish_config)

$ fish_config

fish_configを実行すると、ブラウザが起動します。 色やプロンプトなど設定できます。

変更点を確認したい(fish_delta)

$ fish_delta

fishのデフォルトから変更を加えた箇所を確認できます。

プロンプトを微修正したい(fish_prompt.fish)

$ code ~/.config/fish/functions/fish_prompt.fish

上記のfish_configで選んだプロンプトを少しだけ修正したい場合は、fish_prompt.fishを直接編集してしまいましょう。

パスを設定したい(fish_add_path)

# Homebrew
fish_add_path /usr/local/bin

# pipx
fish_add_path $HOME/.local/bin

# Rust
fish_add_path $HOME/.cargo/bin

fish_add_pathを使ってパスを追加できます。

注釈

これまでは以下の方法set -xを使った方法でよかったのですが、v3.2から非推奨になりました。

$ set -x PATH $PATH $HOME/.cargo/bin

パスを確認したい(fish_user_paths)

$ echo $fish_user_paths
~/.cargo/bin ~/.local/bin /usr/local/bin

$ printf '%s\n' $fish_user_paths
~/.cargo/bin
~/.local/bin
/usr/local/bin

パスはfish_user_pathsで確認できます。

変数を設定したい(set)

set 変数名 値
set -l 変数名 値1 値2
set -gx 変数名 値    # bash/zshのexportに相当
set 変数名    # 空リストにする(未定義とは異なる)
set -q 変数名    # 変数名が定義されているかを確認

bash / zshではexportコマンドを使って変数を定義しますが、fishではsetコマンドを使います。 スコープ(-l / -g / -u)と外部変数化(-x / -u)はオプションで指定し、set -qはif文と組み合わせて変数の定義確認に使えます。

リダイレクトしたい

$ pbcopy < ~/.gitconfig
$ echo "hello" > stdout.md
$ echo "hello" 2> stderr.md
$ echo "hello" 2>&1 > stdout_and_stderr.md

fish も bash/zsh と同じリダイレクト操作が使えます。

詳しくは「実行結果をファイルに保存したい(>)」を参照してください。

実行結果で処理を分岐したい(and / or / not)

コマンドを実行; and echo "成功"
コマンドを実行; or echo "失敗"

if not test -e ファイルパス
    echo "ファイルが存在しません"
end

fishではbash/zshの&& / ||に相当する処理をand / orで書きます(&& / ||もv3.0以降エイリアスとして使えます)。 直前のコマンドが成功(終了ステータス0)した場合はand以降、失敗した場合はor以降が実行されます。 notは終了ステータスを反転させるので、if文と組み合わせて「存在しない場合」のような条件分岐にも使えます。

ワイルドカードでファイルを指定したい(* / **)

$ ls *.txt
$ ls **.txt

fishのワイルドカードはbash/zshと少し異なります。

  • *:カレントディレクトリ直下のファイルにマッチ(サブディレクトリは対象外)

  • **:カレントディレクトリ以下を再帰的に探索してマッチ

bashでおなじみの?(任意の1文字にマッチ)はfishには存在しないので注意してください。

警告

fishはワイルドカードが1件もマッチしないとエラーになり、コマンドは実行されません。

$ ls hoge**.txt
fish: No matches for wildcard 'hoge**.txt'. See `help language#wildcards-globbing`.
ls hoge**.txt
   ^~~~~~~~~~^

bash/zshではマッチしない場合ワイルドカードの文字列がそのままコマンドに渡りますが、fishではこの挙動がなく必ずエラーになります。

コマンド補完を整理したい(fish_update_completions)

$ fish_update_completions
Parsing man pages and writing completions to ~/.local/share/fish/generated_completions/
  7148 / 7148 : zic.8

fish_update_completionsでコマンド補完の候補を更新できます。 有効になったコマンド補完は~/.local/share/fish/generated_completions/で確認できます。

コマンド履歴を整理したい

// 履歴の数を確認
$ wc -l ~/.local/share/fish/fish_history
   41529

// 履歴ファイルの内容を確認
$ tail -n 30 ~/.local/share/fish/fish_history
- cmd: fish_key_reader
  when: 1718746545
- cmd: bind
  when: 1718746557
- cmd: fish_update_completions
  when: 1718746615
- cmd: cd ~/.local/share/fish/
  when: 1718746873
  paths:
    - ~/.local/share/fish/
- cmd: wc -l ~/.local/share/fish/fish_history
  when: 1718747030
  paths:
    - ~/.local/share/fish/fish_history
- cmd: tail -n 30 ~/.local/share/fish/fish_history
  when: 1718747220
  paths:
    - ~/.local/share/fish/fish_history

Fishはコマンド履歴からも補完してくれます。 しかし、打ち間違えてしまったコマンドを覚えてしまっていることもあります。 そのときは履歴ファイル(~/.local/share/fish/fish_history)を直接開き、 該当するコマンド履歴を削除します。

コマンド履歴の構造は、以下のようになっていました。 不要な項目は、この構造ごと削除します。

- cmd: コマンド名
  when: 時刻(unixtime)
  paths:
    - 実行したパス

めんどくさい場合は、履歴ファイルをまるっと削除してもいいかもしれません。