UnixHow to Use the Unix Shell Command-Line
This page will give a quick overview of the command-line interface used in the Rails-development demos. The following is intended to be a brief introduction to help get readers new to such interfaces started. For deeper treatments of the topic, we provide helpful resources at the end of the page.
Command-line interfaces are very widely used in software development environments—and with good reason! Terminal apps (like Windows Terminal, macOS Terminal, and Linux Gnome Terminal, just to name a few) enable users to enter textual commands into a command-line interface to perform a host of development tasks. In particular, many platforms, frameworks, and toolkits (including Rails) provide their core functionality via a command-line interface.
Although different flavors of command-line interface exist, the demos will use the Unix Shell command-line interface (specifically Bash/Z Shell), which is arguably the most popular for Rails development.
Typical User–Shell Interaction
Interactions with a Unix shell command-line interface goes something like this. The shell provides a prompt that might look something like this:
▊ |
Prompts are customizable, so they may look very different than this.
Users can type commands after the prompt, like this:
ls -l▊ |
In this case, the user has typed the command ls -l
, which displays a detailed file listing. If the user presses the Enter key, the command will run, producing output, like this:
ls -l |
Note that once the command completes, another prompt is offered, so that the user can enter their next command.
Command Syntax
At its most basic, Unix command syntax is a command token followed by an arbitrary number of whitespace-separated argument tokens. All tokens are strings. Since whitespace is used to separate arguments, a string token itself generally may not contain embedded whitespace characters; otherwise, it will will be interpreted as multiple tokens. If you have an argument that must contain whitespace (e.g., because it’s a filename that contains whitespace), then either the argument must be surrounded by quotes or the whitespace characters must be escaped (e.g., “\
”). Here are some examples of the cat
command with varying numbers and types of arguments.
Example Command | Explanation |
---|---|
cat aaa.txt |
In this example, the cat command is given one argument, aaa.txt . |
cat aaa.txt bbb.txt |
In this example, the cat command is given two arguments, aaa.txt and bbb.txt . |
cat aaa.txt bbb.txt ccc.txt |
In this example, the cat command is given three arguments. |
cat 'filename with spaces.txt' |
In this example, the cat command is given one argument. Because that argument contains spaces, it is surrounded by single quotes. |
cat "filename with spaces.txt" |
Same as the previous example, except using double quotes instead of single quotes. (Either one is OK to use.) |
cat filename\ with\ spaces.txt |
Same as the previous example, except escaping each embedded space character instead of surrounding the whole argument with quotes. |
cat aaa.txt x\ x\ x.txt "y y y.txt" zzz.txt |
In this example, the cat command is given four arguments. Can you tell what they are? |
In addition to this basic syntax, there are several common syntactic patterns that Unix shell commands employ.
One such common pattern are dash options. Dash options are arguments with a form like this: -a
, -b
, -c
, etc.
Example Command | Explanation |
---|---|
ls -l |
The ls command may be called with a -l option that makes the command produce more-detailed output. |
ls -a |
ls may also be called with a -a option that makes the command output include hidden files. |
ls -a -l |
Multiple dash options may be used for a single command. |
ls -al |
For single-letter dash options, multiple options may also be combined together as a single dash option. |
ls --all |
For each option, Unix commands often have a single-letter dash option and a corresponding longer double-dash version. For example, the ls option -a may also be expressed as --all . |
ls -a -l foo bar |
Dash options may be used in combination with other sorts of arguments. For example, this command has two dash options (-a and -l ) and two string arguments (foo and bar ). |
Directory Tree Structure
Interactions with a Unix shell take place in the context of a Unix file system. The Unix file system is generally made up of directories (or folders), text files (e.g., source code), and binary files (e.g., image files).
The directory structure is generally organized as a tree. Each directory is contained within a parent directory and may itself contain child directories. A directory may also contain text and binary files. For example, the following is part of the directory tree for the app
directory of a Rails project:
app |
Note how the assets
directory is contained within the app
parent directory and has three child directories, config
, images
, and stylesheets
. Also, note the text files (i.e., with .js
and .scss
suffixes) and the binary image file, quiz-bubble.png
.
The entire Unix filesystem directory tree originates from a single root directory, which is denoted as /
.
Each registered user of the system has a home directory somewhere in the filesystem directory tree. The home directory is denoted as ~
. Where home directories are located depends on the OS. In Linux, they are often in the /home
directory (e.g., /home/alice
). In macOS, they are in the /Users
directory (e.g., /Users/alice
).
Expressing File Paths
When interacting with a shell, the user is always “in” some directory in the file system. This directory is referred to as the current working directory (also sometimes present working directory). Generally, a user’s home directory set as the current working directory when a user logs into the system.
Shell commands often take a file or directory as part of their arguments. To illustrate, the following are some examples of different ways to express file paths using the ls
(directory listing) command. Assume that the examples take place in the context of this directory tree:
aaa |
Also, assume that current working directory is the bbb
folder in the above directory tree.
Example Command | Explanation |
---|---|
ls ddd |
List the contents of the ddd child directory within the current working directory (bbb ). “ddd ” in this case is a relative path because its position is relative to the current directory. |
ls ddd/ |
Same as the previous example. In this case, the / just clarifies that ddd should be a directory (and not a file). Putting a / after a directory name like this is generally optional. |
ls ./ddd |
Same as the previous example. In this case, . is used to explicitly denote the current working directory. Also note that / is used as separator between elements of the path. |
ls eee/hhh |
List the contents of hhh , which is a subdirectory of eee , which in turn is a subdirectory of the current working directory (bbb ). |
ls .. |
List the contents of the parent directory (aaa ) of the current working directory (bbb ). |
ls ../.. |
List the contents of the parent of the parent of the current directory. |
ls ../ccc |
List the contents of ccc , which is a subdirectory of the parent directory (aaa ) of the current working directory (bbb ). |
All of the above example paths are considered relative paths because they are all expressed in a way that is relative to the current working directory.
In contrast to relative paths, absolute paths always mean the same thing regardless of which directory is the current working directory. Such paths always start from a fixed location in the filesystem—for example, the root directory or the current user’s home directory (~
). Here are some examples that use absolute paths:
Example Command | Explanation |
---|---|
ls /aaa/bbb |
Assume that the aaa directory is contained within the root directory. List the contents of the bbb directory, which is a child of the aaa directory. Note that the first / denotes the root directory. |
ls ~/aaa/bbb |
Assume that the aaa directory is contained within the current user’s home directory. List the contents of the bbb directory, which is a child of the aaa directory. Note that the ~ denotes the home directory. |
Inspecting and Changing the Current Working Directory
The following are several common commands for inspecting and changing the current working directory.
pwd
: Report the path of the current (aka present) working directory.ls
: List the contents of the current working directory.cd
: Change the current working directory.
Here are some examples of common usages of these commands, including some of their commonly used options.
Example Command | Explanation |
---|---|
pwd -P |
List the absolute path to the current working directory. |
ls -a |
List all files in the current working directory, including hidden files. |
ls -l |
List all files in the current working directory, providing a “long” listing that includes permissions, etc. |
ls -l -a |
Combines the above two commands. |
cd |
Change the working directory to the home directory. |
cd foo |
Change the working directory to the directory named foo within the current working directory. |
cd .. |
Change the working directory to the parent directory of the current working directory. |
cd ~ |
Change the working directory to the current user’s home directory. |
cd / |
Change the working directory to the root directory of the filesystem. |
Manipulating Files and Directories
The following are common commands for manipulating files and directories from the command-line.
mkdir
: Make a directory.cp
: Make a copy of a file or directory.mv
: Move (or rename) a file or directory.rm
: Remove a file.cat
: Outputs the contents of text files. If multiple files are listed, the output effectively concatenates them, which is why the command is calledcat
(short for concatenate).nano
: Launch a basic command-line text editor.
Here are some examples of common usages of these commands, including some of their commonly used options.
Example Command | Explanation |
---|---|
mkdir foo |
Make a directory named foo in the current working directory. |
cp a.txt b.txt |
Make a copy of the file a.txt in the current working directory, and save the copy as b.txt (also in the current working directory). |
cp a.txt foo/ |
Make a copy of the file a.txt in the current working directory, and save the copy (using the same filename) in the subdirectory foo . |
cp -a foo bar |
Make a copy of the folder foo (including all the folder’s contents), and save the new folder as bar . Note that the -a option (short for archive) is needed when copying a directory. |
mv a.txt b.txt |
Rename the file a.txt to b.txt |
mv a.txt foo/ |
Move the file a.txt from the current working directory into the subdirectory foo . |
rm a.txt |
Remove (i.e., delete) the file a.txt from the current working directory. |
rm -r foo |
Remove (i.e., delete) the directory foo and all its contents. Note that the -r option is needed when the target is a directory. |
cat a.txt |
Outputs the contents of file a.txt . |
nano a.txt |
Opens the file a.txt in a command-line text editor. Note the special key commands listed at the bottom of the terminal. For example, Ctrl-X (denoted ^X ) will exit the editor, giving the user the option to save their changes. |
Finding Documentation on Commands
There are several ways that users commonly find documentation on commands. (Unfortunately, this can be a bit inconsistent depending on who created the command.)
Firstly, googling is often your best option to figure out what command will perform a certain function.
If you think you know the command you need, but want to find out what options, there are several ways to go about it.
For the commands mentioned above, which the standard file-management commands in Unix, the man
command (short for manual) is probably your best bet:
man ls |
The above example will open a documentation viewer in your terminal for the command ls
. You can scroll up and down in the documentation using the up- and down-arrow keys. To exit the viewer, enter q
(short for quit).
For other commands, there may not be a good man
page; however, there are some other common ways to find documentation.
One such way is that many commands offer a help option (-h
and/or --help
), for example:
ls --help |
This command will cause ls
to print usage documentation.
One final way often works for certain commands (e.g., git
and rails
) that expect a sub-command as their first argument, for example:
git help |
This command will cause git
to display general help documentation.
Furthermore, the help
sub-command can often be followed by a specific sub-command, like this:
git help commit |
This command will cause git
to display documentation specifically about its commit
sub-command.
Productivity Features
Finally, there are two productivity features common to shells/terminals that you will definitely want to train yourself to use.
Quickly Accessing Previous Commands in the Command History
From the terminal prompt, hitting your up- and down-arrow keys will cycle through your command history. It is very common to enter the same (or almost the same) commands over and over, and this shortcut will save you a lot of time and typing.
Tab Completion to Speed Up Typing
When entering file paths as arguments to commands, you can use the Tab key to autocomplete directory and filenames. For example, imagine that a user starts to type a command, like this:
ls f▊ |
If the user now hits the Tab key, the shell will look for all the files in the current working directory that start with f
. If there’s only one such file, it will automatically fill in that file’s name for the user, like this:
ls foo▊ |
If there are multiple such files, then the terminal will blink/beep at you, and you’ll have to add enough characters to disambiguate which file you want.
Similar to the up-arrow shortcut, this Tab completion feature will save you tons of time and typing.
Helpful Resources
As the above document was just intended as a practical introduction, you may want to explore these other resources to learn more details about how Unix shells work and how to use them effectively.
Suggestions for other helpful resources are welcome!