TweetFollow Us on Twitter

The Shell: Automation

Volume Number: 21 (2005)
Issue Number: 4
Column Tag: Programming

Mac In The Shell

by Edward Marczak

The Shell: Automation

Doing Something Useful

Automation: it's everything. There's little other reason to have computers in a business. While that may be a slight oversimplification, let's agree that it's a compelling reason to have them around. Sometimes, you automate smaller tasks so you can free up your time to automate the bigger tasks.


Last month, we touched on some basic shell commands. This month, we'll take those, and a new one or two, and create a script that helps us automate some system maintenance.


The March "Mac In The Shell" talked about how the bash shell works with files, interprets pattern matching characters, and can get you help. As you've been practicing your shell-fu, hopefully you've found some new commands that are simply too useful to give up. For now, though, they're just commands. By chaining commands together, or letting them interact in any way, they become greater than the sum of their parts. Unix is built on this philosophy. You'll find that most commands are small, single-purpose programs. Each program can concentrate on being great at one thing. Then, we can write a script or function, or use i/o redirection to have the output of one program act as input to another.

Here's an example: 'wc' is the "word, line, character, and byte count" program. You can feed it a file, and it will happily spit back these statistics:

$ wc 
      93     299    2350

'' has 93 lines, 299 words and 2350 bytes. Sometimes, you just have to know these things. Additionally, 'wc' accepts switches that tailor the output to your needs. If you just need to know how many lines, use the '-l' (ell) switch:

$ wc -l 

But what if we need to know how many lines in a directory listing? The 'ls' command doesn't have an option for that. That's why we let each program do what it does best! We'll let the 'ls' command list the directory, and have 'wc' use the output from 'ls' as its input. An example from my home directory:

$ ls -l | wc -l

(Yes, that's about 20-or-so too many, OK?) The "|" character is the pipe, or more properly, "pipeline." I'll give a quick overview of the going-ons here, but for more information and usage examples, see my article in the December 2004 MacTech.

Most of us take for granted the fact that we have a keyboard in front of us, and when we type, characters show up on the screen. Additionally, few people run and remember that this is supposed to be emulating a real terminal. Well, in some ways, the underlying system does still treat each terminal session as if it were a real, physical terminal hooked into it. It does this through the use of virtual terminals (or, 'pseudo-terminals'). I suppose "Virtual" just didn't roll off the tongue.

Whether you're using a real text-terminal connected via wire to an AIX server, or locally on your OS X box, some things are constant. We all have learned (or should have, at some point), about "Input, Process, Output" in computer information handling. When you're running a shell, there are defaults for 'input' and 'output', called 'standard input' and 'standard output'. Standard input is taken from your typing at the keyboard. Standard output is the screen. There are several ways to redirect this input and output, and the pipe is one of the ways to do that.

In the previous example, we could certainly have done this:

$ ls -l > filelist.txt
$ wc -l filelist.txt

The '>' character lets us redirect standard output. Instead of the output from 'ls' printing to the screen as it usually does, we redirect it to a file. Then we can have 'wc' operate on the file. However, it's a lot easier and neater to use the pipe redirector to do it all in one step, isn't it?

The Automator

Apple apparently agrees with my stance on automation, as evidenced by the 'Automator' feature of Tiger. However, in reality, you are the automator. We're not quite up to the stage where operating systems and applications really watch what you do over time, and then modify behavior purely on your actions. So, you have to automate actions. Automator in Tiger is a great step in this direction, and it will even call shell scripts for you!

A fair amount of automation is already built into OS X for you. Shell scripts that clean up log files, rebuild databases, and more run from cron. 'cron' is a system utility that runs shell scripts ("jobs," more precisely, as it can really kick off any program, such as perl, PHP or python) on a set schedule. We learned how to massage cron and have it run our own jobs from Josh Wisenbaker in the March issue of MacTech. Despite the maintenance that already exists in OS X, there's always more work to do. Here's an example of a script that I like to run on OS X Server, but there are parts that will be useful on OS X as well (remember that OS X makes a great server, too, as it will run pretty much anything that OS X Server will). I'll also introduce one of my favorite commands.

What We Need To Know

An OS X Server box that is tasked with just about everything that it can do has a lot of responsibilities: DNS, e-mail, file serving, web serving, and more. There are certain critical parameters that we should be kept abreast of, such as free disk space, if there's anything stuck in the mail queue, if any binaries have been altered, etc. I like knowing this summary every morning. So, how can we get this in a simple, single source? A shell script that e-mails its output to us, of course!

First, running out of disk space pretty universally bad. OS X, with its "I advocate a single partition" disk scheme makes watching disk space even more critical. 'df' is the tool we use to find out how much disk space is used and free on local, mounted volumes. I like using the '-h' 'human readable' switch:

$ df -h
Filesystem                  Size     Used     Avail     Capacity     Mounted on
/dev/disk4                  173G      73G      100G          42%      /
devfs                       110K     110K        0B         100%      /dev
fdesc                       1.0K     1.0K        0B         100%      /dev
<volfs>               512K     512K        0B         100%      /.vol
/dev/disk5                  234G     221G       13G          95%      /Volumes/Data2
automount -nsl [436]          0B       0B        0B         100%      /Network
automount -fstab [449]        0B       0B        0B         100%      /automount/Servers
automount -static [449]       0B       0B        0B         100%      /automount/static
/dev/disk10                 932G     444G      487G          48%      /Volumes/Data1

It's good to know about all of our volumes, but the super-important one is our system volume. The system volume is represented by the "/" on the first line of output above. We can see that of the three real volumes on this system, one is getting pretty close to being full (Data2 at 95% capacity = 'only' 13GB left!).

We can find out about what's in the mail queue with the 'mailq' command. This will tell us what has been deferred in a sendmail or postfix queue. I just happen to have an example: (see bottom figure.) Here, we see this server has three messages that are still waiting to be delivered for one reason or another. Sometimes, you'll find that messages to a certain destination are backed up because the mail host is genuinely down or unreachable. Other times, you'll find that routing is borked on your end, and the queued messages have a bit more of a random pattern.

There are several systems that will take a hash of your files, and then later tell you if anything has changed. This has become known as a tripwire function, named so after the application "Tripwire" that basically fathered this genre of utility. Naturally, the goal of running a system like this is security. If someone/something replaces your 'ls' binary with one that hides certain files, you want to know about it. I run tripwire on most of my Mac OS X boxes, more as a notification of things that have been installed than for the paranoid security reasons, so that's what I'll discuss here. Of course, there are others, such as radmind (which also can do a lot more than simply compare files), and Checkmate. We'll be discussing tripwire in a future column, but for now, I'm just going to go though the motions.

First, I go dump all of the old reports from the reports directory:

rm -f /usr/local/tripwire/report/*

Then, we want to run the tripwire and generate our new report:

/usr/local/tripwire/bin/tripwire -m c

Finally, we can update the database with the new changes, so we're reset for the next run:

/usr/local/tripwire/bin/tripwire -m u -a -r 
   /usr/local/tripwire/report/`ls /usr/local/tripwire/report` 
   -P "My really long passphrase" -v

What's a system without backup? Even if I have a tape backup running, I like to a) copy certain files locally on the same

$ mailq
-Queue ID-          -Size-           -Arrival Time-                -Sender/Recipient-
0C4125B83A8         2615             Fri Apr  1 02:59:56           MAILER-DAEMON
 (Name service error for type=MX: Host not found, try again)

B8E2A4EF0EF         2628             Thu Mar 31 01:28:52           MAILER-DAEMON
 (Name service error for type=MX: Host not found, try again)

D7ACD4439EE         3204             Wed Mar 30 07:59:25           MAILER-DAEMON
 (connect to[]: Operation timed out)

-- 9 Kbytes in 3 Requests.

disk, simply for ease of access, and b) get files off of the server to a remote location. I use rsync for both of these tasks. If you plan on implementing this as outlined here, please note: you must replace the Apple-supplied rsync with RsyncX if you want to sync files with resource forks ( So, what do we want to copy here? I like to get /etc locally:

rsync -a -q --delete /private/etc/ /backup/etc/

On a server running mail, I like to grab the mail store:

rsync -a -q --delete /var/imap/ /backup/var/imap/
rsync -a -q --delete /var/spool/imap/ /backup/var/spool/imap/

Lastly, I like to move certain files off-site. rsync will do that, too:

rsync --delete -l -a -v /Shares/shared/
   /Volumes/Backup/rsync-bu/shared/ --eahfs -stats

Lastly, I make sure I clean up any directories that may be building up files. Some of my servers run OpenBase databases (for the excellent DayLite by MarketCircle). One of the options for OpenBase is an automatic backup. Great! The only problem with this is that, while it's happy to make the backup, it doesn't know when to get rid of it. Files can pile up pretty quickly, which means disk space can disappear quickly, too. Here's where my favorite command comes in. The 'find' command is one of those commands that certainly fits the philosophy that we discussed earlier. However, it's also a bit of a Swiss Army knife in that it will handle certain tasks even though other utilities would do the job just fine. Yes, this will be talked about in more depth next month. The find command lets us find files based on several different criteria. One parameter is the age of the file. I want to delete any OpenBase backup files that haven't been modified for 7 days:

find /Library/OpenBase/Backup/ -mtime +7 -delete

This will rid us of files that have not been modified in 7 days in the /Library/OpenBase/Backup directory. find is very powerful, and can be a system admin's best friend on many occasions. However, while you're learning, please note: find is also one of those commands that you have to be a little careful with, and it will descend recursively into all of the directories below the path you specify. Used with the "-delete" switch, it can do damage! As a last measure in my old-file-removal routine, I like to also dump old quarantined mail caught by amavis:

find /var/quarantine/ -mtime +7 -delete

Put It All Together

Now that we know exactly what we want to do, let's turn it into a shell script. To do this, we need a text editor. I typically reach for vi. Apple tends to lead people through these examples with pico. While there are some GUI tools that will also do the trick (TextWrangler and SubEthaEdit come to mind), this is a column on using the terminal, and that's what we'll do! Remember: vi, emacs and pico can easily be used over ssh, with no access to a GUI at all - TextWrangler and SubEthaEdit can't!

Creating a shell script involves a few steps. We'll call this one ''. Get into vi to edit this file by typing "vi". Press the 'i' key to go into insert mode. You should now see the word 'INSERT' at the bottom of your screen. First thing we need to do is to declare what kind of script this is:


Alternatively, this could have been a perl script (#!/usr/bin/perl), PHP, Python, a different shell such as tcsh, or other variety. When you invoke this as an executable, the shell looks at this first line to determine which interpreter to use to run your script. This is a nice shorthand way to execute a script, rather than have to specify everything on the command-line. Then, we'll add each of our commands, one by one, with some comments. So, the whole thing looks like this:


# Our nightly maintenance routine
# Problems?  Contact Joe Admin
# version 1.0 - 2005-04-04

# Let the logs know that we've begun
logger -p local0.notice -i -t Nightly Starting nightly routine

# Get disk stats
/usr/bin/df -h

# See what's in the mail queue

# Run tripwire reports
logger -p local0.notice -i -t Running tripwire reports
rm -f /usr/local/tripwire/report/*
/usr/local/tripwire/bin/tripwire -m c
/usr/local/tripwire/bin/tripwire -m u -a -r /usr/local/tripwire/report/`ls 
   /usr/local/tripwire/report` -P "My really long passphrase" -v

# Backup files
logger -p local0.notice -i -t Backing up files
/usr/bin/rsync -a -q --delete /private/etc/ /backup/etc/
/usr/bin/rsync -a -q --delete /var/imap/ /backup/var/imap/
/usr/bin/rsync -a -q --delete /var/spool/imap/ /backup/var/spool/imap/
/usr/bin/rsync --delete -l -a -v /Shares/shared/
   /Volumes/Backup/rsync-bu/shared/ --eahfs -stats

# Clean up old files
find /Library/OpenBase/Backup/ -mtime +7 -delete
find /var/quarantine/ -mtime +7 -delete

logger -p local0.notice -i -t Nightly maintenance complete

Lines that start with a hash mark ('number sign') are comments and are ignored by the bash interpreter. This script will execute, one line at a time from the beginning to the end. It sends its output to standard output. However, we're going to run this from cron, which, by default, will take any standard output and e-mail it to the owner of the crontab.

Let's save this script. If you're still with me in vi, press the escape key once, and then type ":" (colon, not semi-colon - so hit the shift key, too). The colon character puts you into command mode. When you see the colon character at the bottom of your screen, type 'wq' and press enter. That's short for 'w'rite the file and then 'q'uit. You'll be back at the command line. So, just one more thing: we need to mark this script executable. Type "chmod u+x" and press return. This adds the executable bit to the permissions of our script. Without it, the shell won't (easily) execute our file.

I want to test this script, but a word of warning first: Do NOT run this script as-is. It needs to be adjusted for your environment. The 'logger', 'du' and 'mailq' lines are harmless. Everything else needs to be changed to some sane value. You may or may not have tripwire installed. If you do not, simply remove that section. What directories are you concerned with backing up? Naturally, the 'Clean up old files' section will remove files! Make sure you either remove these lines, or point them at a directory that makes sense for you!

Did you read all that? Really? OK. Now we'll....wait. Go read the preceding paragraph again....I'll wait.......OK, thanks. If you're really ready, let's run this sucker. At the command line, type "./" (don't type the quotes), press enter, and you'll see a good deal of info come spewing back at you. You can also check /var/log/system.log and you'll see lines like the following produced by our script:

Apr  4 18:28:13 localhost Nightly[668]: maintenance complete

The output you see on your screen is the same information that will get sent to you via e-mail.

Last comments on this script: you may have noticed that I prefixed each command with its full path in the script, but usually don't bother when I simply call it on the command-line. Two reasons: First, we want to be sure we get the right binary, if there are multiple on our system. Secondly, it's a bit of a (good) habit: depending on how your script gets called, it may not have access to the environment, which means no path variable. So, absolute paths should go everywhere in a script like this.

Additionally, if you ever need to put a password or passphrase into a shell script (rare, but it happens), you should mark the file only readable by root ("chown root", followed by "chmod 700").

Schedule It

We don't want to have to run this manually every day, do we? (Shouts of, "No!" heard nearby) So, let's get this into cron.

A script like this will need to run privileged as root. There are a few ways to do this. We could drop it in root's crontab. We could drop a line in the system crontab. Or, as a variant, we could ignore messing with cron directly at all. They're all good methods, and which you choose really depends on your style. However, OS X already schedules maintenance tasks that run on daily, weekly and monthly schedules. We're going to take advantage of that.

We need our script to run on a daily basis, so let's move our script to the appropriate place:

sudo mv /etc/periodic/daily/
sudo chmod 550 /etc/periodic/daily/
sudo chown root:wheel /etc/periodic/daily/

That's all! Now, the system will run our script as part of its regular 3:15am daily maintenance.

Closing time

This month we learned how to create a simple shell script. This script runs through its commands in order, with no conditions or loops. I will say that this exercise glossed over a few small details, and completely ignored the fact that OS X Server already has a decent way to monitor free disk space (called "diskspacemonitor"), and do some of what we talked about (see /var/log/daily.out). This example script certainly isn't perfect, nor was it meant to be all-inclusive of every system administration ill. It introduced you to a few new commands. More importantly, it should give you ideas. It should allow you to create something that works for you.

You can now start to automate some tasks that are repetitive in your computing environment. Perhaps you need stats on processes chewing up too much CPU. Perhaps you need to monitor open file count. Whatever it is, now you have a way. Ask questions - here if you'd like. You can send in questions to Once you start automating, you start getting some time back. Time to read that new book on OS X, time to spend with friends and family, time to watch that new Battlestar Galactica episode, or time to rest. All fine goals, no?

Ed Marczak owns and operates Radiotope, a technology consulting company that asks, "how can we help you automate that?" Automate at


Community Search:
MacTech Search:

Software Updates via MacUpdate

OmniPlan 3.0 - Robust project management...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Yummy FTP 1.11 - FTP/SFTP/FTPS client fo...
Yummy FTP is an FTP + SFTP + FTPS file transfer client which focuses on speed, reliability and productivity. Whether you need to transfer a few files or a few thousand, schedule automatic backups, or... Read more
Tweetbot 2.1 - Popular Twitter client. (...
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
MacPilot 8.0 - Enable over 1,200 hidden...
MacPilot gives you the power of UNIX and the simplicity of Macintosh, which means a phenomenal amount of untapped power in your hands! Use MacPilot to unlock over 1,200 features, and access them all... Read more
Typinator 6.7 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
Adobe Lightroom 6.2 - Import, develop, a...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
ForeverSave 2.1.4 - Universal auto-save...
ForeverSave auto-saves all documents you're working on while simultaneously doing backup versioning in the background. Lost data can be quickly restored at any time. Losing data, caused by... Read more
VueScan 9.5.27 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
AirPort Utility 6.3.6 - Set up and manag...
Note: Most recent release available only within OS X 10.11 El Capitan update. Use AirPort Utility to set up and manage your Wi-Fi network and AirPort base stations, including AirPort Express, AirPort... Read more
Quicksilver 1.3.1 - Application launcher...
Quicksilver is a light, fast and free Mac application that gives you the power to control your Mac with keystrokes alone. Quicksilver allows you to find what you need quickly and easily, then act... Read more

YAMGUN (Games)
YAMGUN 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: The invasion has begun! Protect the walls of the citadel against waves of enemies! But watch out, you will soon run out of ammo...... | Read more »
Royal Bounty HD (Games)
Royal Bounty HD 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: New World Computing Approved "Hi Guys! looks good so far! keep up the good work. I worked on HoMM 3 and 4 creating all of the... | Read more »
Swords & Crossbones: An Epic Pirate...
Swords & Crossbones: An Epic Pirate Story 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
Camel Up (Games)
Camel Up 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: | Read more »
The Martian: Bring Him Home (Games)
The Martian: Bring Him Home 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Based on the best selling novel and critically acclaimed film, THE MARTIAN tells the story of Astronaut Mark... | Read more »
This Week at 148Apps: September 21-30, 2...
Leap Into Fall With 148Apps How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you're looking for. The ones we love become Editor’s Choice, standing out above... | Read more »
Tweetbot 4 for Twitter (Social Networki...
Tweetbot 4 for Twitter 4.0 Device: iOS Universal Category: Social Networking Price: $4.99, Version: 4.0 (iTunes) Description: *** 50% off for a limited time. *** | Read more »
Mori (Games)
Mori 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Stop, rewind and unwind with Mori. Time is always running, take a moment to take control. Mori is an action puzzle game about infinitely... | Read more »
100 Years' War (Games)
100 Years' War 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: | Read more »
Tower in the Sky (Games)
Tower in the Sky 0.0.60 Device: iOS Universal Category: Games Price: $1.99, Version: 0.0.60 (iTunes) Description: | Read more »

Price Scanner via

Save up to $350 with Apple refurbished iMacs
Apple has Certified Refurbished iMacs available for up to $350 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27″ 3.5GHz 5K iMac – $1949 $350 off MSRP - 27... Read more
Mac Pros on sale for up to $300 off MSRP
B&H Photo has Mac Pros on sale for up to $300 off MSRP. Shipping is free, and B&H charges sales tax in NY only: - 3.7GHz 4-core Mac Pro: $2818.99, $181 off MSRP - 3.5GHz 6-core Mac Pro: $3699... Read more
5K iMacs on sale for up to $150 off MSRP, fre...
B&H Photo has the 27″ 3.3GHz 5K iMac on sale for $1899.99 including free shipping plus NY tax only. Their price is $100 off MSRP. They have the 27″ 3.5GHz 5K iMac on sale for $2149, $150 off MSRP... Read more
Twelve South Redesigns BookArc For Today’s Sm...
Twelve South has announced a redesigned version of their very first product, BookArc for MacBook. Tailored specifically for the newest generation of MacBooks, BookArc holds the new, smaller Apple... Read more
Phone 6s Tips & Tricks – Tips Book For iP...
Poole, United Kingdom based Tap Guides Ltd. has announced the release and immediate availability of iPhone 6s Tips & Tricks, an in-depth eBook available in the iBookstore that’s priced just $2.99... Read more
13-inch 2.5GHz MacBook Pro on sale for $994,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $994.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $105 off MSRP. Price valid... Read more
Is The iPad Pro Really A Serious Laptop Repla...
Probably not, at least for productive professionals and other power users. Steve Jobs declared that we’d entered the “post-PC Era” with the advent of the original iPad in 2010, a phrase we don’t hear... Read more
Wednesday Deal: 13-inch Retina MacBook Pros f...
Adorama has 13″ Retina MacBook Pros on sale for up to $130 off MSRP. Shipping is free, and Adorama charges sales tax for NY & NJ residents only: - 13″ 2.7GHz/128GB Retina MacBook Pro: $1199.99 $... Read more
uBar 3.0 for Mac OS X – Custom Dock Replaceme...
Brawer Software has announced the release of uBar 3.0, an important update to their popular app and window manager for Mac OS X. uBar allows users to position it whichever side of the screen they... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
Apple has Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz MacBook Pros... Read more

Jobs Board

*Apple* Retail - Multiple Customer Support P...
Job Description:Customer SupportSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the Read more
Software Engineer, *Apple* Watch - Apple (U...
…the team that is revolutionizing the watch! As a software engineer on the Apple Watch team, you will be responsible for building world-class applications and frameworks Read more
*Apple* Online Store UAT Lead - Apple (Unite...
**Job Summary** The Apple Online Store is a fast paced and ever evolving business environment. The User Acceptance Testing (UAT) lead in this organization is able to Read more
Hardware Systems Integration Engineer - *App...
**Job Summary** We are seeking an enthusiastic electrical engineer for the Apple Watch team. This is a design engineering position that entails working with Read more
Touch Validation Design (EE) - *Apple* Watc...
**Job Summary** Help launch next-generation Touch Technologies in Apple products. The Touch Technology team develops cutting-edge Touch solutions and technologies that Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.