English is a perplexing language. For example, consider the words moon and good. To the uninitiated, the words should rhyme, but the former is pronounced /mun/ (according to the International Pronunciation Alphabet), while the latter is spoken /good/. Seemingly, the only rule in English is exception.
UNIX shells are equally perplexing. For instance, in the Bourne shell (and most common
UNIX shells), the phrases
`$var` look alike but yield substantially different results.
(Each CLI in the shell examples presented in this article are prefaced with the name
of the active shell and the command number.)
bash-1) # Demonstrate the differences between single-, double-, and back quotes bash-2) var=ls bash-3) echo '$var' $var bash-4) echo "$var" ls bash-5) echo `$var` Rakefile app bin components config db doc lib log patches public script src test tmp vendor
In the sequence above, the variable
var is set to the two-letter
string ls. In the initial
echo command, the apostrophes
prevent interpretation of the variable, instead yielding a verbatim copy of the quoted
text, the four-letter string $var. Next, in command 4, the double quotation marks
do interpret the variable, so the result is the string ls. Finally, the back quotes both
interpret the variable and run the intermediate result as a subshell. Thus,
`$var` yields the intermediate string ls, which runs
as a shell command to produce the contents of the local directory.
Certainly, all three operators—the single, double, and back quotation marks—serve
a valid purpose, but like exceptions in English, memorizing and mastering the variations
can be maddening. Here's more proof: What's the difference between the phrase
$var contains whitespace.)
bash-1) # Create three files and try to remove two bash-2) touch three two one bash-3) var="one two" bash-4) rm "$var" rm: one two: No such file or directory bash-5) rm $var bash-6) ls three
If a variable contains whitespace, the double quotation marks keep the variable expansion intact as a single argument. Otherwise, any whitespace in the variable is interpreted as an argument delimiter.
Yep. Shell syntax can be maddening. And that's unfortunate, because it makes the CLI—one of the most powerful features of UNIX—more difficult to learn. Indeed, inconsistencies like those described above fluster hardened veterans, too.
fish—the Friendly Interactive Shell—swims
upstream against the tide of obfuscation, providing streamlined syntax and a
much-improved user experience. Like other shells,
provides redirection, shortcuts, globbing (that is, expansion of wildcards), subshells,
tab completion, and variables. Unlike alternatives, however,
fish also provides color-coded CLIs, an extensive
command-line editor, and rich documentation.
Additionally (and intelligently),
fish provides only one way to
do anything. If a UNIX utility achieves a particular task,
does not repeat the feature as a built-in command. For example,
fish uses the system-wide application /bin/kill to terminate
processes. (By comparison, the Bourne shell implements its own version of kill as
a built-in application. You can type
/bin/kill at the Bourne
shell prompt to use the application, instead.) Whenever possible,
prefers simplicity over flexibility, making it far more predictable to use.
Here, let's install
fish, reel it in, and try just some of its
Fish is an open source project created by Axel Liljencrantz and licensed under
the GNU General Public License, version 2. As of this writing, the latest version
fish is 1.23.0, released 13 January 2008.
If you use UNIX or a UNIX-like system, such as Linux® or Mac OS X,
fish should build from source code readily and
easily on your system. Here are the steps, as shown in Listing 1:
- Download the most recent source tarball of the program.
- Unpack it.
- Change to the source directory.
- Configure the build.
Listing 1. Build fish from source
bash-1) wget http://www.fishshell.org/files/1.23.0/fish-1.23.0.tar.gz bash-2) tar xzvf fish-1.23.0.tar.gz bash-3) cd fish-1.23.0 bash-4) ./configure --without-xsel checking if autoconf needs to be run... no checking if autoheader needs to be run... no checking for /usr/pkg/include include directory... no ... bash-5) make gcc -c -o function.o function.c ... bash-6) sudo make install ... To use fish as your login shell: * add the line '/usr/bin/fish' to the file '/etc/shells'. * use the command 'chsh -s /usr/bin/fish'.
If you're using a UNIX-like system, the additional flags to
configure aren't strictly needed. However, to
minimize dependencies and to keep
fish in the
same directory structure as common shells, you can add
respectively. (If you use Mac OS X version 10.4 Leopard, also add the parameter
LDFLAGS=-liconv. If you omit the latter option on Mac
OS X, the attendant
fish utilities fail to build.)
Optionally, if you use a popular UNIX variant, you can likely find pre-built binaries
ready to install on your distribution. For example, if you use Debian Linux, you
fish in an instant with the command
sudo apt-get install fish. Check the
home page for availability for your system.
Before diving in to more complex topics, let's look at how common shell tasks
are accomplished in
- To redirect standard input and standard output, use the operators
>, respectively. To redirect standard error, use the carat (
^), as shown in Figure 1. To append standard error to a file, use
Figure 1. Redirect standard error with the caret operator
In command 3, the error messages produced by
rmare captured in the file named errors. Command 4 shows the contents of the file. The
fishshell has rich support for redirection, such as combining descriptors into one stream and closing descriptors.
By the way, the colored and underlined text shown aren't editorial. The shell highlights text in the CLI as you type. In the lines, green indicates that the command name is valid; an invalid command name is colored red. The underline is a hint that the named file exists. (A section below covers shell feedback in more detail.)
- To run a subshell, use the parentheses (
()), as shown in Figure 2. Text enclosed within parentheses is interpreted as a list of commands and replaced by the result.
Figure 2. Use parentheses to run a subshell
- To create an alias, or shortcut, create a
A function can contain one or more commands, and the special variable
$argvautomatically expands to the list of arguments passed on the original command line.
You can list all defined functions with the command
functions. To erase a function, use
functions --erase name, as in
functions --erase ll.
You can also instantly save any function you write at the command line. When your code is complete, type
funcsave name, such as
funcsave ll. The function is immediately available to all your currently running shells and all future shells, as well. The command
funced nameinteractively edits an existing function. The
funcedcommand has full syntax highlighting, tab completion, and automatic indenting;
funcedmake it easy to customize your shell.
- To set a variable, type
set variable name value. As with the
functionsbuilt-in variable, type
set --erase variable nameto "unset," or erase, a variable. To retrieve the value stored in the variable, type a dollar sign (
$) followed by the variable's name, as shown in Figure 3.
Figure 3. Test for the existence of a variable
--queryoption to test whether a variable is defined. If the variable is set,
set --queryreturns a status code of 0, indicating that no error occurred; otherwise, it returns a 1. Statement 6 chains two commands with the
oroperator: The second command (
echo) executes only if the first command fails.
So, how does
fish handle the dreaded
`$var`? True to
form, it follows a few simple rules:
- If a variable contains whitespace, the whitespace is always preserved,
and the variable always evaluates to a single argument (see
Figure 4. Fish keeps strings with embedded whitespace intact
- If the double quotation mark is the outermost quote, all variables are expanded.
- If the single quotation mark is the outermost quote, no variables are expanded.
Let's look at how these rules work in practice.
Command 1 creates four files, where the last file has whitespace in its name.
Commands 3 and 4 delete the file named by the variable
Commands 6 and 7 delete the two files named in the
variable. Look closely at command 6: Because the value is not placed in quotation
marks (either single or double), whitespace is not protected. Hence, command 7
expands the variable into two arguments and deletes both files. Commands 9 and
10 reiterate the scenario in commands 6 and 7.
Commands 11 and 12 demonstrate the whitespace rule. Even though the variable is
not surrounded by double quotation marks in command 12,
maintains the whitespace set in command 11. Very nice.
Commands 14 through 16 exhibit
fish's nested quoting rules.
Now, glance again at commands 11, 15, and 16. The shell uses color codes to display
balanced quotation marks and reinforce proper syntax. Look, too, at commands 9 and
11. The latter command underlined the file name, indicating that it exists. The missing
underline in command 9 is a big hint you did something wrong.
fish's first name.
Speaking of friendly features,
fish's tab completion
feature is another novelty that new UNIX users—and experts—find
extremely useful. To see completion in action, type along in the example that
follows. Click the Tab key at the end of each line.
If you're unsure of a command name, you can click Tab after typing a few letters to view a list of possible completions, as Figure 5 shows. (The list of completions on your system may differ from the list shown here. The list depends both on your PATH environment variable and the contents of your UNIX system.)
Figure 5. Click Tab to complete a command name
Notice the red text in the CLI. If
fish doesn't recognize
the name of a command, it is shown in red. Clicking Tab reveals all the
application names—with a brief description—that begin with
what you've you typed so far. You can also click Tab at an empty prompt to
see all applications in your PATH.
If you'd like to know what options are available for a command, click Tab after a
-) or double hyphen
--), as shown in Figure 6.
Figure 6. You can also click Tab to complete an option
fish tells you which options are available. The
shell maintains a large index of common commands and options, and chances are, you
can get the help you need. However, custom or more esoteric utilities may lack such
data. You can read the
fish documentation to learn more
about writing your own completions.
You can also click Tab after typing a few letters of the option, as Figure 7 shows. The shell displays all the possible matches.
Figure 7. You can type part of an option, too
If you don't know what kind of operand a command manipulates,
fish can help—in many cases, but not all. For
example, if you type
fish variable editor), a space, and then press Tab,
fish presents a list of available variables. The
set is an argument. Similarly, if you type
type, a space, and then click Tab,
displays a list of built-ins and functions that extend which utilities are available to
you on the file system.
In general, all the built-ins and functions included with
have context-sensitive operand completion. Try
example, as shown in Figure 8.
Figure 8. Many commands are context sensitive and present suitable arguments
cd function is a
function and is aware that its operand is an existing directory. When you click
Tab after typing
presents all the existing directories contained in every directory in your CDPATH.
Another smart completion is associated with
ssh followed by a space, and then click Tab to see a
list of known hostnames taken from your Secure Shell known hosts file (typically
found in ~/.ssh/known_hosts):
fish-1) ssh login.example.com (Hostname) host1.example.com (Hostname)
fish shell also completes file names and directory
names. Again, it highlights correct elements as you type path names.
One significant difference between
fish and other shells
is the lack of history shorthand, such as
If you like
fish and want to adopt it as your login
shell, add the path to
fish to the official list of
shells, /etc/shells, and then run
bash-1) type fish fish is /usr/bin/fish bash-2) sudo vi /etc/shells Add the line /usr/bin/fish to the file if it's missing, and save the file bash-3) cat /etc/shells /bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh /usr/bin/fish bash-4) chsh -s /usr/bin/fish Changing shell for strike Password: ******** bash-5) login strike Password: ******** Last login: Wed Oct 8 15:02:21 on ttys000 Welcome to fish, the friendly interactive shell Type help for instructions on how to use fish fish-1) echo $SHELL /usr/bin/fish
There is a lot to discover and like in
fish. Dare I say
it? "There is a lot of
C in the
You can tweak the colors in syntax highlighting. You can customize your startup by editing
~/.config/fish/config.fish. You can share variables across shell instances using
universal variables and
fishd. The shell also has
a great history search feature, an interactive variable editor, and an interactive
Best of all, there is a tremendous amount of documentation all available from
fish itself. If you need help, just type
help at any command prompt.
The doctors are right:
fish is good for you.
UNIX: Check out other parts in this series.
Learn more about the design of
See more screen shots of
Learn more about UNIX shells.
The AIX and UNIX developerWorks
zone provides a wealth of information relating to all aspects of AIX systems
administration and expanding your UNIX skills.
New to AIX and UNIX?
Visit the New to AIX and UNIX page to learn more.
Browse the technology
bookstore for books on this and other technical topics.
Get products and technologies
Check out developerWorks blogs
and get involved in the developerWorks
Participate in the AIX and UNIX forums:
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- Virtualization Forum
- More AIX and UNIX Forums
- AIX Networking
Martin Streicher is a freelance Ruby on Rails developer and the former Editor-in-Chief of Linux Magazine. Martin holds a Masters of Science degree in computer science from Purdue University and has programmed UNIX-like systems since 1986. He collects art and toys. You can reach Martin at firstname.lastname@example.org.