書式
function NAME [OPTIONS]; BODY; end

概要

function コマンドは関数名 NAME
本体 BODY の関数を定義します。

関数とは
関数名がコマンドとして与えられたときに
実行されるコマンドのリストです。

オプション

以下のオプションが用意されています。

-a NAMES / --argument-names NAMES
コマンドライン引数を変数 NAMES に割り当てる。
-d DESCRIPTION / --description=DESCRIPTION
関数の動作についての説明文。
補完時の説明文に適している。
-w WRAPPED_COMMAND / --wraps=WRAPPED_COMMAND
WRAPPED_COMMAND から補完設定を継承する。
詳しくは complete コマンドを参照。
-e EVENT_NAME / --on-event EVENT_NAME

イベント EVENT_NAME
発生したときに関数を実行する。

fishは内部的にイベントを発生させている、
たとえばプロンプト表示時などに。

-v VARIABLE_NAME / --on-variable VARIABLE_NAME
変数 VARIABLE_NAME の値が
変更されたときに関数を実行する。
-j PGID / --on-job-exit PGID

グループID PGID のジョブが
終了したときに関数を実行する。

PGID の代わりに
文字列 caller を設定できる。

caller 指定は コマンド置換 内のみで有効で、
そのコマンド置換を作成したジョブが
終了したときに発動するハンドラとなる。

-p PID / --on-process-exit PID
プロセスID PID のfishの子プロセスが
終了したときに関数を実行する。
-s SIGSPEC / --on-signal SIGSPEC

シグナル SIGSPEC を受け取ったときに
関数を実行する。

SIGSPEC はシグナル番号か
シグナル名(SIGHUP とか HUP)。

-S / --no-scope-shadowing

呼び出し元の関数の変数に
アクセスできるようにする。

通常では、関数内においては
呼び出し元と同名の全変数は隠蔽される、

つまり、関数内の変数の値は
呼び出し元の関数とは無関係である。
関数における変数スコープ 参照。

-V NAME / --inherit-variable NAME
関数実行時に、
変数 NAME の値を複写し、
同名同値のローカル変数を定義する。

関数に追加の引数を与えられたとき、
環境変数配列 $argv に設定されます。
--argument-names オプションが設定されたとき、
引数はオプションに指定された変数 にも 設定されます。

イベントハンドラ

イベントハンドラのオプションの
ひとつが関数に与えられたとき、
関数は特定のイベントが発生したときに
自動で実行されます。

  • -e / --on-event
  • -v / --on-variable
  • -j / --on-job-exit
  • -p / --on-process-exit
  • -s / --on-signal

ユーザは新しいイベントを
emit コマンドをで生成できます。

fishは以下のイベントを生成します。

fish_prompt
fishのプロンプトが表示される直前に発生する。
fish_command_not_found
コマンド検索に失敗したときに発生する。
fish_preexec

コマンドラインから
コマンドを実行する直前に発生する。

呼び出された関数の最初の引数に
コマンドラインが渡される。

fish_postexec

コマンドラインから
コマンドを実行した直後に発生する。

呼び出された関数の最初の引数に
コマンドラインが渡される。

注意:
fish_preexecfish_postexec
コマンドラインが不正であっても発生します。

コマンドラインパラメータには
コマンドラインの内容そのまま渡されます。

改行文字が含まれている可能性もあります。

実行例

以下は ll 関数を定義します。

  • ls コマンドを -l オプションを付けて実行
  • ls に渡るファイルやスイッチも渡せる
function ll
    ls -l $argv
end

以下は mkdir 関数を定義します。

  • command コマンドにより、
    外部コマンドの mkdir を実行する
  • 成功すれば
    作成したディレクトリ(訳注:最後の引数)に
    カレントディレクトリを変更する
  • 訳注:最後の引数がオプションの場合は
    他には何もしない。
function mkdir -d 'Create a directory and set CWD'
    command mkdir $argv
    if test $status = 0
        switch $argv[(count $argv)]
            case '-*'

            case '*'
                cd $argv[(count $argv)]
                return
        end
    end
end

以下は notify 関数を定義します。

  • 最近のジョブが完了したときにビープ音を鳴らす。
  • 以後訳注: jobs -l -g で最近のジョブのグループIDを取得
  • $job はローカル変数
  • ジョブがないときは 終了ステータス 1(異常終了)
  • 関数内関数 _notify_job_$job を定義
    • $job の値を関数名に埋め込んでいる
    • --on-job-exit でジョブが終了したときに
      実行できるイベントハンドラ
    • --inherit-variable job$job
      関数内関数でも参照できるようにしている
    • functions -e で関数自身を削除(自殺)
function notify
    set -l job (jobs -l -g)
    or begin; echo 'There are no jobs' >&2; return 1; end

    function _notify_job_$job --on-job-exit $job --inherit-variable job
        echo -n \a  # beep
        functions -e _notify_job_$job
    end
end

変数のスコープを表した実例

まず基本的なこととして、
関数内においては、
外側の同名のローカル変数は隠蔽されます。

次に -S-V の違いを示します。

前者がいわばダイナミックスコープで、
外側の変数が見えている状態です。

後者は関数定義時の値がコピーされるだけです。

あくまでローカル変数ですので、
外側の変数には影響しません。

function f1
        echo "in f1:$a"         # ""
        set -l a 1
        function f2 -S          # ダイナミックスコープになる
                echo "in f2:$a"
                set a 10        # 外側のaが変更される
        end
        function f3 --inherit-variable a # 定義時の値1がコピーされる
                echo "in f3:$a"
                set a 100       # 外側には影響しない
        end


        echo "before f2:$a"     # 1
        f2                      # 1
        echo "after f2:$a"      # 10
        f3                      # 1
        echo "after f3:$a"      # 10
end
set -l a 0
echo "outside: $a"               # 0
# ローカル変数は関数内では隠蔽される
f1
echo "outside: $a"               # 0

実行結果はこうなります。

outside: 0
in f1:
before f2:1
in f2:1
after f2:10
in f3:1
after f3:10
outside: 0

最後までお読みいただき、ありがとうございました。参考になれば嬉しいです。