Getting Mac OS X 10.3 to Behave Almost Like my Linux Boxes

(and other tweaks)

Warning! Much has changed since 10.3, so don't expect these to work (or be the best way to do things) on 10.4 (Tiger).

Here are some notes on how I set up a few Apples running OS X 10.3.  I do not claim that this is the best way to go about doing anything and some of this is very specific to my needs, but it seems to work.  If you have any comments, corrections, or suggestions on better ways to do any of this, please let me know!

Some of these things are trivial to do and the way to do them is fairly obvious, i.e., there's absolutely no trick to them.  However they are listed here to remind me they should be done on a fresh install (since I've already had to contend with this stuff three times). Topics:

Cluster-related topics:

Swapping Control and Caps Lock

After getting on the net, the next most important thing is getting the control and caps-lock right (at least for those of us who refuse to stretch our pinkies and think the prominent caps lock key is pure evil).  This fix comes from  Note that this fix will not work on a laptop (since the laptop does not use a USB keyboard).

You want to do this as root, so you'll probably have to do this first:

  sudo su
Now use vi or emacs or whatever editor you have and open the file:
Yes, that's quite a path! You will see, at line 25, something like this:
         <key>Generic Keyboard</key>
Change that by adding the two lines shown here after the second <dict>:
         <key>Generic Keyboard</key>
              <key>Swap control and capslock</key>
Then, as root still, do the following:
  touch /System/Library/Extensions
Reboot and hopefully the control key will be where it's supposed to be!

It is my experience that this has to be redone after every minor upgrade of the OS (i.e., when 10.3 switched to 10.3.1 I had to re-do this and then again with the switch to 10.3.2).

If you want to use an application to handle the dirty work for you, you may find ucontrol useful. (Thanks to Tim Heany for brining this to my attention.)

GNU Compiler

For this you have to get things from the Apple Developers site.  Registration is free (you'll just get something like biweekly announcements from Apple about various development related things -- it isn't too onerous, but probably not too useful for you either).  You enter this information at  Click on the little "Log In" text next to the arrow toward the top of the page.

After logging in, click on "Download Software" (in orange?) text on the left side of the page.  This expands a bit.  Click on "Developers Tools" (again, on the left side of the page).

Checking things August 12th, things have changed from what was previously described here.  It now appears you can simply download the XcodeTools1.5__CD.dmg bindaries (about 372 MB) as a single-shot thing.  Install this "in the usual way."

X Windows Applications, Fink, LaTeX, etc.

There are a few hoops to jump through and there is some order dependence.  You must have the compiler installed before you do the following.

Do not install the Apple X11 server (well, not yet anyway).  If you have done that, then issue this command (which looks drastic, but we'll fix it in a bit):

  sudo rm -rf /usr/X11R6 /etc/X11
The next step is to get fink going.  Once you get "FinkCommander" running, things are quite nice.

Go to  Click on Download over on the left.

Click on "Fink 0.7.0 Binary Installer" and install that (you may have to click on an icon of a box being unpacked to get this going).  It should go fairly smoothly and you will see a directory someplace (I think a Finder window pops up) labeled "FinkCommander" (or something like that).  Open that directory and drag the FinkCommander application to your Applications folder (I think a green circle with a plus sign will appear when you've dragged it to a place where it knows its supposed to move to a new directory).  Once you have it there, double-click on it to open it.  I think you have to enter your password twice before it will be happy.

Once it starts, you will see a long list of applications you can install.  Rather than sorting through these collectively, it's much easier to use the "Name" field in the upper right corner to get what you want.

Let's try to install grace (really xmgrace, you have to type xmgrace at the command line).  This is a great plotting package (and free, of course).  Details about grace can be found here.  (But, you can skip this if you have no need for grace.)

Click on the Name field and start typing "grace".  As you type the number of applications which match your selection will be shown (first all those that have a "g" in their name, then a "gr", then and "gra", etc.).

Once you see grace, click on it so that it is highlighted in blue (or whatever).

Now click on the button that looks like a green plus sign on a page with a letter "h" on it.  It will say various things about dependencies and do you want to select this or that.  Just stick with the default choices which you get by just hitting return each time.  Once it starts compiling this will take a very, very long time to compile.  Don't worry about that.  Mostly this is compiling all the stuff that grace requires which is probably stuff you want on your system anyway (assuming you're a bit of a number cruncher).

The applications I typically install are:

After you install TeX (i.e., the tetex distribution), you should run texconfig as the superuser.
  sudo texconfig
Under the dvips "global" settings change the paper size to letter (just get it highlighted and hit return I think).  Under the dvips "cmd" settings, make sure you hit return with a blank entry so that output will go to a file instead of a printer.

You will find that xdvi is broken.  I have found that this fixes things, although I'm not sure why:

  sudo su
  cd /sw/src
  tar zxvf tetex-src-2.0.2.tar.gz
  cd tetex-src-2.0.2
  cd texk/xdvik
  make install
  cp xdvi.bin /sw/bin
  cd  /sw/src/
  rm -rf tetex-src-2.0.2
Hopefully that will do the trick! (Although I'm not sure why -- one person claimed [and I can't find it now] that you had to issue the command
  perl -pi -e 's|ld1||g' Makefile
at some point, but I can't find any occurrences of ld1 or 1dl or such in the Makefiles [and one should check after running configure].) Now, you need to get a X windows server going.  That's covered next...

X Windows Server

Do not do this until after you have installed fink!

Go to  Fill in the information they request (don't forget to uncheck the box that says you want Apple spam), and click the "Download X11" button.  You may have to click on an icon of a box being unpacked or the installer may start automatically.  After installing it, fire up the server and see what you get.  I think you will get a xterm that isn't too functional.  I suggest you modify the file

to get the default xterm to be decent.  The line I have in there now replaces their old xterm command (toward the bottom of the file) with the following
  xterm -sb -sl 500 -e /bin/bash -login &
For you csh fans this would be something like
  xterm -sb -sl 500 -e /bin/tcsh -l &
Also, you can get the X11 application to launch similar xterms if you customize things similarly under the Applications menu (i.e., make sure X11 is the selected app, click on Applications and then click on "Customize..."). Add
  setenv DISPLAY :0.0
to your .cshrc file or
  export DISPLAY=:0.0
to your .bash_profile file.  This way you should be able to type X windows commands from Terminal and they'll know how to start.

Start-up Chime

If you want to stop the start-up chime or control the volume, see:

Colorizing ls Output

ls on the Mac can colorize the output like I'm used to on Linux machines.  As noted by Aaron Whiteman: "ls will respond to your terminal, so if it is set to something like 'vt100' it won't display in colour.  Use 'xterm' instead." I have an issue with the xterm emulation in that when I read man pages they will disappear once I stop reading them.  Aaron's fix for that is to set the following environmental variables:
  export LESS='-X -e'
  export PAGER=less
However, I have another issue with the default ls (having to do with its return value, but this may have been fixed in Panther).  So, I downloaded the GNU ls (which ultimately lives in /usr/local/bin) and made an alias to that.  Here's what has to be done.

Go to and then follow the link to the downloads, i.e., Once there, select the version you want of 'coreutils', i.e., coreutils-5.0.tar.bz2.  (For some reason when I downloaded this with Safari 3.1.1 it added an additional .tar to the end of the file name. Firefox didn't have this problem.)

Assuming you downloaded the .bz2 version of the tar-ball, you can unpack it with a command such as

  tar -xv --use-compress-program bunzip2 -f coreutils-5.0.tar.bz2

From the Terminal cd to wherever it unpacked and then type the following

  sudo make install
Then just alias your ls to whatever you like, but in /usr/local/bin.  For example, something like this:
  alias ls /usr/local/bin/ls -F --color
for C shell or the following for bash
  alias ls='/usr/local/bin/ls -F --color'

For those of you who like to get your colors just so, you may want to check out TerminalColors which lets you tweak colors to your heart's content. (Thanks to David Lee for bringing this to my attention.)


I believe by default the Mac goes to sleep after a half hour or so if it hasn't had any input.  This is usually evil if you're running some job as it doesn't notice that there is an active process running (since there are typically several active processes doing stuff).

Go to the System Preferences.

Click in the Energy Saver (light bulb icon).

Click the "Sleep" button at the top if you don't see a slider labeled "Put the computer to sleep when it in inactive for:".

Slide this slider over to "Never".

It is okay to let the display go to sleep whenever (I have mine set for 10 minutes or so).

Secure Shell (ssh and Its Friends)

By default ssh on the Mac is not set up to accept incoming connections.  So from the Mac you could use scp to copying files in or out, but you couldn't sit at a remote machine and connect to the Mac.  So, to get ssh started, issue this command:
  sudo /sbin/service ssh start
You should just have to issue that command once and it will then be running the next time you reboot or whatever.

Alternatively, Aaron Whiteman clued me in to the "proper" way to start ssh.  Open "System Preferences", choose "Sharing", and select "Remote Login".  Done!

Aaron also writes:

Look into "SSH Agent" (, which puts your ssh keys in the keychain, doing the same as what ssh-agent/ssh-add do on a unix box.  It also has the added benifits of being able to set env variables before you are completely logged in, so and any other MacOS application have them as needed.

General instructions for generating keys (and getting this going on a generic box) can be found here.

For the Mac, first generate these keys (and put the "pub" part on the machines you want to get to).  Quoting the material from the site mentioned in the previous link, you generate the keys by issuing the command:

  ssh-keygen -t dsa -f ~/.ssh/id_dsa -C ""
This will prompt you for a password that you select (it doesn't have to be your log-in password but it can be).  If this command successfully executes, it should terminate by saying:
  Your public key has been saved in ~/.ssh/
To use the key on other hosts you will be connecting from, copy ~/.ssh/id_dsa key to the other hosts using a command such as:
  scp ~/.ssh/id_dsa you@another-host:.ssh/
Finally, make sure the public key is in the ~/.ssh/authorized_keys file on the hosts you wish to connect to. You can do this with a command such as:
  cat ~/.ssh/ | ssh you@other-host 'cat - >> ~/.ssh/authorized_keys'
Note that could use scp to copy the file to the other host, but that will blow away any existing copy of the authorized_keys file. The command given above is safer in that appends information to any existing file (or creates the file if it doesn't exist).

To get this to work on my cluster, where every node shares a common home directory, in the directory .ssh I issue the following command:

  ln -s authorized_keys
Also on the cluster I have the following in my .bash_profile.
# The following is for getting password-less logins to work.  Much of           
# what I've done here is described at                                           
# but, I did have to tweak things a bit to get them to work here.  One          
# of the changes I needed was to add the hostname to the SSH_ENV                
# variable to ensure there was a unique "environment" for each host.            


function start_agent {
     echo "Initialising new SSH agent..."
     /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
     echo succeeded
     chmod 600 "${SSH_ENV}"
     . "${SSH_ENV}" > /dev/null

# Source SSH settings, if applicable                                            
if [ -f "${SSH_ENV}" ]; then
     . "${SSH_ENV}" > /dev/null
     ps -xuww | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {

That should, I believe, be it.  When you log on to one of the hosts the first time you will be prompted for the password you used to generate the keys.  However, after that, you should be able to access the host without a password for subsequent log-ins.

If you use the application SSH Agent, click the "Add Identity..." button.  You want to add the id_dsa file.  Enter your password to unlock the keys and then you should be done! No more need to enter passwords for your ssh-related connections (well, until you log-out and log-in again or shut down SSH Agent).

If you use SSH Agent, be sure to go to its Preferences and check the "Make Agent Global" box.

Safari Download Directory

It can be annoying to have Safari download a bunch of stuff to the Desktop when you would rather it just go to the /tmp directory (where it will eventually disappear -- this directory is purged on reboot and I believe files older than three days are deleted [see the /etc/daily script for details]).

In the Preferences of Safari, click on "General".

You will see a menu item that says "Save download files to:".  Click on that and select Other...

Then the window comes up type command-shift-G (upper case).  You will be prompted for a directory.  Type "/tmp".

Now click "Select" and hopefully you'll be all set.

Terminal Key Equivalents

The other thing you'll want to do is get your key-equivalents under Terminal to be such that they don't mess you up when you mistakenly do a emacs-ism with the command key instead of the "option" key.

First, you probably want to say you want the option key to act as the meta key.  Do this by going to the "Show Info" window (command-i).  At the top, select "Keyboard" from the menu list.  Click on the box at the bottom that says "Use option key as meta key".

Another thing that is helpful at times: I think by default the emulation is such that if you're looking at a man page or something and then you hit 'q' to get out of it the entire man page disappears and you're original screen is displayed.  No good.  I typically want to see what the man page just said while I struggle over some command.

In the Terminal Preferences (command-,), select "vt100" in the "Declare terminal type ($TERM) as:" menu.

To make it so that you have to hit command-shift-Q to quit Terminal, issue the following command at the command line (but not from the Terminal command line as noted below):

  defaults write NSGlobalDomain NSUserKeyEquivalents '{"Quit Terminal" = "@$Q";}'
Note the dollar sign before the Q.  The "@" means command key and "$" means shift.  IMPORTANT: Issue this command from an xterm when Terminal is not running.  If you don't do that, Terminal may overwrite your tweak the next time it closes.

There are other keyboard tweaks that are important for me.  You can tweak this from the command line (using defaults), but I went directly to the file ~/Library/Preferences/  I now have the following in there:

       <key>Open URL</key>

The first thing (i.e., the Open URL command) makes it so that after you select some text in a terminal window you can open it as a URL by hitting command-shift-U.  The second thing makes it so that you have to hit command-shift-W to close a window (important for those used to hitting meta-W to select text in emacs). I believe you could do the same thing and avoid editing the file if you issue this command:

  defaults write NSUserKeyEquivalents '{"Open URL" = "@$U";"Close" = "@$W";}'
Note that you can't issue these keyboard tweaks one at a time.  The next time you write to the NSUserKeyEquivalents section it will overwrite what was there (perhaps there is an append option but I haven't bothered to look).

More on emacs

The emacs I use comes from mindlube:  You want to click on the link at the top of the page where it says "Download the new 10.3 build".  This should work whether you have the X windows server installed or not.

Since I like larger fonts than what you get by default, I added this to my .emacs file

(modify-frame-parameters (selected-frame) '((font . "-*-courier-medium-r-*--*-140-*-*-*-*-*-*")))

Installing the Apple Script Menu.

For the PostScript item discussed below, life is easiest if you have the Apple Script Menu installed.

Simply use the Finder to go to /Applications/AppleScript then double-click on "Install Script Menu".  If this works properly you should notice something that looks like as S in the upper right corner of your screen (by the clock and the volume-control icon).  Supposedly this S is a scroll.  I can see that.

Alternatively, for those averse to using the Finder, you can enter this at the command line

  open "/Applications/AppleScript/Install Script"
(Yes, those quotes are necessary because of the spaces, or you can remove them and put backslashes in front of the spaces.)

Getting PostScript from JPEG, GIF, PDF, etc.

For this to work (at least as described here), you must first have the Apple Script Menu installed.

If you have the need to convert a JPEG, GIFf, PICT, TIFF, PDF, or TEXT (RTF) file to PostScript, use the finder to select the desired file.  Now click on the Apple Script Menu.  Move the mouse over the Printing Scripts selection and then click on the Convert to PostScript that appears in the other menu.  You should notice in the Finder window that there is now a new version of your file with a .ps appended.  (The original is left unchanged.)

It is also possible to convert this script to an application so that you just drag files to it and it will convert them to PostScript.  (But we won't get into that here.)

From any application on which you can print, you can also print to file (and have the output PostScript or PDF).  From the Apple help information:

It is also worth mentioning that you can convert to PDF too--there is an Apple script for that in the same menu.  It appears that it will not convert PostScript to PDF, but if you've installed the Unix tools mentioned above, you can always use ps2pdf for that.

Getting a Good System Beep.

In the old NextStep OS and in the first release of OS X they had a "system beep" called ChuToy.  That's still my favorite although it isn't in current distributions.  To rectify that, download this file and put it in /System/Library/Sounds/ (calling it ChuToy.aiff).  Then start System Preferences and select ChuToy as the system "alert sound."

As Matthew Schinckel points out, it is probably a better idea to put this in ~/Library/Sounds so that it doesn't get blow away when the system is upgraded.

Synch'ing File Systems.

These days it seems I'm doing a lot of work on various machines and I typically like to run and edit the files locally.  When all is said and done, I want to sync the local file system where I've been working to the central place where I keep my files.  I have written a script which makes this fairly easy to do.  I call this syncer and keep it in a directory on my path.  When I want to sync to the remote host (which can be set on the command line but has a default value specified by the REMOTE variable in the script), I can just issue the command syncer -v (I like running this verbosely).
#!/bin/bash -norc
# A shell script to 'sync' two file systems (or portions of file systems.)

# Default "remote" host with which we're sync'ing.

# Default directory on local machine to which we're reading or
# writing is the current working directory.

# Create default directory on remote host to which we're reading or writing.
# Strip out home directory part if there is any.
REMOTE_DIR=`echo ${LOCAL_DIR} | sed s#${HOME}/##`

# By default we do a get and then a put.

while getopts ":r:l:R:gpvh" opt; do
    case $opt in
	g ) PUT=0 ;;
	p ) GET=0 ;;
	v ) VERBOSE=1 ;;
	* )
	  echo "usage: ${0##*/} [-r remote_dir]  [-R remote_host]"
	  echo "         [-l local_dir] [-g] [-p] [-v] [-h]"
	  echo "  By default ${0##*/} will sync the current working directory with"
	  echo "  the corresponding directory on ${REMOTE}."
	  echo "  Flags:"
	  echo "       r  specify the remote directory"
	  echo "       R  specify the remote host"
	  echo "       l  local directory"
	  echo "       g  only do a 'get' from the remote host"
	  echo "       p  only do a 'put' to the remote host"
	  echo "       v  verbose"
	  echo "       h  print this message"
	  exit 1
shift $(($OPTIND-1))

if [ "$VERBOSE" = "1" ]; then
    echo "remote host:      ${REMOTE}"
    echo "remote directory: ${REMOTE_DIR}"
    echo "local directory:  ${LOCAL_DIR}"

# Get the latest version of the routines from the remote host.
if [ "$GET" = "1" ]; then
    rsync ${GET_FLAGS} -e ssh --exclude '*~' --exclude 'junk*' ${REMOTE}:${REMOTE_DIR} ${LOCAL_DIR}

# Put the latest version of the routines onto the remote host.
if [ "$PUT" = "1" ]; then
    rsync ${PUT_FLAGS} -e ssh --exclude '*~' --exclude 'junk*' ${LOCAL_DIR} ${REMOTE}:${REMOTE_DIR}


For those interested in something much more sophisticated, you should check out unison. (Thanks to Derek Teaney for bringing this to my attention.)

Cluster-Related Topics

Running a Command (Or Commands) on Client Nodes.

I have a cluster with one head node, named headmac.local and four compute nodes named comp1.local, comp2.local, comp3.local, and comp4.local.  Only the head node has a monitor attached to it.  Assuming I'm logged onto the head node, to run a command on each of the compute nodes, I use the following script which I call run-on-clients:

#!/bin/bash -norc
# Simple script to run a command on each of the client nodes.

if [ "$1" = "" -o "$1" = "-h" -o "$1" = "-?" ]; then
    echo usage: ${0##*/} [-h] command_to_be_run
    echo "       (enclose compound commands in quotes)"

echo Command to be run on each node: $*

for i in 1 2 3 4; do

    echo ====== Running on comp$i.local ======
    ssh comp$i.local "$*"


I have another version of this script, called run-on-all, which runs the command on the head node as well.  To make use of this command rather painless, it helps to have set up ssh-agent and ssh-add to do their things in accordance with the instructions that one can find by following the links given in SSH and Friends.  To use this command to check the clock on each of the nodes, you would issue the following command:
   run-on-clients date
You can also issue compound commands by enclosing the desired commands in quotes.  For example, to check on the contents of the /tmp directory on each of the nodes, you could issue the following command:
   run-on-clients "cd /tmp; ls"
With the quote, you can put things on multiple lines and then the semi-colon separator is optional.  Thus the following is equivalent to the previous command:
   run-on-clients "cd /tmp

Installing Packages on Client Nodes.

Since the compute nodes do not have monitors, packages must be installed via the command line.  The current cluster configuration is that a RAID is attached to the head node and each of the compute nodes mount the RAID as a remote volume.  Because compute nodes do not have a monitor attached (and I don't currently run Apple's Remote Desktop software), the GUI software-installer application cannot be run.  There is an installer utility which provides the command-line equivalent of the GUI installer.  Unfortunately it appears that one cannot install software from a remote volume.  It is nice initially to download packages to the RAID, since then the package is at least visible to all the nodes.  There is a way to issue a single command (well, perhaps "single" is a misnomer) to install the package on each of the nodes.  However, first, assume the package Fink 0.7.0 Installer.pkg is installed on the local host.  Then, one can simply issue the command:
   sudo installer -pkg Fink\ 0.7.0\ Installer.pkg -target /
Assuming the package is on the RAID, here is a command which demonstrates how the package Fink 0.7.0 Installer.pkg can be installed on all the client nodes using the run-on-clients command described above.  Here is assumed the package is in the Desktop subdirectory of the home directory (and, of course, that the home directory is mounted by each of the client nodes).
run-on-clients "cd Desktop; tar cvf - Fink\ 0.7.0\ Installer.pkg |
  (cd /tmp; tar xvf -); cd /tmp;
  sudo installer -pkg Fink\ 0.7.0\ Installer.pkg -target /"
Note that packages are not single files.  They are bundles, i.e., they appear as a single entity in the Finder, but they are actually directories filled with various files.  Since we can't install directly from the remote volume, tar is used to make a copy of the package in the /tmp directory.  The package is then installed from there.

Another thing to note about the previous command!  Since the sudo command is used to give superuser privlidges, you will be prompted for your password.  Unfortunately since you are typing this on the local host but the command is being requested by the remote host, your password will be echoed to the screen as you type it.  To avoid this, you can modify the run-on-clients script to turn off echoing, or you can wrap a stty -echo and stty echo around the command.  So, something like this:

stty -echo; run-on-clients "cd Desktop; tar cvf - Fink\ 0.7.0\ Installer.pkg |
  (cd /tmp; tar xvf -); cd /tmp;
  sudo installer -pkg Fink\ 0.7.0\ Installer.pkg -target /"
stty echo
When you type that final stty echo it will not be echoed to the screen (but subsequent input should be).

Path for LAM/MPI.

I use the LAM implementation of MPI to implement parallel code.  On the client nodes it is essential that the path be set correctly to find the necessary LAM/MPI routines.  Therefore, assuming /usr/local/bin is not otherwise on your path (and that is where the LAM stuff has been placed), the following line should be in the .bashrc file:
   export PATH=$PATH:/usr/local/bin

John Schneider's home page.