We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Install and Use the Fish Shell on an Ubuntu VPS

Posted Apr 9, 2014 20.2k views System Tools Ubuntu


Linux and Unix-like operating systems are lucky enough to have quite a few alternatives to almost every component of their operating environment. One of the components that server users interact with the most is the command line shell.

While most systems ship with the bash shell, which stands for "Bourne again shell" after the creator of the original sh shell that was its predecessor, there are other options that many users would benefit from checking out. You may have heard of the popular zsh, which you can learn about here.

Another full-featured shell, which will be the subject of this guide, is the fish shell. The fish shell is a modern, attractive, and powerful command shell that can extend the capabilities of the usual bash shell. In this guide, we'll learn how to install, configure, and use this shell alternative.

We will be using these on an Ubuntu 12.04 VPS instance, but you should have an easy time adapting this to the distribution of your choice.

How to Install the Fish Shell

Fortunately for us, the default Ubuntu 12.04 repositories contain the fish binary packages.

We can install it in the conventional way by updating our local package index and pulling the package onto our system:

sudo apt-get update
sudo apt-get install fish

That is all we need to do to get the new shell onto our system.

To start playing around, we'll start a new fish shell from within our current session. We'll discuss later on how to change your default shell if you decide that fish is for you:


demouser@host ~>

You can see that your prompt changed. Instead of a "$" as a prompt for a normal user, you will see a ">" character.

Getting Acquainted with Some Superficial Features

Right away, we can begin to see some of the advantages of this shell by just going about our normal routines in the shell. These are mostly accomplished by included functions that we will look into later on.

For example, if you list the contents of a directory, you'll notice that they are automatically appended with a character at the end that indicates the type of file:


bin/   etc/         lib/         media/  proc/  sbin/     sys/  var/
boot/  home/        lib64/       mnt/    root/  selinux/  tmp/  vmlinuz@
dev/   initrd.img@  lost+found/  opt/    run/   srv/      usr/

This is the same output as ls -F, which classifies contents by type.

If you type in a file path, whether relative or absolute, you will see that the fish shell underlines directory paths to make it easier to interpret at a glance:

cd /home/demo

If your terminal has the ability to display colored output, you'll have noticed that your prompt is automatically colored as well. Furthermore, it is dynamically colored. If you type something that is not a valid command, it will show up as red.

This would be red:


However, when you add the final "o", turning it into a command, you'll see it instantly turn green. This provides you with useful feedback that can make it easy to spot typos early.

Utilize TAB Completion for an Easier Time

You may also notice that the TAB completion is excellent:

cd /    ## Hit the TAB key at this point

/bin/    (Directory)  /media/    (Directory)  /srv/  (Directory)
/boot/   (Directory)  /mnt/      (Directory)  /sys/  (Directory)
/dev/    (Directory)  /opt/      (Directory)  /tmp/  (Directory)
/etc/    (Directory)  /proc/     (Directory)  /usr/  (Directory)
/home/   (Directory)  /run/      (Directory)  /var/  (Directory)
/lib/    (Directory)  /sbin/     (Directory)  
/lib64/  (Directory)  /selinux/  (Directory)

As you can see, fish intelligently lists only the directories for the cd command, since these are the only values that make sense.

If we were to use a more generic command, we'd see all listings (and their type) instead:

touch /     ## Hit the TAB key at this point

/bin/                  (Directory)  /proc/               (Directory)
/boot/                 (Directory)  /root/               (Directory)
/dev/                  (Directory)  /run/                (Directory)
/etc/                  (Directory)  /sbin/               (Directory)
/home/                 (Directory)  /selinux/            (Directory)
/initrd.img  (Symbolic link, 15MB)  /srv/                (Directory)
/lib/                  (Directory)  /sys/                (Directory)
/lib64/                (Directory)  /tmp/                (Directory)
/lost+found/           (Directory)  /usr/                (Directory)
/media/                (Directory)  /var/                (Directory)
/mnt/                  (Directory)  /vmlinuz  (Symbolic link, 5.2MB)
/opt/                  (Directory)  

A similar feature that is helpful is the formatting of the man command. If we want to see all of the fish man pages, we can use tab completion:

man fish    ## Hit the TAB key at this point

fish       (1: the friendly interactive shell)
fish_indent       (1: indenter and prettifier)
fish_pager  (1: internal command used by fish)
fishd           (1: universal variable daemon)

In a similar vein, you can get full-featured help using whatever terminal web browser you have using the built-in help system:


fish home | Main documentation page | Design document | Commands | FAQ |

Fish user documentation


Table of contents

  • Fish user documentation
      □ Table of contents
      □ Introduction
      □ Syntax overview
      □ Help
      □ Tab completion

On my machine, this opened the help system in the w3m terminal web browser. You can follow any links like you would in a normal browser, and can quit by typing "q". If you want to see the help for a specific command that fish knows about, just use it as an argument afterwards:

help cd

cd - change directory



Description Changes the current

directory. If DIRECTORY is supplied it will become the new directory. If
DIRECTORY is a relative path, the paths found in the CDPATH environment
variable array will be tried as prefixes for the specified path. If
CDPATH is not set, it is assumed to be '.'. If DIRECTORY is not
specified, $HOME will be the new directory.

Back to index.

Again, you can see what help commands are available by using TAB completion:

help    ## Type a space to let fish know you are finished with the command, and then hit the TAB key at this point

alias                                   (Help for the specified command)
and                                     (Help for the specified command)
begin                                   (Help for the specified command)
bg                                      (Help for the specified command)
bind                                    (Help for the specified command)
block                                   (Help for the specified command)
break                                   (Help for the specified command)
breakpoint                              (Help for the specified command)
. . .    

A Different Way of Doing Some Common Tasks

Many people who have used bash and even sh for years will have grown accustomed to the way that these shells do things. While fish does carry on much of the legacy of these shells, it modifies behavior where it can provide improvements.

Redirection, Piping, and Wildcards

One easy example of this is with redirection. Normal redirection and pipes work the same as with bash:

  • |: Pipe output of command on the left to the input of command on the right
  • <: Takes standard input from the file on the right instead of the keyboard
  • >: Writes standard output to the file on the right instead of the screen

However, one difference is the way that you redirect standard error. You do this with the carat character:

  • ^: Redirect standard error to the location on the right.

This provides an easy way to redirect one file descriptor to another. Recall that each file descriptor is usually associated with a number:

  • 0: Standard input. The input of your command is the keyboard by default.
  • 1: Standard output. The output of your command is the screen by default.
  • 2: Standard error. The errors of your command are printed to the screen by default.

We can redirect one file descriptor to another by using the "&" character followed by the descriptor number.

For instance, we can redirect a command's standard output into a file and then point its standard error to our standard output file as well by typing something like this:

ls /etc >ls_results.txt ^&1

All of the standard output is put into the ls_results.txt file and then the standard error is set to the location that the standard output is being directed (the file above).

As for wildcards, fish again uses most of the defaults from bash. These are included:

  • *: Match any character string that does not include "/".
  • ?: This matches any single character, not including "/".

The one additional wildcard that is extremely helpful is the recursive wildcard:

  • **: Match any string including "/".

This can be used to easily add recursive functionality to commands. Even though ls has a recursive option, we can do this with fish. We could find all files that end in .conf in our /etc directory by typing:

ls /etc/**.conf

. . .

On my machine, the first two lines of output show this in action. One file is in the top directory that we were searching and the next is in a subdirectory.

Creating Functions and Aliases

We can create functions and aliases in fish with an easy to use syntax.

The basic format is something like:

function function_name

If you wish to parse arguments within your function, you have them available all bundled together within the $argv variable. They are stored as an array.

For instance, we can make a function like this that will print out all of our arguments:

function say_hello
    echo hello $argv

We could call this with one or more arguments and it'll pass them all to the echo command:

say_hello John Doe

hello John Doe

If we want to access a specific variable, pull it out of the argument array by reference number (in fish, arrays start at 1, not 0). We could modify our previous script to use only the 2nd argument:

function hello_sir
    echo hello Mr. $argv[2]

We could then call this function and we'd get a different result:

hello_sir John Doe

hello Mr. Doe

We can see all of the defined functions by typing:

functions -a

You can delete one of your functions by typing:

functions -e function_name

For aliases, the bash shell has a specific command. In fish, it uses the same function syntax.

The only thing to be aware of is that if the command supersedes or replaces the command it is referencing, you must add the command builtin to tell the shell not to recursively call the function, but use the exterior command.

For instance, if we want the cat command to include numbering by default, we might want to redefine the command to include that flag. Remember to pass the argument variable so that it can parse the filenames correctly:

function cat
    command cat -n $argv

Now, when we call cat, the output will be automatically numbered:

cat /etc/hosts

     1   localhost fish fish
     3  # The following lines are desirable for IPv6 capable hosts
     4  ::1     ip6-localhost ip6-loopback
     5  fe00::0 ip6-localnet
     6  ff00::0 ip6-mcastprefix
     7  ff02::1 ip6-allnodes
     8  ff02::2 ip6-allrouters

If you are using a function to override the defaults of a command, you can also use the command builtin to bypass any modifications you have made and get the original command.

command cat /etc/hosts   localhost fish fish

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Simplified History

While bash provides a very complex, but useful set of history functions, fish pares these down and works on improving the basics to address usage issues.

You can move up chronologically in your history by using the UP key. You can move in the reverse direction by using the DOWN key. This is fairly standard.

If we wish to return to our prompt, we just hit the escape key.

We can also type in part of a previous command and then press the UP key to search for the latest instances of that specific command.

Furthermore, we can use the ALT-UP and ALT-DOWN commands to recall the command line arguments only.

For instance, let's say we listed the contents of a directory:

ls /etc

acpi/                   groff/               ltrace.conf              rmt*
adduser.conf            group                magic                    rpc
alternatives/           group-               magic.mime               rsyslog.conf
apm/                    grub.d/              mailcap                  rsyslog.d/
apparmor/               gshadow              mailcap.order            screenrc
. . .    

We realize that this is the directory we are looking for and we want to switch to it now. We can start by entering the new command:

cd      # Don't press return yet

Now, we can insert in the arguments from the last command by hitting the ALT-UP keys:

cd      # Hit Alt-UP and get...

cd /etc

This is a very simple example, but you can see how this could potentially be incredibly useful, especially since you can scroll through previous command arguments.

Another kind of history that fish provides is directory history. This is a great feature that allows you to basically move back through your cd history to get to previous directories.

You can see your directory history by typing:


You can move backwards and forwards in your directory history by pressing ALT-LEFT and ALT-RIGHT when at an empty command prompt. This will allow you to easily cycle between directories.

Creating your Configuration Files and Changing your Default Shell

If you find that you enjoy the fish shell, you'll probably want to include some customizations to shape your environment.

While you might be used to putting customizations in your ~/.bashrc or ~/.bash_profile files, these are not used for this shell.

To configure your preferences, you should create a file at ~/.config/fish/config.fish. All fish configuration files must end in .fish. Usually, the ~/.config/fish/ path will be created when you use the shell for the first time.

If you would like to start with an example file, you can copy it from the fish package directory:

cp /usr/share/fish/config.fish ~/.config/fish

You can then edit it like any other file:

nano ~/.config/fish/config.fish

When you get acquainted with the file, you should probably remove anything that you have not customized personally.

It is best not to add functions directly into this configuration file. Instead, you should create a directory called functions within your fish configuration directory:

mkdir ~/.config/fish/functions

Inside of this directory, create files for each of the functions you wish to make. As long as each file ends with .fish, the shell will find them and incorporate them into its environment. Each function must be in its own file with nothing else.

For instance, we could create a file to make our hello_sir function available in every session for our user, we could type this (before continuing, remember to unset the cat alias we made earlier with set -e cat if you haven't done so already):

cat > ~/.config/fish/functions/hello_sir.fish
function hello_sir
    echo hello Mr. $argv[2]

After typing end, hit CTRL-D to end the input. This will now be available every time the shell is loaded. If we wanted to also add our say_hello function, we'd need a separate file.

If you need some inspiration, you can take a look at the default fish functions:

cd /usr/share/fish/functions

After you've gotten your shell configured to your liking, you may wish to use fish as your default shell. To do this, you can use the chsh command.

First, we need to know the path to the fish shell:

which fish


Next, we can change our shell by typing:

chsh -s /usr/bin/fish

You will be asked for your password to confirm. Once this is complete, every time you login, you will be given a fish prompt.

If you want to change back to your other shell, you can specify it by path in the same way:

chsh -s /bin/bash


By now, you should be relatively familiar with the basics of using the fish shell. It is a good middle ground for many people, because it sticks to convention where it makes sense, but adds functionality where previous shells left room for improvement.

There are definitely more things to learn, but you should have a good foundation for further exploration. Remember to utilize the excellent help system that is available through the help command.

By Justin Ellingwood


Creative Commons License