fish — the user-friendly shell with autosuggestions

Practical guide to fish — variables, functions, abbreviations and universal variables in the user-friendly, non-POSIX command-line shell.

fish – the Friendly Interactive Shell – favours comfort over convention: autosuggestions, syntax highlighting and smart tab completion all work straight away, with no configuration required. Its main stumbling block is the deliberately non-POSIX syntax – instead of export you use set -x, and instead of &&/|| you write and/or. This guide walks you through the variables, functions, abbreviations and string tools you actually reach for day to day.

Basics

fish — Start a Fish shell session.

fish

fish -c '<command>' — Execute a command string and exit.

fish -c 'echo Hello World'

fish -l — Start as a login shell.

fish -l

fish -n <script> — Check syntax without executing (no-execute mode).

fish -n myscript.fish

fish_config — Open the web-based configuration UI in a browser.

fish_config

fish_config theme choose <name> — Set a color theme from the command line.

fish_config theme choose 'Dracula'

fish --version — Show the installed Fish version.

fish --version

Variables & Environment

set <var> <value> — Set a local variable (current scope only).

set name 'World'

set -x <var> <value> — Set and export a variable (available to child processes).

set -x EDITOR vim

set -U <var> <value> — Set a universal variable (persists across sessions and restarts).

set -U fish_greeting 'Welcome back!'

set -e <var> — Erase (unset) a variable.

set -e TEMP_VAR

set -S <var> — Show detailed info about a variable (scope, export status).

set -S PATH

set -l <var> <value> — Set a local variable (only in current block).

set -l tmp_file /tmp/output.txt

fish_add_path <dir> — Permanently add a directory to PATH (universal).

fish_add_path ~/.local/bin

Abbreviations & Aliases

abbr -a <name> <expansion> — Add an abbreviation (expands inline when typed).

abbr -a gco 'git checkout'

abbr -a --position command <name> <expansion> — Add abbreviation that only triggers in command position.

abbr -a --position command l 'ls -la'

abbr -e <name> — Erase an abbreviation.

abbr -e gco

abbr -l — List all abbreviation names.

abbr -l

abbr --show — Show all abbreviations with their expansions.

abbr --show

alias <name> '<command>' — Create a function alias (wrapper around function).

alias ll 'ls -la'

funcsave <name> — Save a function/alias permanently to disk.

funcsave ll

Functions

function <name>; ...; end — Define a function.

function greet; echo "Hello, $argv[1]"; end

function <name> -a <args>; ...; end — Define a function with named arguments.

function greet -a name; echo "Hello, $name"; end

function <name> -d '<desc>' — Define a function with a description.

function serve -d 'Start dev server'; python3 -m http.server; end

functions <name> — Show the definition of a function.

functions greet

functions -e <name> — Erase a function.

functions -e greet

funcsave <name> — Save function to ~/.config/fish/functions/.fish.

funcsave greet

functions -n — List all defined function names.

functions -n

Control Flow

if <condition>; ...; else; ...; end — Conditional execution.

if test -f config.yaml; echo 'Found'; else; echo 'Missing'; end

switch <value>; case <pattern>; ...; end — Pattern matching (like case/switch).

switch $os; case Linux; echo 'Linux'; case Darwin; echo 'Mac'; end

for <var> in <list>; ...; end — Loop over a list of values.

for f in *.txt; echo $f; end

while <condition>; ...; end — Loop while a condition is true.

while test $count -lt 10; set count (math $count + 1); end

begin; ...; end — Group commands in a block (for redirection or scoping).

begin; echo stdout; echo stderr >&2; end 2>/dev/null

and <command> — Execute command only if the previous succeeded.

make build; and make test

or <command> — Execute command only if the previous failed.

test -f .env; or echo '.env not found'

String & Math

string match '<pattern>' <string> — Match strings against a glob or regex pattern.

string match '*.txt' readme.txt

string replace '<old>' '<new>' <string> — Replace first occurrence in a string.

string replace 'foo' 'bar' 'foobar'

string split '<sep>' <string> — Split a string by a delimiter.

string split ',' 'a,b,c'

string trim <string> — Remove leading and trailing whitespace.

string trim '  hello  '

string length <string> — Return the length of a string.

string length 'hello'

string sub -s <start> -l <len> <string> — Extract a substring.

string sub -s 1 -l 5 'Hello World'

math '<expression>' — Evaluate a math expression.

math '2 ^ 10'

Completions & History

complete -c <cmd> -s <short> -l <long> -d '<desc>' — Add a tab completion for a command.

complete -c myapp -s v -l verbose -d 'Enable verbose output'

complete -c <cmd> -a '<args>' — Add argument completions for a command.

complete -c myapp -a 'start stop restart'

history search <term> — Search command history.

history search git

history delete --exact '<cmd>' — Delete a specific entry from history.

history delete --exact 'rm -rf /tmp/test'

history clear — Clear all command history.

history clear

history merge — Merge history from other Fish sessions.

history merge

Conclusion

fish takes a lot of typing off your hands: autosuggestions, syntax highlighting and completions are available with zero setup, and with set -U, funcsave and fish_config you can build a persistent environment of your own. The biggest stumbling block remains the non-POSIX syntax: snippets from bash/zsh or Stack Overflow often won't run unchanged – you have to translate export, &&/|| and command substitution into set -x, and/or and fish's (…) parentheses. For portable scripts that must run everywhere, a #!/bin/sh shebang stays the safe choice; as a comfortable interactive everyday shell, however, fish really shines.

Further Reading

  • bash – the ubiquitous POSIX shell and default on most Linux systems
  • zsh – a powerful POSIX-compatible shell with extensive enhancements
  • env – show environment variables and run commands in a modified environment