- Part 1 – First Steps in Terminal
- Part 2 – Navigating the File System
- Part 3 – Special Characters
- Part 4 – Commands
- Part 5 – Managing Files
- Part 6 – Symbolic Links
If you like this series and want to learn Terminal and the shell on macOS in more detail, get my book “macOS Terminal and Shell“
Arguments
So far we have use three commands: pwd
, cd
, and ls
These commands are already quite different.
pwd
is a single word command. You enter it and it prints information (the working directory to the terminal).
cd
, however, requires additional information from you: where do you want to change to? The cd
command requires an argument:
$ cd ~/Documents
(You can enter cd without an argument, and it will change to your home directory, but usually you want an argument.)
The command itself cd
and the argument ~/Documents
are separated by a space.
Some commands can have more than one argument. In that case all arguments are separated from each other by a space. (Or more. bash
doesn’t care about multiple spaces.)
This is why we have to treat spaces in paths and filenames so carefully, because otherwise the shell might interpret the path as two or more arguments.
Finally ls
has an optional argument. When you just write ls
. it will list the contents of the current working directory. When you give an argument it will list the contents of that path. The ls
command also has several options that modify its behavior.
When a shell command is written in documentation optional arguments are usually enclosed in square brackets:
ls [-options] [path]
Mandatory arguments, on the other hand, are shown without the square brackets.
When you enter an ls
command with completely wrong options (surprisingly difficult, since its options cover nearly the entire alphabet, and some extra characters as well.) it will print a “usage” line:
$ ls --a
ls: illegal option -- -
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
The extra ...
after the optional file command tells us, that you can give ls
more than one path argument:
$ ls ~/Desktop ~/Documents
Read the Manual
When you want detailed information on a command, there are a few approaches.
Because of the long and diverse history of shells, bash
and macOS in particular, not all commands support all of these options. Behavior here can be very inconsistent.
First, as we just saw with ls
, some commands will print a brief usage note, when you enter something that the command cannot parse.
With some commands you can provoke the usage message with the -h
or --help
option:
$ sw_vers -h
Usage: sw_vers [-productName|-productVersion|-buildVersion]
The usage message is commonly very brief and usually does not explain all the options.
To get more detailed in information on command you can read its man page. man pages are documentation, often very detailed, stored in an file format optimized for display in ASCII terminals.
To get the man page for a command run the man
command:
$ man ls
This will take over the current Terminal window and display the information.
This special display mode is actually controlled by another command called less
. There many key commands you can use for navigation in this mode.
Key | |
---|---|
q |
exit and return to command line prompt |
up/down arrow | scroll up/down by a line |
space or z |
scroll down by a page |
w |
scroll up a page |
g |
top of document |
G (shift-g) |
end of document |
/word<return> |
find next occurrence of word in document |
n |
find next occurrence of search term |
N |
find previous occurrence of search term |
h |
help |
You can also scroll in this mode with the mouse wheel or two-finger scrolling on a trackpad.
You can also open man pages in terminal from the Help menu. When you enter a shell command in the help search field of Terminal it will suggest a man page, when one is available. When you select a suggested man page, it will open in a new yellow window.
You can modify the appearance of the man page window by changing the ‘Man Page’ window profile in Terminal’s Preferences.
You can also open a man page by selecting text and choosing ’Open man page from the context menu.
Some commands are ‘built-in’ to the bash shell. These do not always have man pages. Requesting the man page for a built-in command will show the man page for builtin
instead.
cd
is one example for a built-in command.
You can get documentation for built-in commands with
$ command help cd
Finding commands
We just learned that some commands, like cd
, are ‘built-in’ to the shell. Others are not, so what and where are they?
All commands are files in the file system. They have a special file privilege set which makes them executable. Obviously, you cannot make any file executable, it has to have some form of code which makes sense so the system can interpret it as commands.
If you want to know where a given command resides in the file you can use the which
command
$ which ls
/bin/ls
$ which sw_vers
/usr/bin/sw_vers
However, you do not have to type /bin/ls
every time you want to execute ls
. How does the shell know where to look?
The shell has an environment variable called PATH
which contains a list of directories where it will look for commands that are typed without an absolute path. You can print the contents of this variable with the echo
command:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
Note: commands and variable names in the shell are case-sensitive. It is convention that environment variables are written in all-caps. You have to use the correct case for the
PATH
variable to get or set the proper value.
When you are new to shell and bash
, there is a lot to process in this simple command, so let’s take this apart piece by piece:
The echo
command simply tells the shell to print something to the terminal, so
$ echo hello
hello
prints ‘hello’ back to the terminal. This alone is rarely useful, but can be used to get at the results of another process.
$ echo $(( 6 * 7 ))
42
The $(( … ))
means ‘evaluate this arithmetically,’ so this command prints the result of this arithmetic to the terminal.
In general in bash
the $
stands for ‘substitute contents.’ echo $PATH
means: print the contents of the PATH variable.
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
When you forget the $
and just write
$ echo PATH
PATH
bash
will interpret PATH
as a literal string and prints it to the terminal.
The actual contents of the PATH
variable is a list of directories separated by colons.
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
The order of the directories in the PATH
is important as the shell will stop looking when it finds a command.
When you enter a command without a path, e.g. ls
, bash
will start looking for the command executable in /usr/local/bin
, then in /usr/bin
, and then in /bin
, where it will find an executable ls
, stop looking and execute that.
Note: if there were another executable named
ls
in a later directories it would not be used, since the shell will stop looking at the first match it finds. Changing the order of the standard directories in thePATH
or even inserting other directories earlier in thePATH
can lead to unexpected behavior.
The PATH
on your system may be different when you have extra software installed. Xcode, Server.app, Xquartz, munki, Python3 and many other software packages insert paths to their command directories in the search path.
Note: some software solutions will attempt to modify the
PATH
on a system to make their commands available to the shell, other will place the commands or links to the commands in/usr/local/bin
to make them available (e.g. text editors like BBEdit or Atom).
We will look at strategies to on how and why to modify the search path later.
Some third party solutions will instruct you to modify the PATH
to include their commands rather than doing it during the installation.
Running Other Commands
When you need to execute a command or script that is not in the PATH
, you have to type the full or relative path to the command:
$ /usr/libexec/PlistBuddy
Usage: PlistBuddy [-cxh] <file.plist>
or
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport --getinfo
These are commands that are usually considered too uncommon or maybe even dangerous to put in the standard search paths.
When you start using and writing custom-built scripts and commands, you can use relative paths:
$ test/my_great_script.sh
or
$ scripts/postinstall
When you need to execute a command or script in the current working directory, you have to start the command with ./
, so the shell knows to not look in the search path.
$ ./buildMyProject.sh
Remember the .
is a shortcut representing the current working directory.
Tab-completion for Commands
You can use tab-completion for commands as well. This will speed up your typing and prevent typing errors.
You can use this to get a list of all the commands available in the shell. At an empty command prompt hit the tab-key twice. Then shell will warn you that there are many completions (more than a thousand, depending on your version and configuration of macOS.
You can also use this command to list all tab-completions:
$ compgen -c
Note:
compgen
is the command thatbash
runs to determine which commands are available for tab-completion. You usually would not interface with it directly.