FUNCTION(1)

πŸŽ€ FUNCTION(1) β€” the fish-shell manual, section 1 πŸŽ€

okay bestie, buckle up, because we're learning how to make functions in fish and honestly? it's giving main character energy. this is from the fish-shell manual (section 1, iykyk).


✨ NAME ✨

function β€” create a function. that's it. that's the whole name. iconic.


🌸 SYNOPSIS 🌸

function NAME [OPTIONS]; BODY; end

πŸ’– DESCRIPTION πŸ’–

function creates a new function called NAME with the body BODY. periodt.

so what even is a function? a function is literally just a list of commands that get executed whenever you type the function's name as a command. no cap. you write it once, you call it forever. it's the friend who always shows up. 🫢

the following options are available:

  • -a NAMES, --argument-names NAMES β€” assigns the value of successive command-line arguments to the names given in NAMES (separated by spaces). these are the same arguments given in argv (see the argv docs at #envvar-argv), and they're still available there too β€” unless --inherit-variable argv was used, or one of the given NAMES is argv. also peep "Argument Handling" at #variables-argv.
  • -d DESCRIPTION, --description DESCRIPTION β€” a lil description of what the function does, suitable as a completion description. basically the vibe check of your function. ✨
  • -w WRAPPED_COMMAND, --wraps WRAPPED_COMMAND β€” inherit completions from the given WRAPPED_COMMAND. this is how you say "hey, this function completes like that command" β€” for example if you're creating an alias. see the documentation for complete for more info. note: if the wrapped command is the same as the function name, this will be ignored. πŸ™ˆ
  • -e EVENT_NAME, --on-event EVENT_NAME β€” run this function when the specified named event is emitted. fish internally generates named events, for example when showing the prompt. custom events can be emitted using the emit command. lowkey magical. πŸ”₯
  • -v VARIABLE_NAME, --on-variable VARIABLE_NAME β€” run this function when the variable VARIABLE_NAME changes value. important caveat: fish makes no guarantees on any particular timing, or even that the function will be run for every single set. rather, it will be run when the variable has been set at least once β€” possibly skipping some values, or being run when the variable has been set to the same value (except for universal variables set in other shells, where only changes in the value will be picked up for those).
  • -j PID, --on-job-exit PID β€” run this function when the job containing a child process with the given process ID PID exits. instead of a PID, the string 'caller' can be specified. this is only allowed when in a command substitution, and will result in the handler being triggered by the exit of the job which created this command substitution. heads up: this will not trigger for disowned jobs (see disowned).
  • -p PID, --on-process-exit PID β€” run this function when the fish child process with process ID PID exits. instead of a PID, for backward compatibility, "%self" can be specified as an alias for $fish_pid, and the function will be run when the current fish instance exits. also heads up: this will not trigger for disowned jobs (see disowned).
  • -s SIGSPEC, --on-signal SIGSPEC β€” run this function when the signal SIGSPEC is delivered. SIGSPEC can be a signal number, or the signal name, such as SIGHUP (or just HUP). note that the signal must have been delivered to fish β€” for example, Ctrl+C sends SIGINT to the foreground process group, which will not be fish if you are running another command at the time. and get this: observing a signal will prevent fish from exiting in response to that signal. πŸ’…
  • -S, --no-scope-shadowing β€” allows the function to access the variables of calling functions. normally, any variables inside the function that have the same name as variables from the calling function are "shadowed", and their contents are independent of the calling function.
⚠️ it's important to note that this does not capture referenced variables or the scope at the time of function declaration! at this time, fish does not have any concept of closures, and variable lifetimes are never extended. in other words, by using --no-scope-shadowing, the scope of the function each time it is run is shared with the scope it was called from rather than the scope it was defined in. read that twice bestie, it matters. 😭
  • -V, --inherit-variable NAME β€” snapshots the value of the variable NAME and defines a local variable with that same name and value when the function is defined. this is similar to a closure in other languages like Python, but a bit different. note the word "snapshot" in the first sentence. if you change the value of the variable after defining the function β€” even if you do so in the same scope (typically another function) β€” the new value will not be used by the function you just created using this option. see the function notify example below for how this might be used. πŸ‘‘

the event handler switches (on-event, on-variable, on-job-exit, on-process-exit and on-signal) cause a function to run automatically at specific events. new named events for --on-event can be fired using the emit builtin. fish already generates a few events β€” see "Event handlers" at #event for more. πŸ¦‹

functions names cannot be reserved words. these are elements of fish syntax or builtin commands which are essential for the operations of the shell. current reserved words are: [, _, and, argparse, begin, break, builtin, case, command, continue, else, end, eval, exec, for, function, if, not, or, read, return, set, status, string, switch, test, time, and while. so like… don't even try it. πŸ’€

care should be taken when creating a function of the same name as an existing shell builtin or common program. if the function behaves differently, it is very common for problems to occur within fish or in scripts written by others. consider writing an abbreviation instead (see abbreviation) if you are wanting to replace one tool with another for interactive use. πŸŽ€


🌈 EXAMPLE 🌈

function ll
    ls -l $argv
end

will run the ls command, using the -l option, while passing on any additional files and switches to ls.

function debug -a name val
    echo [DEBUG] $name: $val >&2
end

set foo bar
debug foo bar
# prints: [DEBUG] foo: bar

# OR

function debug2 -a var
    echo [DEBUG] $var: $$var >&2
end

set foo bar
debug2 foo
# prints: [DEBUG] foo: bar

will create a debug command to print chosen variables to stderr. slay. πŸ“

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

this will run the mkdir command, and if it is successful, change the current working directory to the one just created. honestly? convenient.

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

this will beep when the most recent job completes. beep beep bestie πŸ””


πŸ’œ NOTES πŸ’œ

events are only received from the current fish process, as there is no way to send events from one fish process to another. fr fr, that's just how it is.


⭐ SEE MORE ⭐

for more explanation of how functions fit into fish, see "Functions" at #syntax-function. 🧚


fish-shell developers


aaaaand that's the whole page, bestie! if you made it this far you're officially a fish function girlie πŸ’…βœ¨ β€” this was FUNCTION(1) from the fish-shell manual, version 4.9, dated Sep 08, 2026. go forth and define functions, but like, responsibly. πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from
  • arch rolling: fish 4.9.3-1 Β· GPL-2.0-only AND BSD-3-Clause AND ISC AND MIT AND PSF-2.0
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms