fish-shell

fish-shell

  • シェル言語の一つ
  • zsh 並の補完機能がある
    • さらに予測機能 (tab を押さなくても履歴機能を表示) がある
  • 軽量
  • prevdnextddirh コマンドで、カレントディレクトリ履歴を基に移動できる。
  • 最新版をインストールする
    $ sudo add-apt-repository ppa:fish-shell/release-3
    $ sudo apt update
    $ sudo apt install fish
  • 共用サーバ等でホームディレクトリにインストールする ($HOME/local にインストールする場合)
    1. cmake のバージョンが 3.2 以上でない場合、cmake をインストールする。
    2. 最新版のソースをダウンロードする。
      $ wget https://github.com/fish-shell/fish-shell/releases/download/3.1.2/fish-3.1.2.tar.gz
    3. ソースを展開する。
      $ tar axvf fish-3.1.2.tar.gz
    4. インストールする。
      $ cd fish-3.1.2/
      $ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local
      $ make -j 4
      $ make install
      • cmake の -DCMAKE_INSTALL_PREFIX オプションでインストール先を変える。
      • -j 4 は並列にコンパイルするオプションであり、この場合、4 CPU を使ってコンパイルしている。環境に応じて、変更する。
    5. インストールされたか確認する。
      $ ~/local/bin/fish --version
      fish, version 3.1.2
    6. .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
    7. 再ログインする。
  • プロンプトは 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 コマンドを使って取得する。
  • 定義
    • functionend で囲む。
      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
    1. a.txt の行数を wc -l コマンドでカウントする。→ 例: 100
    2. b.txt の行数を wc -l コマンドでカウントする。→ 例: 120
    3. それぞれの行数を用いて数式を echo で表示する。→ 例: 100 + 120
    4. 数式を 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: 対象文字列
  • リダイレクト
    • 標準出力
      $ 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_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
  • 対策1: {} をシングルクォートで囲んで、最後に + を付ける。
    例:
    $ find . -name '*.sh' -exec chmod +x '{}' +
  • 対策2: find の結果を xargs で処理する。
    例:
    $ find . -name '*.sh' | xargs chmod +x
  • 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 でファイルを転送しようとすると以下のエラーメッセージが表示される
    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 で動作するようにしている。
  • .bashrc の先頭に記述する。
    if [ -z "$PS1" ]; then
    	return
    fi
    • .bashrc で何らかの処理がされている場合、scp や rsync が進行しないエラーが発生するため、.bashrc がこれらのコマンドで読み込まれた際、対話モードでない場合は即座に終了するようにする。
  • 問題: string replace でハイフンの入ったパターンを置換できない。
  • 解決策: replace の後に (ハイフン 2 つ) を入れる。
    • 例:
      $ string replace -- '-min' '' 'hoge-min.js'
      hoge.js
  • fish-shell.txt
  • 最終更新: 2023/05/12 15:15
  • by mumeiyamibito