Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
FISH-TUTORIAL(1)		  fish-shell		      FISH-TUTORIAL(1)

       fish-tutorial - fish-shell tutorial

       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.

       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!

       Once installed, just type in fish into your current  shell  to  try  it

       You  will  be  greeted by the standard fish prompt, which means you are
       all set up and can start	using fish:

	  > fish
	  Welcome to fish, the friendly	interactive shell
	  Type help for	instructions on	how to use fish
	  you@hostname ~>

       This prompt that	you see	above is the fish  default  prompt:  it	 shows
       your  username,	hostname,  and	working	 directory.   -	to change this
       prompt see how to change	your prompt - to switch	 to  fish  permanently
       see switch your default shell to	fish.

       From now	on, we'll pretend your prompt is just a	> to save space.

       This  tutorial assumes a	basic understanding of command line shells and
       Unix commands, and that you have	a working copy of fish.

       If you have a strong understanding of other shells, and	want  to  know
       what  fish  does	 differently, search for the magic phrase unlike other
       shells, which is	used to	call out important differences.

       Or, if you want a quick overview	over the differences to	 other	shells
       like Bash, see Fish For Bash Users.

       Fish  runs  commands like other shells: you type	a command, followed by
       its arguments. Spaces are separators:

	  > echo hello world
	  hello	world

       This runs the command echo with the arguments hello and world. In  this
       case  that's  the  same	as one argument	hello world, but in many cases
       it's not. If you	need to	pass an	argument that includes	a  space,  you
       can escape with a backslash, or quote it	using single or	double quotes:

	  > mkdir My\ Files
	  # Makes a directory called "My Files", with a	space in the name
	  > cp ~/Some\ File 'My	Files'
	  # Copies a file called "Some File" in	the home directory to "My Files"
	  > ls "My Files"
	  Some File

       Run  help  to  open fish's help in a web	browser, and man with the page
       (like fish-language) to open it in a man	page. You  can	also  ask  for
       help  with  a  specific command,	for example, help set to open in a web
       browser,	or man set to see it in	the terminal.

	  > man	set
	  set -	handle shell variables

       You'll quickly notice that fish performs	 syntax	 highlighting  as  you
       type. Invalid commands are colored red by default:

	  > /bin/mkd

       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:

	  > /bin/mkdir

       Valid file paths	are underlined as you type them:

	  > cat	~/somefi

       This  tells you that there exists a file	that starts with somefi, which
       is useful feedback as you type.

       These colors, and many more, can	be changed by running fish_config,  or
       by modifying color variables directly.

       Fish supports the familiar wildcard *. To list all JPEG files:

	  > ls *.jpg
	  santa	maria.jpg

       You can include multiple	wildcards:

	  > ls l*.p*

       Especially  powerful is the recursive wildcard ** which searches	direc-
       tories recursively:

	  > ls /var/**.log

       If that directory traversal is taking a long time,  you	can  Control+C
       out of it.

       For more, see Wildcards.

       You can pipe between commands with the usual vertical bar:

	  > echo hello world | wc
		1	2      12

       stdin  and stdout can be	redirected via the familiar < and >. stderr is
       redirected with a 2>.

	  > grep fish <	/etc/shells > ~/output.txt 2> ~/errors.txt

       To redirect stdout and stderr into one file, you	need to	first redirect
       stdout, and then	stderr into stdout:

	  > make > make_output.txt 2>&1

       For more, see Input and output redirections and Pipes.

       As  you	type fish will suggest commands	to the right of	the cursor, in
       gray. For example:

	  > /bin/hostname

       It knows	about paths and	options:

	  > grep --ignore-case

       And history too.	Type a command once, and you can re-summon it by  just
       typing a	few letters:

	  > rsync -avze	ssh .

       To  accept the autosuggestion, hit ^a (right arrow) or Control+F.	To ac-
       cept a single word of the autosuggestion, Alt+^a (right arrow).  If  the
       autosuggestion is not what you want, just ignore	it.

       A rich set of tab completions work "out of the box".

       Press  Tab  and fish will attempt to complete the command, argument, or

	  > /priTab => /private/

       If there's more than one	possibility, it	will list them:

	  > ~/stuff/sTab
	  ~/stuff/  (Executable, 4.8kB)  ~/stuff/sources/  (Directory)

       Hit tab again to	cycle through the possibilities.

       fish can	also complete many commands, like git branches:

	  > git	merge prTab => git merge prompt_designer
	  > git	checkout bTab
	  builtin_list_io_merge	(Branch) builtin_set_color (Branch) busted_events (Tag)

       Try hitting tab and see what fish can do!

       Like other shells, a dollar sign	followed by a  variable	 name  is  re-
       placed with the value of	that variable:

	  > echo My home directory is $HOME
	  My home directory is /home/tutorial

       This  is	 known as variable substitution, and it	also happens in	double
       quotes, but not single quotes:

	  > echo "My current directory is $PWD"
	  My current directory is /home/tutorial
	  > echo 'My current directory is $PWD'
	  My current directory is $PWD

       Unlike other shells, fish has no	dedicated  VARIABLE=VALUE  syntax  for
       setting variables. Instead it has an ordinary command: set, which takes
       a variable name,	and then its value.

	  > set	name 'Mister Noodle'
	  > echo $name
	  Mister Noodle

       (Notice the quotes: without them, Mister	and  Noodle  would  have  been
       separate	 arguments,  and $name would have been made into a list	of two

       Unlike other shells, variables are not further  split  after  substitu-

	  > mkdir $name
	  > ls
	  Mister Noodle

       In bash,	this would have	created	two directories	"Mister" and "Noodle".
       In fish,	it created only	one: the variable had the value	 "Mister  Noo-
       dle", so	that is	the argument that was passed to	mkdir, spaces and all.
       Other shells use	the term "arrays", rather than lists.

       You can erase (or "delete") a variable with -e or --erase

	  > set	-e MyVariable
	  > env	| grep MyVariable
	  (no output)

       For more, see Variable expansion.

       Sometimes you need to have a variable available to an external command,
       often  as a setting. For	example	many programs like git or man read the
       $PAGER variable to figure out your preferred pager  (the	 program  that
       lets you	scroll text). Other variables used like	this include $BROWSER,
       $LANG (to configure your	language) and $PATH.  You'll  note  these  are
       written in ALLCAPS, but that's just a convention.

       To  give	 a variable to an external command, it needs to	be "exported".
       Unlike other shells, fish does not have an export command.  Instead,  a
       variable	is exported via	an option to set, either --export or just -x.

	  > set	-x MyVariable SomeValue
	  > env	| grep MyVariable

       It can also be unexported with --unexport or -u.

       This  works  the	 other way around as well! If fish is started by some-
       thing else, it inherits that parents exported  variables.  So  if  your
       terminal	emulator starts	fish, and it exports $LANG set to en_US.UTF-8,
       fish will receive that setting. And whatever started your terminal emu-
       lator  also  gave it some variables that	it will	then pass on unless it
       specifically decides not	to. This is how	fish usually receives the val-
       ues for things like $LANG, $PATH	and $TERM, without you having to spec-
       ify them	again.

       Exported	variables can be local or global or universal -	"exported"  is
       not  a  scope!  Usually	you'd  make them global	via set	-gx MyVariable

       For more, see Exporting variables.

       The set command above used quotes to ensure that	Mister Noodle was  one
       argument.  If  it  had  been two	arguments, then	name would have	been a
       list of length 2.  In fact, all variables in  fish  are	really	lists,
       that can	contain	any number of values, or none at all.

       Some  variables,	like $PWD, only	have one value.	By convention, we talk
       about that variable's value, but	we really mean its  first  (and	 only)

       Other  variables,  like	$PATH,	really do have multiple	values.	During
       variable	expansion, the variable	expands	to become multiple arguments:

	  > echo $PATH
	  /usr/bin /bin	/usr/sbin /sbin	/usr/local/bin

       Variables whose name ends in "PATH" are automatically split  on	colons
       to  become lists. They are joined using colons when exported to subcom-
       mands. This is for compatibility	with other tools, which	 expect	 $PATH
       to  use	colons.	 You  can also explicitly add this quirk to a variable
       with set	--path,	or remove it with set --unpath.

       Lists cannot contain other lists: there is no recursion.	 A variable is
       a list of strings, full stop.

       Get the length of a list	with count:

	  > count $PATH

       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:

	  > set	PATH $PATH /usr/local/bin

       You can access  individual  elements  with  square  brackets.  Indexing
       starts at 1 from	the beginning, and -1 from the end:

	  > echo $PATH
	  /usr/bin /bin	/usr/sbin /sbin	/usr/local/bin
	  > echo $PATH[1]
	  > echo $PATH[-1]

       You can also access ranges of elements, known as	"slices":

	  > echo $PATH[1..2]
	  /usr/bin /bin
	  > echo $PATH[-1..2]
	  /usr/local/bin /sbin /usr/sbin /bin

       You can iterate over a list (or a slice)	with a for loop:

	  > for	val in $PATH
	      echo "entry: $val"
	  entry: /usr/bin/
	  entry: /bin
	  entry: /usr/sbin
	  entry: /sbin
	  entry: /usr/local/bin

       Lists  adjacent	to  other  lists  or strings are expanded as cartesian
       products	unless quoted (see Variable expansion):

	  > set	a 1 2 3
	  > set	1 a b c
	  > echo $a$1
	  1a 2a	3a 1b 2b 3b 1c 2c 3c
	  > echo $a" banana"
	  1 banana 2 banana 3 banana
	  > echo "$a banana"
	  1 2 3	banana

       This is similar to Brace	expansion.

       For more, see Lists.

       Command substitutions use the output of one command as an  argument  to
       another.	 Unlike	 other shells, fish does not use backticks `` for com-
       mand substitutions. Instead, it uses parentheses:

	  > echo In (pwd), running (uname)
	  In /home/tutorial, running FreeBSD

       A common	idiom is to capture the	output of a command in a variable:

	  > set	os (uname)
	  > echo $os

       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:

	  > touch "testing_"(date +%s)".txt"
	  > ls *.txt

       Unlike other shells, fish does not split	command	substitutions  on  any
       whitespace  (like  spaces or tabs), only	newlines. This can be an issue
       with commands like pkg-config that print	what is	meant to  be  multiple
       arguments  on  a	 single	 line.	To  split it on	spaces too, use	string

	  > printf '%s\n' (pkg-config --libs gio-2.0)
	  -lgio-2.0 -lgobject-2.0 -lglib-2.0
	  > printf '%s\n' (pkg-config --libs gio-2.0 | string split -n " ")

       If you need a command substitutions output as one argument, without any
       splits, use string collect:

	  > echo "first	line
	  second line" > myfile
	  > set	myfile (cat myfile | string collect)
	  > printf '|%s|' $myfile
	  |first line
	  second line|

       For more, see Command substitution.

       Like  other  shells,  fish  allows multiple commands either on separate
       lines or	the same line.

       To write	them on	the same line, use the semicolon (";").	That means the
       following two examples are equivalent:

	  echo fish; echo chips

	  # or
	  echo fish
	  echo chips

       When  a command exits, it returns a status code as a non-negative inte-

       Unlike other shells, fish stores	the exit status	of the last command in
       $status instead of $?.

	  > false
	  > echo $status

       This  indicates	how the	command	fared -	0 usually means	success, while
       the others signify kinds	of failure. For	instance  fish's  set  --query
       returns	the  number  of	 variables  it	queried	that weren't set - set
       --query PATH usually returns 0, set --query arglbargl boogagoogoo  usu-
       ally returns 2.

       There  is also a	$pipestatus list variable for the exit statuses	[1] of
       processes in a pipe.

       For more, see The status	variable.

       [1]  or "stati" if you prefer, or "statA<<s" if	you've	time-travelled
	    from ancient Rome or work as a latin teacher

       fish  supports  the  familiar  &&  and || to combine commands, and ! to
       negate them:

	  > ./configure	&& make	&& sudo	make install

       Here, make is only executed if ./configure succeeds  (returns  0),  and
       sudo  make  install  is only executed if	both ./configure and make suc-

       fish also supports and, or, and not. The	first two  are	job  modifiers
       and have	lower precedence. Example usage:

	  > cp file1 file1_bak && cp file2 file2_bak; and echo "Backup successful"; or echo "Backup failed"
	  Backup failed

       As  mentioned in	the section on the semicolon, this can also be written
       in multiple lines, like so:

	  cp file1 file1_bak &&	cp file2 file2_bak
	  and echo "Backup successful"
	  or echo "Backup failed"

       Use if and else to conditionally	execute	code, based on the exit	status
       of a command.

	  if grep fish /etc/shells
	      echo Found fish
	  else if grep bash /etc/shells
	      echo Found bash
	      echo Got nothing

       To  compare strings or numbers or check file properties (whether	a file
       exists or is writeable and such), use test, like

	  if test "$fish" = "flounder"
	      echo FLOUNDER

	  # or

	  if test "$number" -gt	5
	      echo $number is greater than five
	      echo $number is five or less

	  # or

	  # This test is true if the path /etc/hosts exists
	  # - it could be a file or directory or symlink (or possibly something	else).
	  if test -e /etc/hosts
	      echo We most likely have a hosts file
	      echo We do not have a hosts file

       Combiners can also be used to make more complex conditions, like

	  if grep fish /etc/shells; and	command	-sq fish
	      echo fish	is installed and configured

       For even	more complex conditions, use begin and end to group  parts  of

       There is	also a switch command:

	  switch (uname)
	  case Linux
	      echo Hi Tux!
	  case Darwin
	      echo Hi Hexley!
	  case FreeBSD NetBSD DragonFly
	      echo Hi Beastie!
	  case '*'
	      echo Hi, stranger!

       As  you	see, case does not fall	through, and can accept	multiple argu-
       ments or	(quoted) wildcards.

       For more, see Conditions.

       A fish function is a list of commands, which may	optionally take	 argu-
       ments. Unlike other shells, arguments are not passed in "numbered vari-
       ables" like $1, but instead in a	single list $argv. To create  a	 func-
       tion, use the function builtin:

	  > function say_hello
	       echo Hello $argv
	  > say_hello
	  > say_hello everybody!
	  Hello	everybody!

       Unlike  other shells, fish does not have	aliases	or special prompt syn-
       tax. Functions take their place.	[2]

       You can list the	names of all  functions	 with  the  functions  builtin
       (note the plural!). fish	starts out with	a number of functions:

	  > functions
	  N_, abbr, alias, bg, cd, cdh,	contains_seq, delete-or-exit, dirh, dirs, disown, down-or-search, edit_command_buffer, export, fg, fish_add_path, fish_breakpoint_prompt, fish_clipboard_copy, fish_clipboard_paste, fish_config, fish_default_key_bindings, fish_default_mode_prompt, fish_git_prompt,	fish_hg_prompt,	fish_hybrid_key_bindings, fish_indent, fish_is_root_user, fish_job_summary, fish_key_reader, fish_md5, fish_mode_prompt, fish_npm_helper, fish_opt, fish_print_git_action, fish_print_hg_root, fish_prompt, fish_sigtrap_handler, fish_svn_prompt, fish_title, fish_update_completions,	fish_vcs_prompt, fish_vi_cursor, fish_vi_key_bindings, funced, funcsave, grep, help, history, hostname,	isatty,	kill, la, ll, ls, man, nextd, nextd-or-forward-word, open, popd, prevd,	prevd-or-backward-word,	prompt_hostname, prompt_pwd, psub, pushd, realpath, seq, setenv, suspend, trap,	type, umask, up-or-search, vared, wait

       You  can	 see  the source for any function by passing its name to func-

	  > functions ls
	  function ls --description 'List contents of directory'
	      command ls -G $argv

       For more, see Functions.

       [2]  There is a function	called alias, but it's just a shortcut to make

       While loops:

	  > while true
	      echo "Loop forever"
	  Loop forever
	  Loop forever
	  Loop forever
	  ... #	yes, this really will loop forever. Unless you abort it	with ctrl-c.

       For  loops  can	be used	to iterate over	a list.	For example, a list of

	  > for	file in	*.txt
	      cp $file $file.bak

       Iterating over a	list of	numbers	can be done with seq:

	  > for	x in (seq 5)
	      touch file_$x.txt

       For more, see Loops and blocks.

       Unlike other shells, there is no	prompt variable	like PS1.  To  display
       your prompt, fish executes the fish_prompt function and uses its	output
       as  the	prompt.	 And  if   it	exists,	  fish	 also	executes   the
       fish_right_prompt function and uses its output as the right prompt.

       You can define your own prompt from the command line:

	  > function fish_prompt; echo "New Prompt % ";	end
	  New Prompt % _

       Then, if	you are	happy with it, you can save it to disk by typing func-
       save  fish_prompt.  This	 saves	the  prompt  in	  ~/.config/fish/func-
       tions/ (Or, if you want, you can create	that file man-
       ually from the start.)

       Multiple	lines are OK. Colors can be  set  via  set_color,  passing  it
       named ANSI colors, or hex RGB values:

	  function fish_prompt
	      set_color	purple
	      date "+%m/%d/%y"
	      set_color	F00
	      echo (pwd) '>' (set_color	normal)

       This prompt would look like:

	  /home/tutorial > _

       You  can	 choose	among some sample prompts by running fish_config for a
       web UI or fish_config prompt for	a simpler version inside  your	termi-

       $PATH  is  an environment variable containing the directories that fish
       searches	for commands. Unlike other shells, $PATH  is  a	 list,	not  a
       colon-delimited string.

       Fish takes care to set $PATH to a default, but typically	it is just in-
       herited from fish's parent process and is set to	 a  value  that	 makes
       sense for the system - see Exports.

       To prepend /usr/local/bin and /usr/sbin to $PATH, you can write:

	  > set	PATH /usr/local/bin /usr/sbin $PATH

       To remove /usr/local/bin	from $PATH, you	can write:

	  > set	PATH (string match -v /usr/local/bin $PATH)

       For  compatibility  with	other shells and external commands, $PATH is a
       path variable, and so will be joined with colons	(not spaces) when  you
       quote it:

	  > echo "$PATH"

       and  it	will be	exported like that, and	when fish starts it splits the
       $PATH it	receives into a	list on	colon.

       You can do so directly in,  like  you  might	 do  in	 other
       shells with .profile. See this example.

       A faster	way is to use the fish_add_path	function, which	adds given di-
       rectories to the	path if	they aren't already included. It does this  by
       modifying  the  $fish_user_paths	universal variable, which is automati-
       cally prepended to $PATH. For  example,	to  permanently	 add  /usr/lo-
       cal/bin to your $PATH, you could	write:

	  > fish_add_path /usr/local/bin

       The  advantage  is  that	 you don't have	to go mucking around in	files:
       just run	this once at the command line, and it will affect the  current
       session	and  all  future  instances too. You can also add this line to, as it only adds the	component if necessary.

       Or you can modify $fish_user_paths yourself, but	you should be  careful
       not  to	append	to  it unconditionally in, or it will grow
       longer and longer.

       Fish starts by executing	commands  in  ~/.config/fish/  You
       can create it if	it does	not exist.

       It  is  possible	 to  directly  create  functions and variables in con-	file, using the	commands shown above. For example:

	  > cat	~/.config/fish/

	  set -x PATH $PATH /sbin/

	  function ll
	      ls -lh $argv

       However,	it is more common and efficient	to use	autoloading  functions
       and universal variables.

       If you want to organize your configuration, fish	also reads commands in
       .fish files in ~/.config/fish/conf.d/. See Configuration	Files for  the

       When  fish encounters a command,	it attempts to autoload	a function for
       that command, by	looking	for a file with	the name of  that  command  in

       For  example, if	you wanted to have a function ll, you would add	a text
       file to ~/.config/fish/functions:

	  > cat	~/.config/fish/functions/
	  function ll
	      ls -lh $argv

       This is the preferred way to define your	prompt as well:

	  > cat	~/.config/fish/functions/
	  function fish_prompt
	      echo (pwd) "> "

       See the documentation for funced	and funcsave for ways to create	 these
       files automatically, and	$fish_function_path to control their location.

       A universal variable is a variable whose	value is shared	across all in-
       stances of fish,	now and	in the future a	even after a reboot.  You  can
       make a variable universal with set -U:

	  > set	-U EDITOR vim

       Now in another shell:

	  > echo $EDITOR

       If you wish to use fish (or any other shell) as your default shell, you
       need to enter your new shell's executable in two	places.

       Add the shell to	/etc/shells with:

	  > echo /usr/local/bin/fish | sudo tee	-a /etc/shells

       Change your default shell with:

	  > chsh -s /usr/local/bin/fish

       This assumes you	installed fish to /usr/local/bin, which	is the default
       location	 when  you've compiled it yourself. If you installed it	with a
       package manager,	the usual location is /usr/bin/fish, but package  man-
       agers typically already add it to /etc/shells. Just substitute the cor-
       rect location.

       (To  change  it	back  to  another  shell,  just	 substitute   /usr/lo-
       cal/bin/fish  with  /bin/bash,  /bin/tcsh or /bin/zsh as	appropriate in
       the steps above.)

       If you want to learn more about fish, there is lots of  detailed	 docu-
       mentation,  the	official gitter	channel, an official mailing list, and
       the github page.

       fish-shell developers

       2021, fish-shell	developers

3.3				 Nov 06, 2021		      FISH-TUTORIAL(1)


Want to link to this manual page? Use this URL:

home | help