If you're curious about this article, chances are you've played around with the Terminal in OS X and have become accustomed to the command-line interface, or you've worked with files through commands that you type rather than menus and icons that you click. If that's not the case, then you should first read Chris Stone's series of articles, titled "Learning the Mac OS X Terminal", and "Learning the Terminal in Jaguar."
In the switch from Jaguar to Panther, one of the footnotes that has occasionally been mentioned is the switch from tcsh to bash as the default shell in Mac OS X. Those who upgraded from Jaguar to Panther will still be using tcsh when they log in to Panther for the first time since your existing preferences will be respected; only new accounts that are created from within Panther will use bash by default. Most casual Terminal users won't notice the difference between the two, as the usual suspects will still work exactly as they did before:
cd will still move you to a different directory,ls will still list the contents of a directory,rm will still delete files,But those who have played around with aliases, environment variables, or other parts of tcsh will find that their lovingly crafted environment is nonexistent when using bash. This article will help those who have played around with tcsh in Jaguar make the transition to bash in Panther (and, in doing so, will quite possibly contain more screen captures of the Terminal than any Mac DevCenter article before it).
|
Related Reading
Learning the bash Shell |
If you've reached this point, chances are that you know that the shell acts as the glue between you and the big, hairy beast that hides in the deepest, darkest recesses of your computer. This beast, known as the kernel, happens to be at the top of your computer's food chain; it governs the resources (memory, processor, and disk) that each process receives, and ensures that everything is running as it should.
So you can imagine what would happen if a kernel doesn't behave properly: applications start crashing, the dreaded pinwheel appears, and the computer generally starts doing weird things. Chances are you've stumbled across this situation before, even if you didn't know it at the time: Windows users are familiar with the "blue screen of death," while those of us who have used one of the various incarnations of Mac OS X have probably come across a few kernel panics here and there.
What you may not have known is that you aren't restricted to which shell you use to keep control of the beast; several shells have been created in the 40-some odd years that Unix has been around. They all do the same job, but each is unique in the features it provides and the syntax it supports.
The first shell (sh), dubbed the Bourne Shell in honour of its creator Stephen Bourne, was developed at AT&T Bell Labs to accompany the first release of the Unix operating system. Since it was the first shell developed, the Bourne Shell serves as the foundation for all shells that have been created since.
The Bourne Again Shell (bash), whose name is a pun on its ancestor, is fully compatible with the Bourne Shell and includes extra features such as job control, command-line editing, and increased scripting support; consider it to be the Bourne Shell's official replacement. Developed and maintained by the Free Software Foundation, bash's source is freely available, which allows you to compile it on just about any flavour of Unix.
So if you make the jump to Linux or *BSD chances are bash will be waiting there to accept your command when you open up Konsole or Gnome Terminal for the first time.
Windowing systems, such as Aqua, KDE, and Gnome all have menus, icons, windows, and a cursor to dictate your actions to the underbelly of your computer. But each has its own unique quirks (for better or for worse) when compared to the others, in ways that are more than just superficial. For example, Aqua's sheets provide an alternative method of implementing dialog boxes for multiple document applications such as web browsers and word processors, since the user is still able to use another window while the dialog is present.
In much the same way, shells each have their own unique quirks that
differentiate themselves, yet each accomplishes the same function: to
relay your commands to the big hairy beast in your computer, and in
turn, to ferry the results back to you. This is why most of the commands
included in your ~/.tcshrc now fail when you try to execute
them in bash, since bash uses a different syntax for
many of its equivalent commands.
In addition to the other Unix components of the operating system, Panther
installs five shells, all of which are stored in the same location as
most other executable programs on Mac OS X, /bin:

Figure 1: The shells included with Panther are sh,
bash, csh, tcsh, zsh.
Judging by the sizes of the files, it would appear as though bash
and sh are in fact identical, while tcsh and csh
are identical; this meshes with the introduction to the different shells
discussed earlier, since bash is backwards compatible with
sh (as is tcsh with csh).
It is important to note that you are by no means limited to using the shells in the above list; several other shells, such as the Korn shell (ksh) can be downloaded and compiled on Mac OS X (or any other Unix system). However, the vast majority of Panther users will likely find the selection more than enough for their needs; if your shell of choice isn't included, chances are you've already downloaded the tarball and compiled it.
Mac OS X provides several ways to change your default login shell. And given OS X's split personality of Unix workstation and friendly desktop computer, it should be no surprise that one method is accomplished through the shell itself, while the other is accessible to anyone with a (one button) mouse.
Oddly enough, it's possible to try to change your default login shell without actually knowing what a shell is. Whether or not that's a good thing is up in the air, but to do it just open Terminal's preferences window and enter the path of the shell in the "Execute this command" text field, as shown below:

Figure 2: Using Terminal's preferences window to switch
to bash.
Then quit Terminal, and restart it to allow the new settings to take effect.
The above method of changing your shell is a convenience provided by Apple. But, like many configuration options that apply to the Unix underbelly of Mac OS X, it is merely a graphical front-end to a Unix command that can be invoked in Terminal.
Back in the days before windows and mice, everything had to
be done through the command-line -- scary, isn't it? On most Unix systems,
changing your shell to bash would be done through the command
chsh bash. However, Apple has slightly modified the chsh
command in OS X (more specifically, Darwin)
so that we must now use chsh -s bash to accomplish this
task on our candy-coated machines:

Figure 3: The results of attempting to change your
shell, both successfully and unsuccessfully.
Again, restart Terminal to ensure that your changes have taken effect.
Whether you've gone ahead and changed your shell or Panther set it up
automatically, you are now working with bash; you can even
double-check by checking the results of the command echo $SHELL
in Terminal.
Because of the size and complexity of bash, we won't be able to cover all of its features here. Instead, we'll take a look at the most common stumbling blocks that people find when moving from tcsh to bash and focus on those. So let's get started.
Every time you log in to your computer, bash will look for initialization files that are used to customize your environment, in exactly the same way that tcsh and the other shells do. Thus, instead of executing the same commands every time you log in, you can place these commands in your initialization file so that bash will do the grunt work for you. bash looks for these files in a few different locations, with each having its own distinct purpose:
| File | Description |
|---|---|
| /etc/profile | system-wide configuration file for the bash and sh shells |
| ~/.profile | executed every time a new shell is created, such as when you open a new Terminal window |
| ~/.bash_logout | executed when you log out from a shell |
Thus, the commands that you wish to invoke every time you open a Terminal
should be placed in your profile, located at ~/.profile
(you'll have to create it if it doesn't exist). If you wish to have
this command executed for every account on your computer that
uses bash, place it in the /etc/profile file instead.
A sample initialization file follows:
# shell variables
PS1="\n$PS1 "
PS2=": "
# environment variables
export CVSROOT=/usr/local/cvsroot
export CVS_RSH=/usr/bin/ssh
export JAVA_HOME=/Library/Java/Home
export ANT_HOME=/usr/local/ant
export CLASSPATH=/Users/dave/FVL/xerces.jar
# the path is initially set to "/bin:/sbin:/usr/bin:/usr/sbin"
export PATH=$PATH:/usr/local/bin:/usr/local/mysql/bin
# aliases
alias l="ls -l"
alias ll="ls -al"
alias mckoi="java com.mckoi.runtime.McKoiDBMain"
If you've played around with shell variables and aliases in tcsh,
then the commands shown above should look pretty familiar. You'll need
to "refresh" your profile after every edit so that the latest changes
take effect (think of refreshing your web browser to get the latest
copy of a web page). This can be done with the command source filename;
so in the case of your log out script, the command source ~/.bash_logout
would do the trick.
A variable, when speaking of programming languages, serves as a placeholder for information that will be retrieved at some point later in the program, such as a number, string, or date. When applied to shells (which actually are programming languages), variables may store your current directory, your prompt string, or any other piece of information required by the tools and programs you use. bash has two types of variables: "regular" variables and environment variables.
|
A regular variable typically holds a piece of information that you use
frequently. Because variables in shell scripts are loosely typed, unlike
C and Java, variables
can hold virtually anything: a number, string, or composite value such
as an array or hash. Creating a variable is pretty painless: name=value,
and retrieving its value is almost as easy: $name.
Thus, if you wished to see the current date when opening a new Terminal window, you could place the following lines in your profile:
mydate=`date "+%H:%M:%S %m/%d/%y"`
echo "hi $USER, the current time is $mydate"
For more information on shell scripting, refer to Chris Stone's series of articles mentioned in the introduction.
Environment variables are essentially a special case of shell variables; they are visible to all child processes that are spawned from the shell. In layman's terms, this means that applications and scripts that are executed from within shell can read the value of the shell's environment variables; as a result, command-line tools typically use environment variables for configuration settings.
By convention, the names of environment variables are all uppercase. Environment variables on OS X may include the following:
| Variable Name | Description | Example |
|---|---|---|
| PATH | A list of colon-separated directories where the shell will look for executable files | /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin |
| CLASSPATH | A list of colon-separated directories and/or JAR files that contain Java class files that may be required in the Java Runtime Environment. | /Users/dave/FVL/Java/xerces.jar: /Users/dave/FVL/mckoi.jar |
| JAVA_HOME | The root directory of your Java installation. | /Library/Java/Home |
| PWD | Your current directory in the file system. | /Applications |
| USER | Your login name. | dave |
To find out which environment variables have been defined in your shell,
use the env command, which simply echoes all the environment
variables to the terminal:

Figure 4: All environment variables defined in my shell.
Creating new environment variables is pretty simple; bash uses
the syntax export VAR_NAME=value. Thus any shell variable
can be turned into an environment variable via the export
command:
# create the JAVA_HOME environment variable
export JAVA_HOME=/Library/Java/Home
# do the same thing explicitly, using two lines
JAVA_HOME=/Library/Java/Home
export JAVA_HOME
And what happens if a required environment variable doesn't exist? Nothing too drastic -- the kernel won't panic and your computer won't start blowing smoke. It shouldn't, anyway. The shell and related tools require certain variables to be defined (such as ), but other tools may need their own environment variables. In the event that you are missing a required variable, chances are the related program will fail safely and let you know what needs to be defined, as does Apache's fop:

Figure 5: A typical example of missing an environment
variable.
The following table lists the differences in working with variables (both shell and environment variables) between tcsh and bash on OS X:
| Command | tcsh | bash |
|---|---|---|
| Display all shell variables | set |
set |
| Create a shell variable | set name=value |
name=value |
| Remove a shell variable | unset name |
unset name |
| List all environment variables | env |
env |
| Create an environment variable | setenv name value |
export name=value |
| Remove an environment variable | unsetenv name |
unset name |
Aliases have been a part of Mac OS for several generations now. However, the terminology has gotten a bit confusing with Mac OS X since it's a branch between two traditionally distinct family trees: Unix and Mac OS, each with their own vocabulary. So it shouldn't be too much of a surprise that bringing the two together results in some conflict. One example of this is the term alias: the Finder and Unix underbelly each use the term for two different things:
link);
shell aliases allow you to remap virtually any Unix command to another
name, and the aliased commands can then be invoked using their new
name. Aliases are declared in a similar method to variables, with the keyword
alias in front of the declaration: alias name=command.
If the command contains spaces, then you will have to wrap it in double
quotes. To find out which aliases you have already defined, simply enter
the command alias (in the event that you wish to remove
an alias, then you can simply use the command unalias name):
alias l="ls -l"
alias ll="ls -al"
alias ~="cd ~"
alias md=mkdir
alias mckoi="java com.mckoi.runtime.McKoiDBMain "
# remove the alias named md (for demonstration purposes)
unalias md
The following image illustrates the use of the first two aliases created above:

Figure 6: An example of how even simple aliases can
save you time at the keyboard.
After opening a Terminal window and being greeted by the message of the day, the first thing you'll see is your command prompt, waiting to accept your every wish. If you went ahead and changed your prompt in Jaguar with tcsh, chances are you'll be disappointed when you first see Panther's default prompt, which should appear something like:

Figure 7: The default prompt for bash in Panther.
Like tcsh, however, it is a relatively trivial process to change
your prompt in bash by setting the value of two special shell
variables, PS1 and PS2. Why two, you may ask?
Good question -- PS1 is can be considered to be the primary
prompt, which is displayed every time a new command can be
entered; while PS2 is the secondary prompt that is displayed
when a command spans more than one line. This screen shot illustrates
the two prompts in use:

Figure 8: An illustration of PS1 and PS2
in bash's default configuration.
The following table lists the information that you may wish to insert into your prompt:
| Command | Description | Example |
|---|---|---|
| \a | ASCII bell character | -- |
| \d | the current date | Sun Feb 08 |
| \H | hostname | Ginger.local |
| \h | shortened hostname | Ginger |
| \u | your username | dave |
| \w | current working directory | /Applications/Network |
| \W | basename of the current working directory | Network |
| \T | current time (12-hour HH:MM:SS format) | 01:16:49 |
| \t | current time (HH:MM:SS format) | 13:16:49 |
| \@ | current time (12-hour AM/PM format) | 1:16 PM |
| \n | new line | -- |
| \\ | print a backslash | \ |
From the information listed in the above table, we can see that Panther's default prompt strings are created using the following commands:
PS1="\h:\w \u$ "
PS2=" > "
This article provides an overview on making the transition from tcsh and bash; at this point you should now know enough about bash to start tailoring your Panther environment to your needs. And while this article covers several key features of it, we have barely scratched the surface; command history, job control, scripting, and several other features went untouched. For more information, be sure to check out the following resources:
man bash at the prompt to read
the pages.David Miller is combining his passions of photography and working on the web at iStockphoto; when not hacking away with a text editor and a few web browsers in hand, he can be seen huddled over his laptop tweaking levels and curves for his freelance photography. Keep track of David's latest projects over at his home on the web.
Return to the Mac DevCenter
Copyright © 2009 O'Reilly Media, Inc.