Published on MacDevCenter (
 See this if you're having trouble printing code examples

Learning the Mac OS X Terminal, Part 2

by Chris Stone

The series continues in Learning the Terminal in Mac OS X, Configuring Email from the Mac OS X Terminal, Customizing the Mac OS X Terminal, and Synchronizing Drives with Cron and the Mac OS X Terminal.

However, none of the first three parts of the series will work in Mac OS X 10.2 (Jaguar) or newer. Jaguar brought several major changes to the OS that require significant changes to the procedure. I'll be posting Jaguar compatible updates to these articles shortly.

In Part 1of this series, you learned how to reschedule default system cron jobs by modifying the system crontab. Here in Part 2, I'll show you how to configure cron to email you a report each time it runs one of these jobs.

First, let's take another look at the pertinent lines in /etc/crontab. Since you only want to look at the file and not modify it, you don't need to use a text editor like pico. Instead, to only display short files like this, use the cat utility, which dumps the entire text file into your window and exits:

[localhost:~] chris% cat /etc/crontab

You might notice a couple of interesting things about this command line. First, since the permissions for /etc/crontab allow anyone to read it (but only root to modify it), using sudo is not necessary.

Second, this command line allows you to access a file in a directory other than your working directory by specifying, in this case, the full (or absolute) pathname to that file. (You didn't first cd to /etc to open crontab, as you did in Part 1.) An absolute path describes the directory hierarchy from the very top of the filesystem (the root directory or "/"), down to the file.

Related Reading

Mac OS X: The Missing ManualMac OS X: The Missing Manual
By David Pogue
Table of Contents
Full Description
Sample Chapter

Finally, because some of the crontab lines might be too long for your window, you'll need to widen the window by dragging its lower right corner to the right until all lines fit without wrapping.

Look now at the line specifying the daily cron job, which, depending on how you configured the time segment in Part 1, begins something like this:

15    17    *     *     *     root    sh /etc/daily ...

Following the first five time fields is the user field. In this case the user field tells cron to run the job as if "root" were doing it. This is necessary here because these maintenance procedures require the full access to the system allowed to the root account.

Following the user field is the sixth and final field, which specifies the actual command for cron to execute. The heart of the command, sh /etc/daily, tells cron to use sh, or the Bourne shell, to run the shell script called "daily," found in the /etc directory.

A shell script is a file holding a series of command lines that can be batch-executed by the shell. Much like an AppleScript, a shell script allows you to create and save long automated procedures that you can run at any time, using a single command. The /etc/daily shell script was written for the Bourne shell, which uses command syntax more apt for shell scripting than the tcsh shell you've been using.

The entire daily cron command line, then, looks like this:

sh /etc/daily   2>&1 | tee /var/log/daily.out  
   | mail -s "`hostname` daily output"  root

cron, in fact, uses the Bourne shell by default to execute its crontab commands, so this command wouldn't work if you ran it manually using the tcsh shell. For the purpose of this article, though, you won't need to modify this command. You won't need to fully understand it either, but this breakdown will give you a general idea of what it does:

sh /etc/daily  2>&1 |	

Run the /etc/daily shell script using the Bourne shell, and send its output and any of its error messages on to the next command.

tee /var/log/daily.out |

Write the input from the previous command to a file and also pass it on to the next command. (That's right -- you can always see the results of the latest daily cron job by viewing /var/log/daily.out.)

mail -s "`hostname` daily output"   root

Comment on this articleThis is the place for your questions and comments as you work with Mac OS X's Terminal application.
Post your comments

Using the input from the previous command as the body, create an email message with the subject "localhost daily out" and send it to root. This, then, is the command that starts the cron report's journey on its way to your mailbox.

The first step in getting the reports delivered is to direct them to your mailbox, instead of root's. To do this, you could conceivably replace "root" in this command with your account name, but wouldn't it would be simpler if you could just tell the system to redirect all mail addressed to root to your mailbox instead? By using a .forward file, you can do just that.

A .forward file is just a text file containing nothing but the name of the account to which you want the mail forwarded (in this case, your account name). Once the .forward file is placed in the home directory of the original addressee (in this case, root), the mail gets forwarded as expected.

By default, the Mac OS X root home directory already contains a .forward file, but this one redirects mail not to another user, but into thin air. This happens because instead of an account name, root's .forward file contains the pathname /dev/null, which is the location of a Unix black hole. Streams of data directed to /dev/null, mail messages included, simply disappear. Since OS X's designers figure most users won't be accessing root's mail, they used this method to ensure mail doesn't pile up at the door while no one's home, eventually filling up your hard disk.

Let's get back to Terminal, then, to edit root's .forward file. You've probably already noticed that there is no "root" directory in /Users -- so where is root's home? The easiest way to find any user's home directory is by using the ~ shortcut (for home directory), along with the account name. Therefore, to change your working directory to root's home directory, enter this:

[localhost:~] chris% cd ~root
[localhost:~root] chris%

Okay, so now you're in ~root, but where is that really? Remember, you can find out with pwd:

[localhost:~root] chris% pwd

Next, use ls to view the contents of ~root:

[localhost:~root] chris% ls 
Desktop   Documents Library 

The contents of your ~root directory might look different, but in any case, you still won't see a .forward file. What happened to it? One clue is the first character of the file's name, which is a dot ("."). An initial dot is the Unix way of marking filesnames as invisible to the shell (and to the Finder as well). But it's easy enough to see such hidden files in the CLI; just use the -a option flag with ls.

Option flags allow you to modify the behavior of commands. The -a option flag for ls tells ls to display "all" items in the working directory, including hidden ones (also known as "dot files"). Simply type the ls command, add a space, and then type the -a flag:

[localhost:~root] chris% ls -a
.		          .forward		.tcsh_history 	  Library
..		          .nsmbrc 		Desktop
.CFUserTextEncoding	  .ssh			Documents
[localhost:~root] chris%

Again, your view might be different, but you will now see ~root/.forward. You'll next want to edit it using pico. Since this file is owned by root, you'll need to use sudo as well:

[localhost:~root] chris% sudo pico .forward

First, delete the file's single line by pressing control + K. Next, type in your account name (the name that's just before the "%" in the prompt; "chris" in this case):

As you learned in Part 1, save the file with control + O, press return to confirm the name, and then press control + X to exit pico. You're done with the .forward file.

The next step in the procedure involves getting the mail transfer agent sendmail to launch successfully when beckoned by the mail user agent mail (which, as you remember, is invoked by the cron job).

Mail user agents (MUAs) are the kinds of applications that allow you to personally send, receive, and otherwise work with your email messages. Outlook, Eudora, and Mac OS X's Mail application are other familiar examples of MUAs.

Mail transfer agents (MTAs), on the other hand, are the not-so-familiar applications that receive the messages from the MUA and pass them on to other users on the same machine, or to MTAs on other machines for ultimate delivery to users elsewhere. The sendmail MTA included with OS X is one of the most popular, used on servers large and small across the Internet.

Since you are not running your own mail server at this point, you don't need sendmail to be running at all times. Instead, you only need to ensure that sendmail launches when invoked by mail to send the cron reports. Used this way, sendmail quits itself once delivery is made.

For sendmail to successfully launch, however, one issue needs to be "fixed" on your system. As a security measure, sendmail will not run with OS X's default permissions (termed "privileges" in the Finder), namely those for the root directory.

This fix involves one simple change: eliminating write privileges for the group assigned to the root directory. The CLI makes it very easy to view and change the various permission settings for any item, but the procedures are still too involved to detail here. (Of course, Mac OS X: The Missing Manual does include an in-depth look at permissions and the CLI.)

Instead, I'll zero in on the single command line required to get sendmail going:

sudo chmod  g-w /

Since you're modifying the settings for a root-owned directory, the command line starts with sudo. Next comes the chmod command, for "change (file) modes." File modes are the settings that specify whether an item can be read or written to, for example, and by which kind of user -- the owner of the item, its group, or any user of the machine. (These settings correspond, of course, with the Privileges settings that are accessible via Finder's Inspector.)

Following a space are chmod's "arguments," the first of which specifies the modes to be changed (option flags are just another kind of argument, by the way). This argument says to take the group ("g") and remove ("-") its permission to write ("w") to the file or directory specified in the next argument (again followed by a space), which in this case is the root directory, ("/").

Your next step, then, is to run the command line:

[localhost:~] chris% sudo chmod  g-w /

Once you do, sendmail should work fine. However, you should know that Mac OS X upgrade installers and some application installers change the root directory back to group-writable, so you'll need to run the chmod command line whenever this happens.

To test everything so far, try sending mail from the CLI. Use the mail command to send mail to root (which, at this point, will get forwarded on to you) like this:

[localhost:~] chris% mail root

You're now working inside the mail CLI application, so you'll see no more tcsh shell prompts until you exit mail. Enter any subject you would like and press return. Type in your message at the cursor. To end your message, send it, and exit mail, press return, type a period, and press return again. You'll then return to your shell prompt:

After a few moments, check your mail by entering the mail command again, but this time with no arguments. Until the message arrives, you'll only see that your box is empty when you run mail:

[localhost:~] chris% mail
No mail for chris

However, once it arrives you'll see something like this:

[[localhost:~] chris% mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/mail/chris": 1 message 1 new
>N  1 chris                 Sat Jan  5 15:30  13/374   "Test"

You're back in the mail application, but this time to view your new message. Press return at the "&" prompt to have a look:

Message 1:
From chris  Sat Jan  5 15:30:01 2002
Date: Sat, 5 Jan 2002 15:30:00 -0800 (PST)
From: Chris Stone <chris>
To: root
Subject: Test

This is only a test.

& q
Saved 1 message in mbox
[localhost:~] chris%

As you can see, the test message stays in your local Unix mailbox when you quit mail. Note that this and any other messages there will disappear as a result of the following procedure. However, if this tutorial is new to you, it's very unlikely that you have other messages there anyway. (Of course, your POP and IMAP mail will stay safe and sound.)

You're now ready to set up your GUI Mail application so it can access your local Unix mailbox. Since you will be modifying the folder in which Mail stores its mail, ~/Library/Mail, you should first make a backup of it to, say, your Documents folder:

[localhost:~] chris% cp -R Library/Mail/ Documents/Mail

Here are some important points about this command line:

Something else you should know about cp is that it does not properly copy files with resource forks, so you should never use it for that. You'll never have a problem copying Unix and Cocoa applications and related files, which don't contain resource forks, but if you are unsure, use the Finder to copy (or have a look at Mac OS X: The Missing Manual for an explanation of using CpMac, which does handle resource forks reliably).

The next step is to make the directory that Mail requires before it can create a Unix mail account. The directory must exist in ~/Library/Mail/ and be named "UNIX:@". To create a directory from the command line, use the mkdir command, followed by a space and the name of the new directory.

However, if there is no Mail directory already inside ~/Library, the command will return an error. To prevent this possibility, use mkdir's -p option flag, which will create any intermediate directories for you if they are missing.

[localhost:~] chris% mkdir  -p Library/Mail/UNIX:@

Next you'll need to open Mail and create a Unix mail account, which requires just a few simple steps:

  1. Open the Mail application, found in /Applications.

    Sure, you can just double-click its icon to open it in the Finder, but since you're in Terminal anyway, how about opening it from there? To do so, just use the open command (don't forget to include the normally-hidden extension at the end):

    [localhost:~] chris% open /Applications/

    Mail launches immediately, just as if you had opened it from the Finder.

    If you've never used Mail before and have no email account info entered in your System Preferences, you'll be prompted to set up an initial account. At a minimum, you'll need to enter an email address, so enter anything you would like; it won't affect the setup of your Unix mail account.

    You can safely click through the other prompts for server and other info, and to import mail from other applications. None of this is needed for the task at hand.

  2. Create a new Unix mail account.

    From Mail's Mail menu, select Preferences, and then click the Accounts icon. In the Accounts pane, click Create Account. To configure the account, you'll at least need to select the account type (Unix Account), enter a description (Local), and enter something -- anything, really -- in the SMTP Host field.

    Of course, if you need to set up a bona fide Unix account, all of these fields mean a great deal. However, for the purpose of only accessing your local Unix mail, this is all you need to configure:

  3. Click OK, close the Preferences window, and you're all set.

    If you are already using Mail to check your regular POP and IMAP accounts, this additional account will not affect those in any way, except that new mail from your Unix account will show up in your default inbox. Of course, if you would like, you could create a new mailbox and a rule to have the incoming cron reports be placed there instead.

Now that everything's in place, you can perform a test. Send a new mail message to root:

[localhost:~] chris% mail root
Subject: Test 2
This is only a test, again.
[localhost:~] chris%

Switch to Mail, and then click Get Mail until you see the message has arrived in your Inbox:

If you see the test message in your inbox, then you're done. The next time cron runs one of the maintenance jobs, you'll see the report in your inbox as well. For example, the daily cron job report will look something like this:

Now that these regular reports will be coming in, you'll probably want to be able to understand them. In Part 3, you'll get a closer look at the scripts themselves to learn how to read the reports they generate.

Also in Part 3, I'll show how a Macintosh with a persistent Internet connection can send its reports to any email address. Until then, keep checking to see that you're receiving the reports as expected, and always feel free to submit your comments or questions to our TalkBack section.

I'd like to thank Scott Gever for his techincal help with this series.

Chris Stone is a Senior Macintosh Systems Administrator for O'Reilly, coauthor of Mac OS X in a Nutshell and contributing author to Mac OS X: The Missing Manual, which provides over 40 pages about the Mac OS X Terminal.

Return to the Mac DevCenter.

Copyright © 2009 O'Reilly Media, Inc.