FISH-INTERACTIVE(1)

πŸ’… FISH-INTERACTIVE πŸ’…

okay so bestie, this is the FISH-INTERACTIVE(1) page from the fish-shell docs, and it's literally the whole reason fish is so nice to actually use β€” like, interactively, on the daily, not just for writing scripts. fish has a bunch of features that make the command line feel less like a punishment and more like a vibe, and we're gonna walk through them in the next few sections. 🫢

fish does its thing by taking commands in the fish language β€” if you need the deets on that, go peek at The fish Language 🐟.


✨ HELP ✨

fish has an extensive help system, bestie. use the help command to get help on a specific subject or command. for instance, typing help syntax displays the syntax section of this documentation. iconic, right? πŸ’–

fish also ships man pages for its commands, and it translates the help pages into man pages. so like, man set will show you the documentation for set as a man page. slay. πŸŽ€

you can also get help on a specific builtin with the -h parameter. for example, to obtain help on the fg builtin, either type fg -h or help fg. easy.

the main page can be viewed via help index (or just help) or man fish-doc. and the tutorial? that's help tutorial or man fish-tutorial. you're welcome. 🌸


πŸ¦‹ AUTOSUGGESTIONS πŸ¦‹

fish suggests commands as you type, based on command history, completions, and valid file paths. as you type commands, you'll see a suggestion offered after the cursor, in a muted gray color (which can be changed with the fish_color_autosuggestion variable). it's giving psychic but make it shell. πŸ”₯

  • to accept the autosuggestion (replacing the command line contents), press β†’ (right) or Ctrl+F.
  • to accept the first suggested word only, press Alt+β†’ (alt-right) or Alt+F.

if the autosuggestion is not what you want, just ignore it β€” ngl it won't execute unless you accept it. no pressure. πŸ™ˆ

autosuggestions are a powerful way to quickly summon frequently entered commands, by typing the first few characters. they're also an efficient technique for navigating through directory hierarchies. main character energy for real. πŸ‘‘

if you don't like autosuggestions, you can disable them by setting $fish_autosuggestion_enabled to 0:

set -g fish_autosuggestion_enabled 0

πŸŽ€ TAB COMPLETION πŸŽ€

tab completion is a time-saving feature of any modern shell. when you type Tab, fish tries to guess the rest of the word under the cursor. if it finds exactly one possibility, it inserts it β€” periodt. if it finds more, it inserts the longest unambiguous part and then opens a menu (the "pager") that you can navigate to find what you're looking for. ✨

the pager can be navigated with the arrow keys, PageUp / PageDown, Tab or Shift+Tab. pressing Ctrl+S (the pager-toggle-search binding β€” / in vi mode) opens up a search menu that you can use to filter the list. lowkey a lifesaver. πŸ’œ

fish provides some general purpose completions, like for commands, variable names, usernames or files.

it also provides a large number of program-specific scripted completions. most of these completions are simple options like the -l option for ls, but a lot are more advanced. for example:

  • man and whatis show the installed manual pages as completions.
  • make uses targets in the Makefile in the current directory as completions.
  • mount uses mount points specified in fstab as completions.
  • apt, rpm and yum show installed or installable packages.

you can also write your own completions or install some you got from someone else. for that, see Writing your own completions 🧚.

completion scripts are loaded on demand, like functions are. the difference is the $fish_complete_path list is used instead of $fish_function_path. typically you can drop new completions in ~/.config/fish/completions/<name-of-command>.fish and fish will find them automatically. πŸ’–


🌈 SYNTAX HIGHLIGHTING 🌈

fish interprets the command line as it's typed and uses syntax highlighting to provide feedback. the most important feedback is the detection of potential errors β€” by default, errors are marked red. 🚨

detected errors include:

  • Non-existing commands.
  • Reading from or appending to a non-existing file.
  • Incorrect use of output redirects.
  • Mismatched parenthesis.

to customize the syntax highlighting, you can set the environment variables listed in the Variables for changing highlighting colors section.

fish also provides pre-made color themes you can pick with fish_config. running just fish_config opens a browser interface, or you can use fish_config theme from fish:

# disable nearly all coloring
fish_config theme choose none
# restore fish's default theme
fish_config theme choose default

or, to see all themes, right in your terminal:

fish_config theme show

to update the theme of all shell sessions without restarting them, first have those sessions define an event handler by adding the following to your config.fish and restarting them:

function apply-my-theme --on-variable=my_theme
    fish_config theme choose $my_theme
end

then, set the corresponding universal variable from any session:

> set -U my_theme lava
> set -U my_theme snow-day

πŸ’… Syntax highlighting variables πŸ’…

the colors used by fish for syntax highlighting can be configured by changing the values of various variables. the value of these variables can be one of the colors accepted by the set_color command. options accepted by set_color like --foreground=, --background=, --bold, --dim, --italics, --reverse, --strikethrough, --underline and --underline-color= are also accepted. so many options, so much power. 😭

example: to make errors highlighted and red, use:

set fish_color_error red --bold

okay so the following variables are available to change the highlighting colors in fish β€” and bestie, we are going through every single one, no skips πŸ’…βœ¨

  • fish_color_normal β€” default color πŸ’–
  • fish_color_command β€” commands like echo ✨
  • fish_color_builtin β€” builtin commands like cd and set - this falls back on the command color if unset 🫢
  • fish_color_function β€” user-defined functions - this falls back on the command color if unset πŸ¦‹
  • fish_color_keyword β€” keywords like if - this falls back on the command color if unset 🌸
  • fish_color_quote β€” quoted text like "abc" πŸŽ€
  • fish_color_redirection β€” IO redirections like >/dev/null πŸ”₯
  • fish_color_end β€” process separators like ; and & ⭐
  • fish_color_error β€” syntax errors πŸ’€
  • fish_color_param β€” ordinary command parameters πŸ’œ
  • fish_color_valid_path β€” parameters and redirection targets that are filenames (if the file exists) 🌈
  • fish_color_option β€” options starting with "-", up to the first "--" parameter πŸ‘‘
  • fish_color_comment β€” comments like '# important' πŸ™ˆ
  • fish_color_selection β€” selected text in vi visual mode πŸ’…
  • fish_color_operator β€” parameter expansion operators like * and ~ 🧚
  • fish_color_escape β€” character escapes like \n and \x70 πŸ“
  • fish_color_autosuggestion β€” autosuggestions (the proposed rest of a command) πŸ’­
  • fish_color_cwd β€” the current working directory in the default prompt πŸ’–
  • fish_color_cwd_root β€” the current working directory in the default prompt for the root user πŸ‘‘
  • fish_color_user β€” the username in the default prompt 🫢
  • fish_color_host β€” the hostname in the default prompt 🌸
  • fish_color_host_remote β€” the hostname in the default prompt for remote sessions (like ssh) πŸ¦‹
  • fish_color_status β€” the last command's nonzero exit code in the default prompt πŸ’€
  • fish_color_cancel β€” the '^C' indicator on a canceled command 😭
  • fish_color_search_match β€” history search matches and selected pager items (background only) πŸ”
  • fish_color_history_current β€” the current position in the history for commands like dirh and cdh πŸŽ€

If a variable isn't set or is empty after subtracting any --theme=THEME options, fish usually tries $fish_color_normal, except for: πŸŽ€

  • $fish_color_builtin and $fish_color_function, where they try $fish_color_command first. πŸ’–
  • $fish_color_keyword, where it tries $fish_color_command first. πŸ’–
  • $fish_color_option, where it tries $fish_color_param first. πŸ’–

okay so one last little color rule before we move on, bestie:

  • For $fish_color_valid_path, if that doesn't have a color, but only modifiers, it adds those to the color that would otherwise be used, like $fish_color_param. But if valid paths have a color, it uses that and adds in modifiers from the other color.

🎨 Pager color variables 🎨

fish will sometimes present a list of choices in a table, called the pager. Yes, it's giving menu energy. πŸ’…

Example: to set the background of each pager row, use:

set fish_pager_color_background --background=white

To have black text on alternating white and gray backgrounds:

set fish_pager_color_prefix black
set fish_pager_color_completion black
set fish_pager_color_description black
set fish_pager_color_background --background=white
set fish_pager_color_secondary_background --background=brwhite

Variables affecting the pager colors:

  • fish_pager_color_progress β€” the progress bar at the bottom left corner
  • fish_pager_color_background β€” the background color of a line
  • fish_pager_color_prefix β€” the prefix string, i.e. the string that is to be completed
  • fish_pager_color_completion β€” the completion itself, i.e. the proposed rest of the string
  • fish_pager_color_description β€” the completion description
  • fish_pager_color_selected_background β€” background of the selected completion
  • fish_pager_color_selected_prefix β€” prefix of the selected completion
  • fish_pager_color_selected_completion β€” suffix of the selected completion
  • fish_pager_color_selected_description β€” description of the selected completion
  • fish_pager_color_secondary_background β€” background of every second unselected completion
  • fish_pager_color_secondary_prefix β€” prefix of every second unselected completion
  • fish_pager_color_secondary_completion β€” suffix of every second unselected completion
  • fish_pager_color_secondary_description β€” description of every second unselected completion

When the secondary or selected variables aren't set or are empty, the normal variables are used, except for $fish_pager_color_selected_background, where the background of $fish_color_search_match is tried first. That's the whole rule β€” no cap. ✨


✨ ABBREVIATIONS ✨

To avoid needless typing, a frequently-run command like git checkout can be abbreviated to gco using the abbr command. Obsessed.

abbr -a gco git checkout

After entering gco and pressing space or enter, a gco in command position will turn into git checkout in the command line. If you want to use a literal gco sometimes, use ctrl-space [1]. Iconic.

Abbreviations are a lot more powerful than just replacing literal strings. For example you can make going up a number of directories easier with this:

function multicd
    echo cd (string repeat -n (math (string length -- $argv[1]) - 1) ../)
end
abbr --add dotdot --regex '^\.\.+$' --function multicd

Now, .. transforms to cd ../, while ... turns into cd ../../ and .... expands to cd ../../../. The way that works? Literally magic. ✨

The advantage over aliases is that you can see the actual command before using it, add to it or change it, and the actual command will be stored in history.

[1] Any binding that executes the expand-abbr or execute bind function will expand abbreviations. By default ctrl-space is bound to just inserting a space.

πŸ’… PROGRAMMABLE PROMPT πŸ’…

When it is fish's turn to ask for input (like after it started or the command ended), it will show a prompt. Often this looks something like:

you@hostname ~>

This prompt is determined by running the fish_prompt and fish_right_prompt functions. Main character energy, honestly.

The output of the former is displayed on the left and the latter's output on the right side of the terminal. For vi mode, the output of fish_mode_prompt will be prepended on the left.

If fish_transient_prompt is set to 1, fish will redraw the prompt with a --final-rendering argument before running a commandline, allowing you to change it before pushing it to the scrollback.

fish ships with a few prompts which you can see with fish_config. If you run just fish_config it will open a web interface [2] where you'll be shown the prompts and can pick which one you want. fish_config prompt show will show you the prompts right in your terminal.

For example fish_config prompt choose disco will temporarily select the "disco" prompt. If you like it and decide to keep it, run fish_config prompt save.

You can also change these functions yourself by running funced fish_prompt and funcsave fish_prompt once you are happy with the result (or fish_right_prompt if you want to change that).

[2] The web interface runs purely locally on your computer and requires python to be installed.

πŸŽ€ CONFIGURABLE GREETING πŸŽ€

When it is started interactively, fish tries to run the fish_greeting function. The default fish_greeting prints a simple message. You can change its text by changing the $fish_greeting variable, for instance using a universal variable:

set -U fish_greeting

or you can set it globally in config.fish:

set -g fish_greeting 'Hey, stranger!'

or you can script it by changing the function:

function fish_greeting
    random choice "Hello!" "Hi" "G'day" "Howdy"
end

save this in config.fish or a function file. You can also use funced and funcsave to edit it easily. 🫢

🏷️ PROGRAMMABLE TITLE 🏷️

okay so most terminals let you set the text that shows up in the titlebar of the terminal window β€” and fish does that by running the fish_title function πŸ’– It gets executed before and after a command, and whatever it outputs is what becomes your titlebar message ✨

The status current-command builtin will always return the name of the job that's about to be put in the foreground (or fish if control is coming back to the shell) whenever fish_title is called. And the first argument? That's the most recently executed foreground command, as a string 🫢

Default title is lowkey iconic: it shows the hostname if you're connected via ssh, the currently running command (unless it's fish) and your current working directory. All of it gets shortened so your tab doesn't get dummy wide πŸ’…

Examples:

To show the last command and working directory in the title:

function fish_title
    # `prompt_pwd` shortens the title. This helps prevent tabs from becoming very wide.
    echo $argv[1] (prompt_pwd)
    pwd
end

πŸ’… COMMAND LINE EDITOR πŸ’…

The fish editor is giving main character energy fr β€” copy and paste, a searchable history, and a whole pile of editor functions you can bind to special keyboard shortcuts 🌸

Like bash and other shells, fish ships two sets of keyboard shortcuts (aka key bindings): one inspired by the Emacs text editor, and one inspired by the vi text editor. Default editing mode is Emacs πŸ‘‘ You can hop to vi mode by running fish_vi_key_bindings and hop back with fish_default_key_bindings. And you can absolutely make your own key bindings by creating a function and setting the fish_key_bindings variable to its name β€” like this:

function fish_hybrid_key_bindings --description \
"Vi-style bindings that inherit emacs-style bindings in all modes"
    for mode in default insert visual
        fish_default_key_bindings -M $mode
    end
    fish_vi_key_bindings --no-erase
end
set -g fish_key_bindings fish_hybrid_key_bindings

Real talk though: the key bindings that come with fish include many of the shortcuts that are popular from the respective text editors, but they are not a complete implementation 😌 They do include a shortcut to open the current command line in your preferred editor (alt-e by default) β€” so if you need the full power of your editor, that's your girl ✨

Shared bindings

Some bindings are common across Emacs and vi mode, because they're not text editing bindings, or because what vi/Vim does for a particular key just doesn't make sense for a shell πŸ’€

  • tab β€” completes the current token. shift-tab completes the current token and starts the pager's search mode. tab is the same as ctrl-i.
  • left (←) and right (β†’) β€” move the cursor left or right by one character. If the cursor is already at the end of the line and an autosuggestion is available, right (β†’) accepts the autosuggestion πŸ¦‹
  • enter β€” executes the current commandline, or inserts a newline if it's not complete yet (e.g. a ) or end is missing).
  • alt-enter β€” inserts a newline at the cursor position. Super useful for adding a line to a commandline that's already complete.
  • alt-left (←) and alt-right (β†’) β€” move the cursor left or right by one word. If the command line is empty, they move forward/backward in the directory history. If the cursor is already at the end of the line and an autosuggestion is available, alt-right (β†’) (or alt-f) accepts the first word in the suggestion.
  • ctrl-left (←) and ctrl-right (β†’) β€” move the cursor left or right by one token. These accept one token of the autosuggestion β€” the part they'd move over πŸ‘€
  • shift-left (←) and shift-right (β†’) β€” move the cursor one word left or right, without stopping on punctuation. These accept one big word of the autosuggestion.
  • up (↑) and down (↓) (or ctrl-p and ctrl-n for the emacs aficionados) β€” search the command history for the previous/next command containing the string that was specified on the commandline before the search started. If the commandline was empty when the search started, all commands match. See the history section for more on history searching πŸ’œ
  • alt-up (↑) and alt-down (↓) β€” search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline wasn't on a token when the search started, all tokens match. Again, see the history section for more on history searching.
  • ctrl-c β€” interrupts/kills whatever is running (SIGINT). the ultimate "nope" button 😭
  • ctrl-d β€” deletes one character to the right of the cursor. If the command line is empty, ctrl-d will exit fish.
  • ctrl-u β€” removes contents from the beginning of line to the cursor (moving it to the killring).
  • ctrl-l β€” pushes any text above the prompt to the terminal's scrollback, then clears and repaints the screen 🧚
  • ctrl-w β€” removes the previous path component (everything up to the previous "/", ":" or "@") (moving it to the Copy and paste (Kill Ring)).
  • ctrl-x β€” copies the current buffer to the system's clipboard; ctrl-v inserts the clipboard contents. (see fish_clipboard_copy and fish_clipboard_paste) πŸŽ€
  • alt-d β€” moves the next word to the Copy and paste (Kill Ring).
  • ctrl-delete β€” moves the next word (or next argument on macOS) to the Copy and paste (Kill Ring).
  • alt-d β€” lists the directory history if the command line is empty.
  • alt-delete β€” moves the next argument (or word on macOS) to the Copy and paste (Kill Ring).
  • shift-delete β€” removes the current history item or autosuggestion from the command history.
  • alt-h (or f1) β€” shows the manual page for the current command, if one exists πŸ“–
  • alt-l β€” lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory get listed.
  • alt-o β€” opens the file at the cursor in a pager. If the cursor is in command position and the command is a script, it'll instead open that script in your editor. The editor is chosen from the first available of the $VISUAL or $EDITOR variables.
  • alt-p β€” adds the string &| less; to the end of the job under the cursor. Result: the output of the command gets paged ✨ If you set the PAGER variable, its value is used instead of less.
  • alt-w β€” prints a short description of the command under the cursor.
  • alt-e β€” edits the current command line in an external editor. The editor is chosen from the first available of the $VISUAL or $EDITOR variables.
  • alt-v β€” same as alt-e.
  • alt-s β€” prepends sudo to the current commandline. If the commandline is empty, prepends sudo to the last commandline. If sudo isn't installed, various similar commands are tried: doas, please, and run0 πŸ‘‘
  • ctrl-space β€” inserts a space without expanding an abbreviation. For vi mode, this only applies to insert-mode.

Emacs mode commands

To enable emacs mode, use fish_default_key_bindings β€” which is also the default, cute πŸŽ€

  • home or ctrl-a β€” moves the cursor to the beginning of the line.
  • end or ctrl-e β€” moves to the end of line. If the cursor is already at the end of the line and an autosuggestion is available, end or ctrl-e accepts the autosuggestion.
  • ctrl-b, ctrl-f β€” move the cursor one character left or right, or accept the autosuggestion, just like the left (←) and right (β†’) shared bindings (which are available as well πŸ’–).
  • alt-b, alt-f β€” move the cursor one word left or right, or accept one word of the autosuggestion. If the command line is empty, moves forward/backward in the directory history instead.
  • ctrl-n, ctrl-p β€” move the cursor up/down or through history, like the up and down arrow shared bindings.
  • delete or backspace or ctrl-h β€” removes one character forwards or backwards respectively.
  • alt-backspace β€” removes one word backwards; ctrl-backspace removes one argument backwards.
  • alt-< β€” moves to the beginning of the commandline; alt-> moves to the end.
  • ctrl-k β€” deletes from the cursor to the end of line (moving it to the Copy and paste (Kill Ring)).
  • escape and ctrl-g β€” cancel the current operation. Immediately after an unambiguous completion, this undoes it.
  • alt-c β€” capitalizes the current word.
  • alt-u β€” makes the current word uppercase.
  • ctrl-t β€” transposes the last two characters.
  • alt-t β€” transposes the last two words.
  • ctrl-z, ctrl-_ (ctrl-/ on some terminals) β€” undo the most recent edit of the line πŸ™ˆ
  • alt-/ or ctrl-shift-z β€” reverts the most recent undo.
  • ctrl-r β€” opens the history in a pager. This shows history entries matching the search, a few at a time. Pressing ctrl-r again searches older entries; pressing ctrl-s (that otherwise toggles pager search) goes to newer entries. The search bar will always be selected ⭐

You can change these key bindings using the bind builtin πŸ’…

Vi mode commands

Vi mode lets you use vi-like commands right at the prompt πŸ¦‹ Initially, insert mode is active. escape enters command mode. The commands available in command, insert and visual mode are described below. Vi mode shares some bindings with Emacs mode.

To enable vi mode, use fish_vi_key_bindings. It's also possible to add all Emacs mode bindings to vi mode by using something like:

function fish_user_key_bindings
    # Execute this once per mode that emacs bindings should be used in
    fish_default_key_bindings -M insert

    # Then execute the vi-bindings so they take precedence when there's a conflict.
    # Without --no-erase fish_vi_key_bindings will default to
    # resetting all bindings.
    # The argument specifies the initial mode (insert, "default" or visual).
    fish_vi_key_bindings --no-erase insert
end

When in vi mode, the fish_mode_prompt function displays a mode indicator to the left of the prompt 🌈 To disable that feature, override it with an empty function. To display the mode somewhere else (like in your right prompt), use the output of the fish_default_mode_prompt function πŸ‘€

When a binding switches the mode, it will repaint the mode-prompt if it exists, and the rest of the prompt only if it doesn't. So if you want a mode-indicator in your fish_prompt, you need to erase fish_mode_prompt β€” e.g. by adding an empty file at ~/.config/fish/functions/fish_mode_prompt.fish. (Bindings that change the mode are supposed to call the repaint-mode bind function, see bind) πŸ’–

The fish_vi_cursor function will be used to change the cursor's shape depending on the mode in supported terminals. The following snippet can be used to manually configure cursors after enabling vi mode:

okay so here's the cursor-shape config they're showing you β€” this is the whole vibe πŸ’…

# Emulates vim's cursor shape behavior
# Set the normal and visual mode cursors to a block
set fish_cursor_default block
# Set the insert mode cursor to a line
set fish_cursor_insert line
# Set the replace mode cursors to an underscore
set fish_cursor_replace_one underscore
set fish_cursor_replace underscore
# Set the external cursor to a line. The external cursor appears when a command is started.
# The cursor shape takes the value of fish_cursor_default when fish_cursor_external is not specified.
set fish_cursor_external line
# The following variable can be used to configure cursor shape in
# visual mode, but due to fish_cursor_default, is redundant here
set fish_cursor_visual block

Additionally, you can tack blink onto each of those cursor-shape parameters to get a blinking cursor in that shape. fish knows the shapes "block", "line" and "underscore" β€” anything else just gets ignored, no drama. 🫢

If the cursor shape does not appear to be changing after setting the above variables, it's likely your terminal emulator does not support the capabilities necessary to do this. not fish being shady, just terminal limitations 😭


🧭 Command mode

Command mode is also known as normal mode, iykyk.

  • h β€” moves the cursor left.
  • l β€” moves the cursor right.
  • k and j β€” search the command history for the previous/next command containing the string that was specified on the commandline before the search was started. If the commandline was empty when the search started, all commands match. See the history section for more information on history searching. In multi-line commands, they move the cursor up and down respectively.
  • i β€” enters insert mode at the current cursor position.
  • I β€” enters insert mode at the beginning of the line.
  • v β€” enters visual mode at the current cursor position.
  • a β€” enters insert mode after the current cursor position.
  • A β€” enters insert mode at the end of the line.
  • o β€” inserts a new line under the current one and enters insert mode
  • O (capital-"o") β€” inserts a new line above the current one and enters insert mode
  • 0 (zero) β€” moves the cursor to beginning of line (remaining in command mode).
  • d,d β€” deletes the current line and moves it to the Copy and paste (Kill Ring).
  • D β€” deletes text after the current cursor position and moves it to the Copy and paste (Kill Ring).
  • p β€” pastes text from the Copy and paste (Kill Ring).
  • u β€” undoes the most recent edit of the command line.
  • ctrl-r β€” redoes the most recent edit.
  • [ and ] β€” search the command history for the previous/next token containing the token under the cursor before the search was started. See the history section for more information on history searching.
  • / β€” opens the history in a pager. This will show history entries matching the search, a few at a time. Pressing it again will search older entries, pressing ctrl-s (that otherwise toggles pager search) will go to newer entries. The search bar will always be selected.
  • backspace β€” moves the cursor left.
  • g,g / G β€” moves the cursor to the beginning/end of the commandline, respectively.
  • ~ β€” toggles the case (upper/lower) of the character and moves to the next character.
  • g,u β€” lowercases to the end of the word.
  • g,U β€” uppercases to the end of the word.
  • :,q β€” exits fish.

✨ Insert mode

  • escape β€” enters command mode.
  • backspace β€” removes one character to the left.
  • ctrl-n β€” accepts the autosuggestion.

🌈 Visual mode

  • left (←) and right (β†’) β€” extend the selection backward/forward by one character.
  • h β€” moves the cursor left.
  • l β€” moves the cursor right.
  • k β€” moves the cursor up.
  • j β€” moves the cursor down.
  • b and w β€” extend the selection backward/forward by one word.
  • d and x β€” move the selection to the Copy and paste (Kill Ring) and enter command mode.
  • escape and ctrl-c β€” enter command mode.
  • c and s β€” remove the selection and switch to insert mode.
  • X β€” moves the entire line to the Copy and paste (Kill Ring), and enters command mode.
  • y β€” copies the selection to the Copy and paste (Kill Ring), and enters command mode.
  • ~ β€” toggles the case (upper/lower) on the selection, and enters command mode.
  • g,u β€” lowercases the selection, and enters command mode.
  • g,U β€” uppercases the selection, and enters command mode.
  • ",*,y β€” copies the selection to the clipboard, and enters command mode.

πŸŽ€ Custom bindings

In addition to the standard bindings listed here, you can also define your own with the bind command:

# Prints ``^C`` and a new prompt
bind ctrl-c cancel-commandline

Put bind statements into config.fish or a function called fish_user_key_bindings.

If you change your mind on a binding and want to go back to fish's default, you can erase it again:

bind --erase ctrl-c

fish remembers its preset bindings and so it will take effect again. This saves you from having to remember what it was before and add it again yourself. convenient queen behavior πŸ‘‘

If you use vi bindings, note that bind will by default bind keys in command mode. To bind something in insert mode:

bind --mode insert ctrl-c 'commandline -r ""'

πŸ¦‹ Key sequences

To find out the name of a key, you can use fish_key_reader.

> fish_key_reader # Press Alt + right-arrow
Press a key:
bind alt-right 'do something'

Note that the historical way the terminal encodes keys and sends them to the application (fish, in this case) makes a lot of combinations indistinguishable or unbindable. In the usual encoding, ctrl-i is the same as the tab key, and shift cannot be detected when ctrl is also pressed. terminal lore, unfortunately πŸ’€

There are more powerful encoding schemes, and fish tries to tell the terminal to turn them on, but there are still many terminals that do not support them. When fish_key_reader prints the same sequence for two different keys, then that is because your terminal sends the same sequence for them, and there isn't anything fish can do about it. It is our hope that these schemes will become more widespread, making input more flexible.

In the historical scheme, escape is the same thing as alt in a terminal. To distinguish between pressing escape and then another key, and pressing alt and that key (or an escape sequence the key sends), fish waits for a certain time after seeing an escape character. This is configurable via the fish_escape_delay_ms variable.

If you want to be able to press escape and then a character and have it count as alt+that character, set it to a higher value, e.g.:

set -g fish_escape_delay_ms 100

Similarly, to disambiguate other keypresses where you've bound a subsequence and a longer sequence, fish has fish_sequence_key_delay_ms:

# This binds the sequence j,k to switch to normal mode in vi mode.
# If you kept it like that, every time you press "j",
# fish would wait for a "k" or other key to disambiguate
bind -M insert -m default j,k cancel repaint-mode

# After setting this, fish only waits 200ms for the "k",
# or decides to treat the "j" as a separate sequence, inserting it.
set -g fish_sequence_key_delay_ms 200

πŸ’– Copy and paste (Kill Ring)

fish uses an Emacs-style kill ring for copy and paste functionality. For example, use ctrl-k (kill-line) to cut from the current cursor position to the end of the line. The string that is cut (a.k.a. killed in emacs-ese) is inserted into a list of kills, called the kill ring. To paste the latest value from the kill ring (emacs calls this "yanking") use ctrl-y (the yank input function). After pasting, use alt-y (yank-pop) to rotate to the previous kill. emacs girlies stay winning 🌸

Copy and paste from outside are also supported, both via the ctrl-x / ctrl-v bindings (the fish_clipboard_copy and fish_clipboard_paste functions [3]) and via the terminal's paste function, for which fish enables "Bracketed Paste Mode", so it can tell a paste from manually entered text. In addition, when pasting inside single quotes, pasted single quotes and backslashes are automatically escaped so that the result can be used as a single token by closing the quote after. Kill ring entries are stored in fish_killring variable.

[3] These rely on external tools. Currently xsel, xclip, wl-copy/wl-paste and pbcopy/pbpaste are supported.

The commands begin-selection and end-selection (unbound by default; used for selection in vi visual mode) control text selection together with cursor movement commands that extend the current selection. The variable fish_cursor_selection_mode can be used to configure if that selection should include the character under the cursor (inclusive) or not (exclusive). The default is exclusive, which works well with any cursor shape. For vi mode, and particularly for the block or underscore cursor shapes you may prefer inclusive.

🧚 Multiline editing

The fish commandline editor can be used to work on commands that are several lines long. There are three ways to make a command span more than a single line:

  • Pressing the enter key while a block of commands is unclosed, such as when one or more block commands such as for, begin or if do not have a corresponding end command.
  • Pressing alt-enter instead of pressing the enter key.
  • By inserting a backslash (\) character before pressing the enter key, escaping the newline.

The fish commandline editor works exactly the same in single line mode and in multiline mode. To move between lines use the left and right arrow keys and other such keyboard shortcuts. multi-line main character energy ✨

⭐ Searchable command history

After a command has been executed, it is remembered in the history list. Any duplicate history items are automatically removed. By pressing the up and down keys, you can search forwards and backwards in the history. If the current command line is not empty when starting a history search, only the commands containing the string entered into the command line are shown.

By pressing alt-up (↑) and alt-down (↓), a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements like it would be before execution, and the history is searched for an element matching that under the cursor.

For more complicated searches, you can press ctrl-r to open a pager that allows you to search the history. It shows a limited number of entries in one page, press ctrl-r [4] again to move to the next page and ctrl-s [5] to move to the previous page. You can change the text to refine your search.

History searches are case-insensitive unless your search string has an uppercase character in it. And if you wanna bail mid-search and go edit what you're searching for? Just hit escape or pagedown and you're back in business πŸ’…

Okay bestie, this next one is genuinely iconic: if you start your commandline with a space, the whole line does not get stored in your history. It's still there for you to recall until the next command gets executed β€” but it never touches the disk. Literally made for when you typo'd something embarrassing and don't want it living in your history forever πŸ™ˆ

Your command history lives in ~/.local/share/fish/fish_history by default β€” or $XDG_DATA_HOME/fish/fish_history if that variable is set. But plot twist: you can set the fish_history environment variable to change the name of the history session (which gives you a <session>_history file). You can do this both before starting the shell and while the shell is running. Obsessed with the flexibility tbh ✨

For other history manipulations, go check out the history command, iykyk 🫢

Examples:

  • Wanna search for previous entries containing the word 'make'? Type make in the console and press the up key. Slay.
  • If your commandline reads cd m, put the cursor over the m character and press alt-up (↑) to search for previously typed words containing 'm'. Chef's kiss πŸŽ€
[4] Or another binding that triggers the history-pager input function. See bind for a full list. [5] Or another binding that triggers the pager-toggle-search input function.

πŸ•΅οΈβ€β™€οΈ PRIVATE MODE πŸ•΅οΈβ€β™€οΈ

fish has a private mode, and in this mode your command history is not written to the history file on disk. To turn it on, either set $fish_private_mode to a non-empty value, or launch with fish --private (short version: fish -P) πŸ’œ

If you launch fish with -P, it both hides your old history and prevents writing history to disk. This is lowkey essential for not leaking personal info (screencasts, bestie β€” think about the screencasts 😭) or when you're dealing with sensitive information.

And if you're writing your own fish scripts and wanna respect a user's wish for privacy? You can query the variable, like if test -n "$fish_private_mode" ..., and alter your script's behavior accordingly. Considerate king behavior fr fr πŸ‘‘


Usually you navigate directories with the cd command β€” classic, we love her β€” but fish also serves up some advanced features on top πŸ¦‹

Your current working directory can be shown with the pwd command, or with the $PWD special variable. Honestly your prompt probably already does this for you, but now you know ✨

πŸ“š Directory history πŸ“š

fish automatically keeps a trail of recently visited directories (via cd) by storing that history in the dirprev and dirnext variables. It's giving main character memory 🌸

Several commands exist to interact with this directory history:

  • dirh β€” prints the history πŸ“œ
  • cdh β€” displays a prompt so you can quickly navigate the history 🧚
  • prevd β€” moves backward through the history. Bound to alt-left (←)
  • nextd β€” moves forward through the history. Bound to alt-right (β†’)

πŸ₯ž Directory stack πŸ₯ž

Another set of commands β€” usually also available in other shells like bash β€” deals with the directory stack. Heads up though: stack handling is not automatic and needs explicit calls of the following commands:

  • dirs β€” prints the stack
  • pushd β€” adds a directory on top of the stack and makes it your current working directory
  • popd β€” removes the directory on top of the stack and changes your current working directory

πŸ‘‘ Author πŸ‘‘

fish-shell developers

fish-shell developers


πŸ’– And that's a wrap, bestie! This was FISH-INTERACTIVE(1), version 4.9, dated Sep 08, 2026, brought to you by the fish-shell developers. Go forth and have the prettiest, most autosuggested commandline of your life. Periodt. πŸ’…πŸŽ€πŸ¦‹
πŸ“¦ 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