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.
fishfish -c '<command>' — Execute a command string and exit.
fish -c 'echo Hello World'fish -l — Start as a login shell.
fish -lfish -n <script> — Check syntax without executing (no-execute mode).
fish -n myscript.fishfish_config — Open the web-based configuration UI in a browser.
fish_configfish_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 --versionVariables & 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 vimset -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_VARset -S <var> — Show detailed info about a variable (scope, export status).
set -S PATHset -l <var> <value> — Set a local variable (only in current block).
set -l tmp_file /tmp/output.txtfish_add_path <dir> — Permanently add a directory to PATH (universal).
fish_add_path ~/.local/binAbbreviations & 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 gcoabbr -l — List all abbreviation names.
abbr -labbr --show — Show all abbreviations with their expansions.
abbr --showalias <name> '<command>' — Create a function alias (wrapper around function).
alias ll 'ls -la'funcsave <name> — Save a function/alias permanently to disk.
funcsave llFunctions
function <name>; ...; end — Define a function.
function greet; echo "Hello, $argv[1]"; endfunction <name> -a <args>; ...; end — Define a function with named arguments.
function greet -a name; echo "Hello, $name"; endfunction <name> -d '<desc>' — Define a function with a description.
function serve -d 'Start dev server'; python3 -m http.server; endfunctions <name> — Show the definition of a function.
functions greetfunctions -e <name> — Erase a function.
functions -e greetfuncsave <name> — Save function to ~/.config/fish/functions/
funcsave greetfunctions -n — List all defined function names.
functions -nControl Flow
if <condition>; ...; else; ...; end — Conditional execution.
if test -f config.yaml; echo 'Found'; else; echo 'Missing'; endswitch <value>; case <pattern>; ...; end — Pattern matching (like case/switch).
switch $os; case Linux; echo 'Linux'; case Darwin; echo 'Mac'; endfor <var> in <list>; ...; end — Loop over a list of values.
for f in *.txt; echo $f; endwhile <condition>; ...; end — Loop while a condition is true.
while test $count -lt 10; set count (math $count + 1); endbegin; ...; end — Group commands in a block (for redirection or scoping).
begin; echo stdout; echo stderr >&2; end 2>/dev/nulland <command> — Execute command only if the previous succeeded.
make build; and make testor <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.txtstring 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 githistory delete --exact '<cmd>' — Delete a specific entry from history.
history delete --exact 'rm -rf /tmp/test'history clear — Clear all command history.
history clearhistory 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
- fish documentation – the official reference and complete tutorial
- fish tutorial – hands-on introduction to the Friendly Interactive Shell