<p>fish is a fully-equipped command line shell (like bash or zsh) that is smart and user-friendly. fish supports powerful features like syntax highlighting, autosuggestions, and tab completions that just work, with nothing to learn or configure.
<p>If you want to make your command line more productive, more useful, and more fun, without learning a bunch of arcane syntax and configuration options, then fish might be just what you're looking for!
<h2 id="tut_learning_Fish">Learning fish</h2>
<p>This tutorial assumes a basic understanding of command line shells and Unix commands, and that you have a working copy of fish.
<p>If you have a strong understanding of other shells, and want to know what fish does differently, search for the magic phrase <i>unlike other shells</i>, which is used to call out important differences.
<p>When you start fish, you should see this:
<pre>
Welcome to fish, the friendly interactive shell
Type <em>help</em> for instructions on how to use fish
you@hostname <em>~</em>>
</pre>
<p>fish comes with a default prompt that shows your username, hostname, and working directory. You'll see <a href="#tut_prompt">how to change your prompt</a> further down. From now on, we'll pretend your prompt is just a '>' to save space.
fish has excellent help and man pages. Run <tt>help</tt> to open help in a web browser, and <tt>man</tt> to open it in a man page. You can also ask for help with a specific command, for example, <tt>help set</tt> to open in a web browser, or <tt>man set</tt> to see it in the terminal.
You'll quickly notice that fish performs syntax highlighting as you type. Invalid commands are colored red by default:
<pre>
> <b class="error">/bin/mkd</b>
</pre>
A command may be invalid because it does not exist, or refers to a file that you cannot execute. When the command becomes valid, it is shown in a different color:
<pre>
> <b>/bin/mkdir</b>
</pre>
fish will underline valid file paths as you type them:
<p>Like other shells, a dollar sign performs <i>variable substitution</i>:
<pre>
> <b>echo</b> <i>My home directory is $HOME</i>
My home directory is /home/tutorial
</pre>
Variable substitution also occurs in double quotes, but not single quotes:
<pre>
> <b>echo</b> <i class="quote">"My current directory is </i><i>$</i><i class="quote">PWD"</i>
My current directory is /home/tutorial
> <b>echo</b> <i class="quote">'My current directory is $PWD'</i>
My current directory is $PWD
</pre>
Unlike other shells, fish has no dedicated syntax for setting variables. Instead it has an ordinary command: <tt>set</tt>, which takes a variable name, and then its value.
<p>(Notice the quotes: without them, <tt>Mister</tt> and <tt>Noodle</tt> would have been separate arguments, and <tt>$name</tt> would have been made into a <i>list</i> of two elements.)
<p>Unlike other shells, variables are <i>not</i> further split after substitution:
<pre>
> <b>mkdir</b> <i>$name</i>
> <b>ls</b>
Mister Noodle
</pre>
In bash, this would have created two directories "Mister" and "Noodle". In fish, it created only one: the variable had the value "Mister Noodle", so that is the argument that was passed to <span style="mono">mkdir</span>, spaces and all.
<h2 id="tut_exit_status">Exit Status</h2>
Unlike other shells, fish stores the exit status of the last command in <tt>$status</tt> instead of <tt>$?</tt>.
<pre>
> <b>false</b>
> <b>echo</b> <i>$status</i>
1
</pre>
Zero is considered success, and non-zero is failure.
Unlike other shells, fish does not have an export command. Instead, a variable is exported via an option to <tt>set</tt>, either <tt>--export</tt> or just <tt>-x</tt>.
<pre>
> <b>set</b> <i>-x MyVariable SomeValue</i>
> <b>env</b> | <b>grep</b> <i>MyVariable</i>
<span style="background: #A0A">MyVariable</span>=SomeValue
</pre>
You can erase a variable with <tt>-e</tt> or <tt>--erase</tt>
<pre>
> <b>set</b> <i>-e MyVariable</i>
> <b>env</b> | <b>grep</b> <i>MyVariable</i>
<span class="meta">(no output)</span>
</pre>
<h2 id="tut_lists">Lists</h2>
<p>The <tt>set</tt> command above used quotes to ensure that <tt>Mister Noodle</tt> was one argument. If it had been two arguments, then <tt>name</tt> would have been a <i>list</i> of length 2. In fact, all variables in fish are really lists, that can contain any number of values, or none at all.
<p>Some variables, like <tt>$PWD</tt>, only have one value. By convention, we talk about that variable's value, but we really mean its <i>first</i> (and only) value.
<p>Other variables, like <tt>$PATH</tt>, really do have multiple values. During <i>variable expansion</i>, the variable expands to become multiple arguments:
<pre>
> <b>echo</b> <i>$PATH</i>
/usr/bin /bin /usr/sbin /sbin /usr/local/bin
</pre>
<p>Lists cannot contain other lists: there is no recursion. A variable is a list of strings, full stop.
<p>Get the length of a list with <tt>count</tt>:
<pre>
> <b>count</b> <i>$PATH</i>
5
</pre>
You can append (or prepend) to a list by setting the list to itself, with some additional arguments. Here we append /usr/local/bin to $PATH:
<pre>
> <b>set</b> <i>PATH $PATH /usr/local/bin</i>
</pre>
You can access individual elements with square brackets. Indexing starts at 1 from the beginning, and -1 from the end:
<pre>
> <b>echo</b> <i>$PATH</i>
/usr/bin /bin /usr/sbin /sbin /usr/local/bin
> <b>echo</b> <i>$PATH[1]</i>
/usr/bin
> <b>echo</b> <i>$PATH[-1]</i>
/usr/local/bin
</pre>
You can also access ranges of elements, known as "slices:"
<pre>
> <b>echo</b> <i>$PATH[1..2]</i>
/usr/bin /bin
> <b>echo</b> <i>$PATH[-1..2]</i>
/usr/local/bin /sbin /usr/sbin /bin
</pre>
You can iterate over a list (or a slice) with a <i>for loop</i>:
Command substitutions use the output of one command as an argument to another. Unlike other shells, fish does not use backticks ` for command substitutions. Instead, it uses parentheses:
A common idiom is to capture the output of a command in a variable:
<pre>
> <b>set</b> <i>os (</i><b>uname</b><i>)</i>
> <b>echo</b> <i>$os</i>
Linux
</pre>
Command substitutions are not expanded within quotes. Instead, you can temporarily close the quotes, add the command substitution, and reopen them, all in the same argument:
Unlike other shells, fish does not have special syntax like && or || to combine commands. Instead it has commands <tt>and</tt>, <tt>or</tt>, and <tt>not</tt>.
Use <tt>if</tt>, <tt>else if</tt>, and <tt>else</tt> to conditionally execute code, based on the exit status of a command.
<pre>
<b>if grep</b> <i>fish /etc/shells</i>
<b>echo</b> <i>Found fish</i>
<b>else if grep</b> <i>bash /etc/shells</i>
<b>echo</b> <i>Found bash</i>
<b>else</b>
<b>echo</b> <i>Got nothing</i>
<b>end</b>
</pre>
There is also a <tt>switch</tt> command:
<pre>
<b>switch</b> <i>(</i><b>uname</b><i>)</i>
<b>case</b> <i>Linux</i>
<b>echo</b> <i>Hi Tux!</i>
<b>case</b> <i>Darwin</i>
<b>echo</b> <i>Hi Hexley!</i>
<b>case</b> <i>FreeBSD NetBSD DragonFly</i>
<b>echo</b> <i>Hi Beastie!</i>
<b>case</b> <i class="quote">'*'</i>
<b>echo</b> <i>Hi, stranger!</i>
<b>end</b>
</pre>
Note that <tt>case</tt> does not fall through, and can accept multiple arguments or (quoted) wildcards.
<h2 id="tut_functions">Functions</h2>
A fish function is a list of commands, which may optionally take arguments. Unlike other shells, arguments are not passed in "numbered variables" like <tt>$1</tt>, but instead in a single list <tt>$argv</tt>. To create a function, use the <tt>function</tt> builtin:
<pre>
> <i><b>function</b> say_hello
<b>echo</b> Hello $argv
<b>end</b></i>
> <b>say_hello</b>
Hello
> <b>say_hello <i>everybody!</i></b>
Hello everybody!
</pre>
<p>Unlike other shells, fish does not have aliases or special prompt syntax. Functions take their place.
<p>You can list the names of all functions with the <tt>functions</tt> keyword (note the plural!). fish starts out with a number of functions:
<p>You can see the source for any function by passing its name to <tt>functions</tt>:
<pre>
> <b>functions</b> <i>ls</i>
function ls --description 'List contents of directory'
command ls -G $argv
end
</pre>
<h2 id="tut_loops">Loops</h2>
While loops:
<pre>
> <b>while</b> <i>true</i>
<b>echo</b> <i class="quote">"Loop forever"</i>
<b>end</b>
Loop forever
Loop forever
Loop forever
...
</pre>
For loops can be used to iterate over a list. For example, a list of files:
<pre>
> <b>for</b> <i>file in *.txt</i>
<b>cp</b> <i>$file $file.bak</i>
<b>end</b>
</pre>
Iterating over a list of numbers can be done with `seq`:
<pre>
> <b>for</b> <i>x in (</i><b>seq</b> <i>5)</i>
<b>touch</b> <i>file_$x.txt</i>
<b>end</b>
</pre>
<h2 id="tut_prompt">Prompt</h2>
Unlike other shells, there is no prompt variable like PS1. To display your prompt, fish executes a function with the name <tt>fish_prompt</tt>, and its output is used as the prompt.
You can define your own prompt:
<pre>
> <b>function <i>fish_prompt</i>
echo <i>"New Prompt % "</i>
end</b>
New Prompt % <u> </u>
</b>
</pre>
Multiple lines are OK. Colors can be set via <tt>set_color</tt>, passing it named ANSI colors, or hex RGB values:
<p>You can choose among some sample prompts by running <tt>fish_config prompt</tt>. fish also supports RPROMPT through <tt>fish_right_prompt</tt>.
<h3>$PATH</h2>
<tt>$PATH</tt> is an environment variable containing the directories in which fish searches for commands. Instead of separating entries with a colon, $PATH is a list. You can modify $PATH in a few ways:
<p><ol>
<li>By modifying the <tt>$fish_user_paths</tt> variable, which is automatically appended to <tt>$PATH</tt>. For example, to permanently add /usr/local/bin to your <tt>$PATH</tt>, you could write:
<p>fish starts by executing commands in <tt>~/.config/fish/config.fish</tt>. You can create it if it does not exist.
<p>It is possible to directly create functions and variables in <tt>config.fish</tt> file, using the commands shown above. For example:
<p><pre>
> <b>cat</b> <i>~/.config/fish/config.fish</i>
set -x PATH $PATH /sbin/
function ll
ls -lh $argv
end
</pre>
<p>However, it is more common and efficient to use <i>autoloading functions</i> and <i>universal variables</i>.
<h3>Autoloading Functions</h2>
<p>When fish encounters a command, it attempts to <i>autoload</i> a function for that command, by looking for a file with the name of that command in <tt>~/.config/fish/functions/</tt>.
<p>For example, if you wanted to have a function <tt>ll</tt>, you would add a text file <tt>ll.fish</tt> to <tt>~/.config/fish/functions</tt>:
<p>See the documentation for <a href="commands.html#funced">funced</a> and <a href="commands.html#funcsave">funcsave</a> for ways to create these files automatically.
<p>A universal variable is a variable whose value is shared across all instances of fish, now and in the future - even after a reboot. You can make a variable universal with <tt>set -U</tt>:
<p>If you want to learn more about fish, there is <a href="index.html">lots of detailed documentation</a>, an <a href="https://lists.sourceforge.net/lists/listinfo/fish-users">official mailing list</a>, the IRC channel <tt>#fish</tt> on <tt>irc.oftc.net</tt>, and the <a href="http://github.com/fish-shell/fish-shell/">github page</a>.