fish-shell
概要
- シェル言語の一つ
- zsh 並の補完機能がある
- さらに予測機能 (tab を押さなくても履歴機能を表示) がある
- 軽量
prevd
、nextd
、dirh
コマンドで、カレントディレクトリ履歴を基に移動できる。
インストール
- 最新版をインストールする
$ sudo add-apt-repository ppa:fish-shell/release-3 $ sudo apt update $ sudo apt install fish
- 共用サーバ等でホームディレクトリにインストールする ($HOME/local にインストールする場合)
- cmake のバージョンが 3.2 以上でない場合、cmake をインストールする。
- 最新版のソースをダウンロードする。
$ wget https://github.com/fish-shell/fish-shell/releases/download/3.1.2/fish-3.1.2.tar.gz
- ソースを展開する。
$ tar axvf fish-3.1.2.tar.gz
- インストールする。
$ cd fish-3.1.2/ $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local $ make -j 4 $ make install
- cmake の
-DCMAKE_INSTALL_PREFIX
オプションでインストール先を変える。 -j 4
は並列にコンパイルするオプションであり、この場合、4 CPU を使ってコンパイルしている。環境に応じて、変更する。
- インストールされたか確認する。
$ ~/local/bin/fish --version fish, version 3.1.2
- .bashrc の末尾に追記する。
if [ "$SSH_TTY" != "" ]; then BOOT_FISH=1 FISH_PATH=$HOME/local/bin/fish if [ $BOOT_FISH -eq 1 ]; then if [ -f $FISH_PATH ]; then $FISH_PATH exit fi fi fi
chsh
コマンドは/etc/shells
に登録されていない shell を登録することができない。BOOT_FISH
が 1 のときのみ、fish-shell 環境になる。エディタで、ここを 1 以外にすれば、bash 環境になる。- bash が一度起動しているため、環境変数は引き継がれる。
- rsync や scp が転送できない対策として、SSH_TTY の if 文を追加した (2020/10/26)。
- 再ログインする。
環境設定
- プロンプトは
fish_prompt
関数で定義する。 - 無銘闇人の現在のプロンプト
function fish_prompt printf "%s %s%s%s%s %s%s %s\n%s" (set_color -o bryellow)"["(date +"%Y/%m/%d %H:%M:%S")"]" (set_color -o green)$USER (set_color normal)"@" (set_color -o green)(hostname) (set_color -o white)"(fish)" (set_color -o blue)"["(jobs | wc -l)"]" (set_color normal)":" (set_color -o cyan)(prompt_pwd) (set_color normal)"\$ " end
- 表示:
[YYYY/MM/DD hh:mm:ss] USERNAME@HOSTNAME(fish) [JOB_NUBER]: CURRENT_DIR $
- 表示例:
[2018/03/07 10:43:45] mumeiyamibito@hoge(fish) [0]: ~ $
function fish_prompt
を何度も実行して、プロンプトが決まったら、funcsave fish_prompt
で関数を保存するか、この関数を~/.config/fish/config.fish
に保存することで、次回起動時から設定したプロンプトが適用される。後者の方法がおすすめ。- 参考サイト:
文字の色
- 文字の色はコマンドの直前に
set_color
コマンドで設定する。
set_color [OPTION] COLOR; COMMAND
COLOR
: 色名 (black
,red
,green
,yellow
,blue
,magenta
,cyan
,white
,brblack
,brred
,brgreen
,bryellow
,brblue
,brmagenta
,brcyan
,brwhite
, その他 16 進数の RGB でも指定可)OPTION
-o
: 太字モード (bold)-i
: 斜体モード (italic)-u
: 下線モード (underline)-b
: background color-r
: 反転モード
- 色名を
normal
にすると色やモードがリセットされる。
構文
変数/配列
- 定義
set
コマンドを使って定義する。
$ set VAR_NAME VALUE1 [VALUE2 VALUE3 ...]
- 意味
VAR_NAME
: 変数名VALUE1
: 値
- 配列の場合、
VALUE
をスペースで区切って指定する。 - 他のシェルと同じように変数名には
$
を付けずに指定する。 - 他のシェルの変数と異なりグローバル変数ではなく、ローカル変数となるため、注意。
- グローバル変数にする場合は、
-g
オプションを付ける。
$ set -g VAR_NAME VALUE
- 子プロセスにも伝播させるためには
-x
オプションを付ける。
$ set -x VAR_NAME VALUE
- 呼び出し
- 他のシェルと同様に
$VAR_NAME
で呼び出す。
$ echo $VAR_NAME
- 配列の場合、1 から始まるインデックス (
INDEX
) で指定する。
$ echo $VAR_NAME[INDEX]
- 変数展開は以下の 2 種類
- ダブルクォーテーションで囲む:
“$VAR_NAME”
,“$VAR_NAME”TEXT
{}
で変数全体を囲む:{$VAR_NAME}
,{$VAR_NAME}TEXT
- B シェルのように
${VAR_NAME}
だとエラーになるため注意する。
- 配列の要素数の取得
$ count $VAR_NAME
count
コマンドを使って取得する。
関数
- 定義
function
〜end
で囲む。
function FUNC_NAME DO_SOMETHING end
FUNC_NAME
: 関数名 (関数名の後に()
や{}
を付けない)DO_SOMETHING
: 関数で実行するコマンド- 引数は
$argv
で受け取る。複数の引数の場合は 1 から始まるインデックスを付けて受け取る (例:$argv[1]
)。
- 呼び出し
- 他のシェルスクリプトと同じ
FUNC_NAME
コマンド置換
- コマンドの結果を引数化する方法。
- bash などでは、以下のように実行することで中間ファイルを生成せずに目的の結果が得られる。
$ echo "$(cat a.txt | wc -l) + $(cat b.txt | wc -l)" | bc
a.txt
の行数をwc -l
コマンドでカウントする。→ 例:100
b.txt
の行数をwc -l
コマンドでカウントする。→ 例:120
- それぞれの行数を用いて数式を
echo
で表示する。→ 例:100 + 120
- 数式を
bc
コマンドで演算する。→ 例:220
- なお、
$()
は``
(バッククォーテーションで囲む) でも代用できる (ただし、ネストできない)。
- fish-shell では、単なる括弧 (
()
) でコマンド置換をする。
$ echo (cat a | wc -l)"+"(cat b | wc -l) | bc
文字操作
- マッチ
$ string match [-a|-i|-r|-n|-v] PATTERN STRING
PATTERN
: パターンSTRING
: 対象文字列-a
: 繰り返しマッチ-i
: 大文字小文字を区別しない-r
: 正規表現でパターンを指定 (デフォルトは glob (ワイルドカード))-n
: マッチした位置を返す-v
: 逆の結果を返す
- 文字の長さを取得
$ string length STRING
STRING
: 対象文字列
- 文字の置換
$ string replace [-a|-i|-r|-q|] PATTERN REPLACE STRING
PATTERN
: パターンREPLACE
: 置換後の文字列STRING
: 対象文字列-a
: 繰り返しマッチ-i
: 大文字小文字を区別しない-r
: 正規表現でパターンを指定 (デフォルトは glob (ワイルドカード))
- リストの文字列を結合
$ string join SEP LIST
SEP
: 区切り文字LIST
: 文字列リスト
- 文字列をリストに分割
$ string split [-m|-r] SEP STRING
-m
: 最大分割数-r
: 右側から分割 (デフォルトは左側から分割)SEP
: 区切り文字STRING
: 対象文字列
- 文字列のトリム (末端の文字列削除)
$ string trim [-l|-r|-c] STRING
-l
: 左側末端の文字列を削除 (デフォルトは両端)-r
: 右側末端の文字列を削除 (デフォルトは両端)-c
: 削除する文字列を指定 (デフォルトは空白)STRING
: 対象文字列
- 位置を指定して文字列抽出
$ string sub [-s|-l] STRING
-s
: 取得する文字列の開始位置-l
: 取得する文字列の長さSTRING
: 対象文字列
- エスケープ文字を追加
$ string escape [-n] STRING
-n
: 出力結果をクォーテーションで囲まないSTRING
: 対象文字列
- 参考サイト: fish shellで文字列操作
リダイレクトとパイプ
- リダイレクト
- 標準出力
$ COMMAND > FILE
- 標準出力 (追記)
$ COMMAND >> FILE
- 標準エラー
$ COMMAND ^ FILE
- 標準エラー (追記)
$ COMMAND ^^ FILE
- 標準出力と標準エラーを同時出力
$ COMMAND 2>&1 | cat > FILE
- パイプ (通常のシェルと同じ)
$ COMMAND1 | COMMAND2
コマンドが存在するか調べる
- 2 通りのコマンドがある
$ type -q <COMMAND>
OR
$ command -sq <COMMAND>
- 結果は、
$status
で受け取るか、; and
や; or
(fish-shell 3.0 以降なら&&
や||
でも可) でつなげて受け取る。- 成否を受け取るなら、
$status
を用いる
$ echo $status
- 続けて、コマンド (コマンドが存在する場合は
COMMAND1
を実行し、存在しない場合はCOMMAND2
を実行する。)
$ type -q <COMMAND>; and <COMMAND2>; or <COMMAND3>
- 参考サイト:
- fish shell はじめました (終了ステータスの変数名)
Tips
テーマを切り替える
fish_config
コマンドで、ウェブインターフェースの設定画面が現れるので、そこで変更する。- リモート環境でウェブインターフェースが使えない場合は、
set -U | grep fish_color
で表示された内容を、リモート環境でもset -U
で設定していくと同じテーマになる。
環境変数を一時的に変更する
- 設定されている環境変数で、出力する内容が変わるプログラムがいくつか存在する。
date
コマンドなどは、使用している OS の言語で、日時のフォーマットが変わる。- 出力する環境によっては、正常に動作しないプログラムもいくつか存在する。
- 元の言語 (たいていは英語) での出力を望む場合は直前に
LANG=C
を付けると良い。- bash や zsh では、コマンド (実行プログラム) の場合、素直に
LANG=C
を付ける。
$ LANG=C date
- fish の場合は、env コマンドを使う。
$ env LANG=C date
- 参考サイト: fishはじめました - iLog
find コマンドの exec が使えない
- 対策1:
{}
をシングルクォートで囲んで、最後に+
を付ける。
例:$ find . -name '*.sh' -exec chmod +x '{}' +
- 対策2: find の結果を xargs で処理する。
例:$ find . -name '*.sh' | xargs chmod +x
if 文で優先順位のある複数の条件を扱う
- fish-shell では if 文の条件で
()
を使って優先度を変えることができない (()
がコマンド置換 (bash の$()
) に割り当てられているため) - 対策:
begin 〜 end
と; and
や; or
を使う- 例:
- Python での表記
if True and not True and False: print("OK") ---> if True and not(True and False): print("OK") ---> OK
- fish-shell での表記
if true; and not true; and false echo "OK" ---> if true; and not begin true; and false; end echo "OK" ---> OK
fish-shell を導入したリモートに rsync や scp でアクセスできない
- 【症状】fish-shell を導入したリモートに rsync や scp でファイルを転送しようとすると以下のエラーメッセージが表示される
protocol version mismatch -- is your shell clean? (see the rsync man page for an explanation) rsync error: protocol incompatibility (code 2) at compat.c(178) [sender=3.1.2]
- 【原因】リモートに ssh にログインした際に、標準出力 (リモートサーバの状況やグリーティングなど) されるものがある場合にエラーになるらしい (bash など他のシェルでも同様の原因の問題があるらしい)。
- 【解決方法】
- ログイン時に実行される
config.fish
から、標準出力 (echo
など) を削除、あるいはコメントアウトする。 - ログイン時に実行される
config.fish
の標準出力部分をif status –is-interactive … end
ブロックで囲む。- 対話シェルの時のみ表示するようにする。
- 例:
if status --is-interactive echo "test" end
コマンドラインスタック
- とても役立つテクニックで、buffer stack とも呼ばれるらしい…。
- 長いコマンドを打っている時に、ヘルプオプションを見たくなった時に便利。
- 長いコマンドを打っている時に、やり忘れたコマンドを実行したくなった時に便利。
- つまり、現在の入力中のコマンドを一時的に退避させる方法。
- 方法:
- 以下の関数を
$HOME/.config/fish/config.fish
に記述する。
function push-line set cl (commandline) commandline -f repaint if test -n (string join $cl) set -g fish_buffer_stack $cl commandline '' commandline -f repaint function restore_line -e fish_postexec commandline $fish_buffer_stack functions -e restore_line set -e fish_buffer_stack end end end function fish_user_key_bindings bind \cs push-line end
- 最後の
bind …
でキーバインドを設定し、Ctrl + s で動作するようにしている。
rsync や scp で fish をインストールしたリモートサーバにファイルを転送できない (旧方法)
.bashrc
の先頭に記述する。
if [ -z "$PS1" ]; then return fi
- .bashrc で何らかの処理がされている場合、scp や rsync が進行しないエラーが発生するため、.bashrc がこれらのコマンドで読み込まれた際、対話モードでない場合は即座に終了するようにする。
ハイフンの入った文字列の置換ができない
- 問題:
string replace
でハイフンの入ったパターンを置換できない。 - 解決策:
replace
の後に–
(ハイフン 2 つ) を入れる。- 例:
$ string replace -- '-min' '' 'hoge-min.js' hoge.js