Fish Shell Cheatsheet - Config, Functions & Aliases
Fish ships with highlighting, completion and fuzzy history search enabled out of the box, so the gap to Bash is less about features and more about zero setup. The real cost of switching is syntax. Blocks close with end instead of fi or done, variables are set rather than exported, list indexing starts at 1, and string handling leans on command substitution where Bash uses pipes. Interaction is mostly muscle memory, but scripts are where migrations break, because .bashrc fragments copied verbatim tend to fail in confusing ways. This sheet is organised as a translation table: variable scope, control flow, functions and abbreviations, string and pipeline idioms, configuration and themes, then history and key bindings. Use it to convert a Bash habit into its Fish equivalent instead of guessing, or to decide when wrapping the command in sh -c is the saner option. Anything with a shebang and strict POSIX assumptions still belongs in /bin/sh rather than being ported, so judge per script instead of per shell.
Typical Use Case
For developers who switched to fish and kept writing bash. fish is not a bash with different prompt settings: variables are set with a command rather than an assignment, there is no process substitution, and lists splice instead of word-splitting. Migrating by copying your .bashrc mostly fails. This sheet covers the syntax differences that actually bite, the three variable scopes, history and search, string manipulation, and plugin installation with fisher.
Variables & Scope 7
set name "John"echo $nameset -x PATH /usr/local/bin $PATHset -U fish_user_paths /usr/local/bin $fish_user_pathsset -l local_var "value"set -g global_var "value"set -e nameControl Flow 5
if test -f file.txt\n echo "exists"\nendif test $count -gt 5\n echo "many"\nelse\n echo "few"\nendfor file in *.txt\n echo $file\nendwhile read -l line\n echo $line\nend < file.txtswitch $status\n case 0\n echo "success"\n case "*"\n echo "failed"\nendFunctions & Aliases 7
function greet\n echo "Hello $argv"\nendfuncsave greetfunctionsfunctions greetalias cls="clear"abbr -a gco "git checkout"funced greetStrings & Pipes 6
string length "hello"string split "," "a,b,c"string join ";" "a" "b" "c"string replace "old" "new" "hello old"string match -r "^\d+" "123abc"echo "data" | string upperConfig & Theme 6
fish_configfish_config theme choose Nordset -U fish_greeting ""fish_update_completionscat ~/.config/fish/config.fishfisher install jorgebucaran/autopair.fishHistory & Keys 5
historyhistory search "git"history delete "rm -rf"Ctrl+RAlt+← / Alt+→Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
set -x / -g / -U / -l / -e | Exported (environment), global, universal (persistent across sessions), local, and erase | set -U fish_user_paths /usr/local/bin $fish_user_paths |
fish_greeting | The login banner; setting it to an empty string removes the greeting | set -U fish_greeting "" |
abbr -a | Command abbreviation: expands on typing and stays out of history, better than alias for commands | abbr -a gco "git checkout" |
string | Built-in string toolkit that replaces bash cut/sed/tr/grep pipelines | string split "," "a,b,c" |
funcsave | Persist a function you just defined interactively into the config file | funcsave greet |
Common pitfalls
SymptomMoving export PATH=... from .bashrc into fish leaves PATH unchanged, or adds a literal string to it.
Causeexport VAR=value is not valid fish syntax; fish assigns with the set command and flags.
FixUse set -x PATH /usr/local/bin $PATH, or set -U fish_user_paths /usr/local/bin $fish_user_paths to make it persistent.
SymptomA function you defined interactively is gone after closing the terminal.
Causefish never writes interactively defined functions back to the config file on its own.
FixRun funcsave greet after defining it; edit an existing one with funced greet.
SymptomStartup reports "fish: Unknown command: [" followed by a pile of syntax errors.
CauseBash [ ] conditional syntax was pasted in; fish uses test plus end blocks instead.
FixRewrite as native fish blocks such as if test $count -gt 5 / else / end, converting piece by piece.
SymptomDisabling an alias with "alias name" fails saying the function does not exist.
Causefish aliases are functions, so unalias has no equivalent and removal uses functions -e.
FixUse functions -e name; for command substitutions prefer abbr -a, which expands more cleanly.
SymptomA PATH entry you added manually disappears after restarting the terminal.
Causeset -x only affects the exported variable for this session and never reaches persistent storage.
FixUse set -U fish_user_paths /usr/local/bin $fish_user_paths so it survives across sessions.
Troubleshooting
1Check whether the config actually took effect
cat ~/.config/fish/config.fishfish reads only this file (not .bashrc); reload with source ~/.config/fish/config.fish after editing.
2Find a long command you ran before
history search "git"The non-interactive twin of Ctrl+R incremental search; history delete "rm -rf" removes risky entries.
3Inspect a function or alias definition
functions && functions greetfunctions lists everything, functions greet prints one definition - enough to spot a shadowed name.
4Install a plugin
fisher install jorgebucaran/autopair.fishfisher is the fish plugin manager; afterwards run functions to confirm the plugin loaded.
Tips
- Fish's if/for/function/switch end with end (no fi/done/esac).
- set -U sets a universal var, persisted and shared across sessions.
- Fish has autocompletion out of the box; Tab to use, Alt+Right to accept.
- fisher is Fish's plugin manager: curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher.
- abbr is lighter than alias and auto-expands to the full command.
- Fish isn't POSIX-compatible; can't run bash scripts directly, but is more intuitive.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us