It is vacation time here in the Scripting OS X headquarters and I will be traveling with family for most of August. The Weekly News Summaries are also on vacation, but to compensate for that I will be posting a draft of parts of my next book on macOS Terminal and
bash. Let me know how you like them or if you think something important is wrong or missing. You can give feedback in the comments, over Twitter or in the MacAdmins forum (also scriptingosx). Thank you for your interest and feedback!
- First Steps in Terminal
- Navigating the File System
- Special Characters
- Commands (this post)
- Managing Files
So far we have use three commands:
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.
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 ...]
... 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
$ 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 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.
||exit and return to command line prompt|
|up/down arrow||scroll up/down by a line|
||scroll down by a page|
||scroll up a page|
||top of document|
||end of document|
||find next occurrence of word in document|
||find next occurrence of search term|
||find previous occurrence of search term|
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
cd is one example for a built-in command.
You can get documentation for built-in commands with
$ command help cd
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 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 $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
PATHvariable 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:
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
$(( … )) means ‘evaluate this arithmetically,’ so this command prints the result of this arithmetic to the terminal.
In general in
$ 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.
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.
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
lsin 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 the
PATHor even inserting other directories earlier in the
PATHcan lead to unexpected behavior.
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
PATHon a system to make their commands available to the shell, other will place the commands or links to the commands in
/usr/local/binto 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>
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:
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.
. 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
compgenis the command that
bashruns to determine which commands are available for tab-completion. You usually would not interface with it directly.