Tag Archives: bash

Mac OS X Mac OS X Server Mac Security Mass Deployment

A Well Caffeinated Command Line

One of the big things in OS X Mountain Lion is how the system handles sleeping and sleeping events. For example, Power Nap means that now, Push Notifications still work when the lid is shut provided that the system is connected to a power source. This ties into Notification Center, how the system displays those Push Notifications to users. Sure, there’s tons of fun stuff for Accessibility, Calendar, contacts, Preview, Messages, Gatekeeper, etc. But a substantial underpinning that changed is how sleep is managed.

And the handling of sleep extends to the command line. This manifests itself in a very easy to use command line utility called caffeinate. Ironically, caffeinate is similar to the sleep command, except it will keep the GUI awake in the event that Mountain Lion wants to take a nap (I’m not saying it should not be used as a replacement for sleep btw).

To just get an idea of what it does, run the caffeinate command, followed by a -t operator and then let’s say the number 2:

caffeinate -t 2

The system can’t go to sleep automatically now, for two seconds. The command will sit idle for those two seconds and then return you to a prompt. Now, extend that to about 10000:

caffeinate -t 10000

While the command runs, manually put the system to sleep. Note that the system will go to sleep manually but not automatically. Now, there are different ways that a Mac can go to sleep. Use the -d option to prevent the display from sleeping or -i to prevent the system from going into an idle sleep. The -s is similar to -i but only impactful when the AC power is connected while the -u option deals with user inactivity.

Overall, a fun little command. It’s just another little tool in an ever-growing arsenal of options.

cloud Mass Deployment Ubuntu Unix

Scripting in Google ChromeOS

I recently got my hands on one of those Google ChromeBooks (Cr-48). Interesting to have an operating system that is just a web browser. But, as anyone likely reading this article already knows, the graphical interface is the web browser and the operating system is still Linux. But what version? Well, let’s go on a journey together.

First, you need ChromeOS. If you’ve got a ChromeBook this is a pretty easy thing to get. If not, check http://getchrome.eu/download.php for a USB or optical download that can be run live (or even in a virtual machine). Or, if you know that you’re going to be using a virtual machine, consider a pre-built system from hexxeh at http://chromeos.hexxeh.net/vanilla.php. I have found the VMware builds to be a bit persnickety about the wireless on a Mac, whereas the VirtualBox builds ran perfectly. I split my time between the two anyway, so I’ve just (for now) been rocking VirtualBox for ChromeOS. When you load it for the first time it asks for a Google account. Provide that, select your network adapter, choose from one of the semi-lame account images ( for the record, I like the mad scientist one) and you’re off to the races.

Next, we need a shell. When you first log in, you see a web page that shows you all of the Chromium apps you have installed. By default, you’ll see File manager and Web Store. If you’ve used the OS X App Store then the Chrome Web Store is going to look pretty darn familiar. My favorite for now is Chrome Sniffer. But all of these kinda’ get away from where we’re trying to go: get a scripting environment for Chrome OS.

Chrome comes with 2 types of shell environments. The first is crosh. To bring up a crosh environment, use Control-Alt-t. This keystroke invokes the crosh shell. Here, type help to see a list of the commands available. Notice that cd, chmod, etc don’t work. Instead, there are a bunch of commands that a basic user environment might need for troubleshooting primarily network connections. “But this is Linux” you ask? Yup.

At the help output you’ll notice shell. Type shell and then hit enter. The prompt will change from crosh> to chronos@localhost. Now you can cd and perform other basic commands to your hearts delight. But you’re probably going to need to elevate privileges for the remainder of this exersize. So let’s type sudo bash and just get there for now. If you’re using a ChromeBook, the root password might be root, or if you’re using a downloaded vm from hexxeh then it might be facepunch (great password, btw).

Provided the password worked, the prompt should turn red. Now, if you’re using a hexxeh build then the file system is going to be read-only. You won’t be able to change the root password nor build scripts. But otherwise, you should be able to use passwd to change the password:

passwd chronos

Once you’ve got slightly more secure shell environment (by virtue of not using the default root password), it is time to do a little exploring. Notice that in /bin, you see sh, bash, rbash and the standard fare of Linux commands (chmod, chown, cp, attr, etc. Notice that you don’t see tcsh, csh or ksh. So bash commands from other platforms can come in, but YMMV with tcsh, etc. Running ps will give you some idea of what’s going on process-wise under the hood:

ps aux

From encrypts to crypto to the wpa supplicant, there’s plenty to get lost in exploring here, but as the title of the article suggests, we’re here to write a script. And where better to start than hello world. So let’s mkdir a /scripts directory:

mkdir /scripts

Then let’s touch a script in there called helloworld.sh:

touch /scripts/helloworld.sh

Then let’s give it the classic echo by opening it in a text editor (use vi as nano and pico aren’t there) and typing:

echo "Hello Cruel World"

Now close, save and then run it:

/scripts/helloworld.sh

And you’ve done it. Use the exit command twice to get back to crosh and another time to close the command line screen. You now have a script running on ChromeOS. Next up, it’s time to start looking at deployment. This starts with knowing what you’re looking at. To see the kernel version:

uname -r

Or better:

cat /proc/version

Google has been kind enough to build in similar sandboxing to that in Mac OS X, but the concept that you can’t run local applications is a bit mistaken. Sure, the user interface is a web browser, but under the hood you can still do much of what most deployment engineers will need to do.

If these devices are to be deployed en masse at companies and schools, scripts that setup users, bind to LDAP (GCC isn’t built-in, so it might be a bit of a pain to get there), join networks and the such will need to be forthcoming. These don’t often come from the vendor of an operating system, but from the community that ends up supporting and owning the support. While the LDAP functionality could come from Google Apps accounts that are integrated with LDAP, the ability to have a “One touch deploy” is a necessity for any OS at scale, and until I start digging around for a few specific commands/frameworks and doing some deployment scripts to use them, right now I’m at about a 6 touch deploy… But all in good time!

Active Directory Mac OS X Mac OS X Server Mac Security Mass Deployment

Directory Services Scripting Changes in Lion

opendirectoryd

Scripting directory services events is one of the most common ways that the OS X community automates post-imaging tasks. As such, there are about as many flavors of directory services scripts are there engineers that know both directory services and have a little scripting experience. In OS X Lion, many aspects of directory services change and bring with them new techniques for automation. The biggest change is the move from DirectoryService to opendirectoryd.

In Snow Leopard and below, when you performed certain tasks, you restarted the directory services daemon, DirectoryService. The same is true in Lion, except that instead of doing a killall on DirectoryService, you do it on opendirectoryd:

killall opendirectoryd

Also, local account passwords in OS X have been moved into attributes within user account property lists and so there is no longer a /var/db/shadow/hash directory. Therefore, copying property lists and their associated password hash file is no longer a necessary process.

dsperfmonitor vs odutil

Next, dsperfmonitor has gone to the great binary place in the sky to join dirt and DirectoryService. It is somewhat replaced with odutil. The odutil command is pretty easy and straight forward. You can see all open sessions, nodes, modules, requests, statistics and nodenames using the show verb (along with those subcommands). You can also set the logging level for directory services to alert, critical, error, warning, notice, info and debug, each with more and more events that are trapped. This is done with the set log verb along with the level (which is by default set to error):

odutil set log debug

The odutil command is also used to enable statistics. These are pretty memory intensive (or they were on a mini w/ 4GB of memory in it but might not be with your 32GB of RAM fortified Xserve). This is done using odutil’s set statistics verb w/ an option of either on or off:

odutil set statistics on

Note: It’s worth noticing that stats are persistent across restarts, so don’t forget to turn it off.

dsconfigldap

For Open Directory administrators, you’ll be elated to know that your LDAP bind script just got a bit shorter. Now, search policies are updated automatically when binding via dsconfigldap. But, if you have a bunch of scripting that you don’t want to rip apart you can still do search policies manually by using the spiffy new -S option for dsconfigldap (yes, I just insinuated that -S was for spiffy, what’s it to ya’?!?!).

Kerberos

scutil can now be used to view Active Directory Kerberos information. scutil can also be used to query the search node and interface states. klist no longer seems to function properly, so use ktutil to with a list verb to see service principals:

ktutil list

dsconfigad

Not to be left out, the Active Directory binding tool, dsconfigad, got some new flair as well (yes, I just insinuated that dsconfigad was really Jennifer Aniston’s contribution to OS X and I challenge you to prove me wrong). There is now a -restrictDDNS option, which I’m sure you can guess disable dynamic DNS registration in Active Directory-integrated DNS zones. There’s also the rockin’ new -authority option, which enabls or disables Kerberos authority generation. Finally, dsconfigad gets some minor cosmetic changes. -f becomes -force, -r becomes -remove, -lu becomes -localuser, -lp becomes localpassword, -u becomes username, -p becomes -password, but the original options still work. Who knows how long the old operators will stick around, but my guess is they’ll be around until dsconfgad isn’t…

Most options and settings for the AD plug-in should now be configured following the AD bind process (thanks to @djstarr for that little addition). How does this impact your scripts. Just move the settings to the bottom of the script if they give you gruff… Also, the -enableSSO option has been changed to -enablesso.

Defaults

Finally, defaults allows you to put the .plist in the command when you use a file path to list them out. This should eliminate the 6 backspaces we often had to type to test certain things after auto-completing file names… :)

Mac OS X Mac OS X Server Mac Security Unix

Making Autocomplete a Bit Less Sensitive

I can’t stand it when I open terminal and go to cd into a directory I know to exist only to be confused by why using the tab doesn’t autocomplete my command. For those that don’t know, when you are using any modern command line interface, when you’re indicating a location in a file system, the tab key will autocomplete what you are typing. So let’s say you’re going to /System. I usually just type cd /Sys and then use the tab to autocomplete. In many cases, the first three letters, followed by a tab will get you there and you can therefore traverse deep into a filesystem in a few simple keystrokes.

But then there’s all this case weirdness with a lot of the more Apple-centric stuff in the file system. For example, when it’s FileSystem vs. Filesystem vs. filesystem. This makes sense when using a partitioning scheme that allows for case-based namespace collisions, but not in HFS+ (Journaled), the default format used with Mac OS X. So I find myself frequently editing the .inputrc file. This file can be used to do a number of cool tricks in a terminal session, but the most useful for many is to take the case sensitivity away from tab auto-completes, effectively de-pony-tailing the sensitive pony-tail boy.

To do so, create the hidden .inputrc file in your home folder:

touch ~/.inputrc

Then open it with your favorite text editor and add this line:

set completion-ignore-case on

Then save and close. Open a new terminal window and you should be able to tab auto-complete whether or not you have the case right. Try it with /sys-TAB instead of /Sys-TAB. Best of all, as you sudo the behavior follows your session (including sudo bash). However, if you su the behavior does not follow your session. Enjoy and may the pinky that is ever reaching for that shift key thank you as it gets a bit more rest in the next few days than in the last few…

Oh, to turn it back off either toss your .inputrc file (if you don’t have any other parameters in there) or just set the final word of the line to no

Mac OS X Ubuntu Unix

Using a Colon As A Bash Null Operator

I was recently talking with someone that was constructing an If/Then and they wanted a simple echo to match only if a condition was not met. Given their other requirements it seemed a great use for a null operator, which in bash can be a colon (:). This has the equivalent of /dev/null, but with less typing.

One example of populating something with null is if you have a case where you want to create a file where there may or may not be a file already, and you want your new file to be empty (or start empty so you can write lines into it). Here, you could have a line in a script that simply sent null to the file. Here, we’ll use this to create a file called seldon:

: > /temp/seldon

You might expect to see a colon in the above created /temp/seldon file, but you don’t because : was interpreted as null. You could also run it without the colon and end up with the same thing.

> /temp/seldon

If you echo :, you will see a colon echo’d to the screen. This renders the colon unnecessary, but it is just an example, leading up to another where you would need something, as the payload of an If/Then. In the following case, let’s say that we are checking to see if variable $A is 1 and if it isn’t we’ll create an empty file called seldon

if [ "$A" = "1" ];
then
:
else
: > /temp/seldon
fi

To test whether a string hasn’t yet been declared, you can use -n:

if [ -n $a ]

But you can also use the colon to shorten or eliminate the need for certain If/Then blocks entirely. To quote the bash reference (from http://www.gnu.org/software/bash/manual/bashref.html):

When not performing substring expansion, using the form described below, Bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

This means that in the following, if $A has nothing to expand set to 1, otherwise leave it alone:

${A:=1}

But, if you wanted to do the opposite and say that if it has nothing to expand leave it and if it has something, reset that something to 1:

${A:+1}

There are a bunch of other uses in the link provided for the bash manual as well, but overall, you can cut out a lot of typing using a little old colon…

Mac OS X Mac OS X Server MobileMe

Sync’ing iTunes Libraries

I recently spent a few days trimming down the amount of space consumed by my home folder. In so doing I discovered a number of things I could be doing better with regards to utilization of my drive space. So I decided to offload most of my media (photos, movies, etc) off my laptop and onto my Mac Mini server. I also decided that one thing I’d like to live on both is iTunes.

Note: Before you do anything in this article you should verify you have a good back up. Also, both machines will end up needing to be Authorized for your iTunes account.

There are a lot of ways to keep two iTunes libraries in sync. There are also a number of 3rd party tools that can help you do so. I tested all the tools I could find and decided I’d rather just script it myself. Scripting a synchronization operation in Mac and Linux always seems to come down to a little rsync action. Given that rsync is a little old in Mac OS X, I started out by updating rsync to the latest (3.0.7) using the steps provided on bombich.com (I added using /tmp):

mkdir /tmp/rsyncupdate
cd /tmp/rsyncupdate
curl -O http://rsync.samba.org/ftp/rsync/src/rsync-3.0.7.tar.gz
tar -xzvf rsync-3.0.7.tar.gz
curl -O http://rsync.samba.org/ftp/rsync/src/rsync-patches-3.0.7.tar.gz
tar -xzvf rsync-patches-3.0.7.tar.gz
cd rsync-3.0.7
curl -o patches/hfs_compression.diff http://www.bombich.com/software/opensource/rsync_3.0.7-hfs_compression_20100701.diff
curl -o patches/crtimes-64bit.diff https://bugzilla.samba.org/attachment.cgi?id=5288
curl -o patches/crtimes-hfs+.diff https://bugzilla.samba.org/attachment.cgi?id=5966
patch -p1 <patches/fileflags.diff
patch -p1 <patches/crtimes.diff
patch -p1 <patches/crtimes-64bit.diff
patch -p1 <patches/crtimes-hfs+.diff
patch -p1 <patches/hfs_compression.diff
./prepare-source
./configure
make
sudo make install
sudo rm -Rf /tmp/rsyncupdate
/usr/local/bin/rsync –version

Provided the version listed is 3.0.7 then we have a good build of rsync and can move on with our next step, getting a target volume mounted. In this case, I have a volume shared out called simply Drobo (I wonder what kind of RAID that is?!?!). Sharing was done from System Preferences -> Sharing -> File Sharing -> click + -> Choose Drobo and then assign permissions. The AFP server is on an IP address of 192.168.210.10. For the purposes of this example, the username is admin and the password is mypassword. So we’ll do a mkdir in /Volumes for Drobo:

mkdir /Volumes/Drobo

Then we’ll mount it using the mount_afp command along with a -i option:

mount_afp “afp://admin:mypassword@192.168.210.10/Drobo” /Volumes/Drobo

Now that we have a mount we’ll need to sync the library up. In this case, the Music directory on the Drobo has a symlink from ~/Music. This was created by copying my Music folder to the drobo and then rm’ing it (fails when trying from Finder):

rm -Rf ~/Music

Then using ln to generate the symlink:

ln -s ~/Music /Volumes/Drobo/Music

Now sync the files. I’m not going to go into all of the options and what they do, but make sure you have permissions to both the source and the target (using the username and password from the user whose data your changing helps):

/usr/local/bin/rsync -aAkHhxv –fileflags –force –force-change –hfs-compression –delete –size-only ~/Music/iTunes /Volumes/Drobo/Music

Note: If you get a bunch of errors about operations failing then consider disabling the Ignore ownership on this volume setting for any external media you may be using.

Now fire up iTunes on the target machine and make sure it works. At this point, I could also share out the Music folder from my laptop and sync back as well, which would effectively allow me to make changes on both machines. However, for now, I only want to make changes on the laptop and not the desktop so there’s no need for a bidirectional sync.

Once the sync is complete, we can tear down our afp mount:

diskutil unmount /Volumes/Drobo

Now that we can sync data, we still need to automate the process as I’m not going to want to type all this every time I run it. First up, I’m going to create a .sh file (let’s just say /scripts/synciTunes.sh):

touch /scripts/synciTunes.sh

Then I’m going to take the commands to mount the drive, sync the data and then unmount the drive and put them in order into the script:

/bin/mkdir /Volumes/Drobo
mount_afp “afp://admin:mypassword@192.168.210.10/Drobo” /Volumes/Drobo
/usr/local/bin/rsync -aAkHhxv –fileflags –force –force-change –hfs-compression –delete –size-only ~/Music/iTunes /Volumes/Drobo/Music
/usr/sbin/diskutil unmount /Volumes/Drobo

Once created, the script should be run manually and provided it succeeds then it can be automated (ie – creating a LaunchDaemon). If it works after a little while, then you can consider synchronizing your iPhoto and anything else if you so choose. Also, I ended up actually using ssh pre-shared key authentication and doing rsync over ssh. That allows you not to put the password for a host on your network into an unencrypted form in a script. You could do some trickeration with the password, but you might as well look into pre-shared keys if you’re going to automate this type of thing to run routinely. Finally, I also later ended up removing the iTunes Genius files as I started to realize they were causing unneeded data to sync and they would just rebuild on the other end anyway. Hope this helps anyone else looking to build an iLife server of their own!

Mac OS X

Scripting FaceTime

I will go through long stretches without playing with new technology until I either get unbusy or get talked into figuring out how to do something remotely interesting with it. Like linking FaceTime up to a help desk database. It turns out that Apple made it a very straight forward process. Simply use a facetime handler as the prefix to a URL with the phone number of the other person (iPhone 4) or their FaceTime email address (usually with the desktop app).

For example, if my email were krypted@krypted.com then you could use the following from terminal:

open facetime://krypted@krypted.com

Or if my phone number were 310-555-1212 (it is you know;):

open facetime://3105551212

Happy FaceTiming

cloud Mac OS X Mac OS X Server Mac Security Mass Deployment Ubuntu Unix

Using the CrashPlan Pro REST API

CrashPlan Pro Server is a pretty cool tool with a lot of great features that can be used to back up client computers. There are a lot of things that CrashPlan Pro is good at out of the box, but there are also a lot of other things that CrashPlan Pro wasn’t intended for that it could be good at, given a little additional flexibility. The REST API that CrashPlan Pro uses provides a little flexibility and as with most APIs I would expect it to provide even more as time goes on.

I often hear people run away screaming when REST comes up, thinking they’re going to have to learn some pretty complex scripting. And while the scripting can be complex, it doesn’t necessarily have to be. You can find a lot of handy information about the options available in the REST API at http://support.crashplanpro.com/doku.php/api. The very first example command that CrashPlan gives is the following:

http://:4280/rest/users?status=Active

Now, to use this in a very simple script, let’s look at it with curl. You are going to need to authenticate, so we’re going to inject that into the URL in much the same was that we would with something like, let’s say, WebDAV, SSH or FTP. If the server name were foundation.lan, the user name was daneel and the password was seldonrulez then the curl command would actually look like so (you could use the -u operator to inject the authentication information, but as you’ll see later I’d like to make those a bit less complex):

curl http://daneel:seldonrulez@foundation.lan:4280/rest/users?status=Active

Note: The default port for the web administration in CrashPlan Pro is 4280.

This is simply going to output a list of Active users on the server. The reason it’s going to output only Active users is that we asked it to (reading from left to right after the rest is shown in the URL) query users, using the status attribute and specifying only to show us users whose status matches as Active. We could just as easily have requested all users by using the following (which just removes ?status=Active):

curl http://daneel:seldonrulez@foundation.lan:4280/rest/users

Each user has a unique attribute in their id. These are assigned in an ascending order, so we could also query for the user with an ID of 3 by simply following the users with their unique ID:

curl http://daneel:seldonrulez@foundation.lan:4280/rest/users/3

We could also query for all users with a given attribute, such as orgId (note that these attributes are case sensitive unlike many other things that start with http). For example, to find users with an orgID of 3:

curl http://daneel:seldonrulez@foundation.lan:4280/rest/users?orgId=3

The API doesn’t just expose looking at users though. You can look at Organizations (aka orgs), targets (aka mountPoints), server statistics (aka serverStats) and Computers (aka computers). These can be discovered by running the following command:

curl -i http://daneel:seldonrulez@foundation.lan:4280/rest/

To then see each Organization:

curl http://daneel:seldonrulez@foundation.lan:4280/rest/orgs

And to see each Computer:

curl http://daneel:seldonrulez@foundation.lan:4280/rest/computers

You can also perform compound searches fairly easily. For example, let’s say that we wanted to see

curl http://daneel:seldonrulez@foundation.lan:4280/rest/computers?userId=3&status=Active

These basic incantations of curl are simply getting information, which programmatically could also be specified using a -X operator (or –request if you like to type a lot) to indicate the type of REQUEST we’re sending (continuing on with our Code42 Sci-fi inspired example):

curl -X GET -H ‘Content-type: application/json’ http://daneel:seldonrulez@foundation.lan:4280/rest/orgs

The important thing about being able to indicate the type of REQUEST is that we can do more than GET: we can also POST and PUT. We also used the -H operator to indicate the type of data, which we’re specifying as application/json (per the output of a curl -i command against the server’s REST API URL). POST is used to create objects in the database whereas PUT is used update objects in the database. This could result in:

curl -i -H ‘Content-Type: application/json’ -d ‘{“username”: “charlesedge”, “password”: “test”, “firstName”: “Charles”, “lastName”: “Edge”, “orgId”: “3″}’ http://daneel:seldonrulez@foundation.lan:4280/rest/users

Once you are able to write data, you will then be able to script mass events, such as create new users based on a dscl loop using groups, remove users at the end of a school year (PUT {“status”: “Deactivated”}), mass change orgIds based on other variables and basically fully integrate CrashPlan Pro into the middleware that your environment might already employ.

Perl, Python, Ruby and PHP come with a number of options specifically designed for working with REST, which makes more complicated scripting much easier (such as with php’s curl_setopt); however, these are mostly useful if you already know those languages and the point of this article was to stay in shell scripting land. This allows you knock out simple tasks quickly, even if the good people at Code 42 didn’t think to add the specific features to their software that you might have in mind. Once you start to get into scripting more complex events, look to the Python examples at the bottom of the API Architecture page to get ya’ kickstarted!

Mac OS X Mac OS X Server Ubuntu Unix

Colorizing the Terminal

It really helps me to see different types of entries in the Terminal listed with different colors. I don’t go for listing everything that you can list as a different color though, as it starts looking a bit like a circus in Terminal when I do. If you want to colorize your terminal in Mac OS X there are two main ways to do so; both will require altering your .bash_profile (or creating if it’s not already there).

To get started, go to your home folder from within Terminal and open .bash_profile from your favorite text editor. If it doesn’t exist then the text editor should create a new file when you save it. Now that you’ve created the .bash_profile paste these two lines in there:

export CLICOLOR=1
export LSCOLORS=ExxxxxDxBxegedabxxacad

The above export can be seen as having two aspects. The first is the position. There are a total of 11 positions, with a foreground and a background being listed in that order, for each position, resulting in 22 total letters. The following represents each position, in sequence:

  1. Directory
  2. Symbolic link
  3. Socket
  4. Pipe
  5. Executable
  6. Special block
  7. Special character
  8. Executable w/ setuid set
  9. Executable w/ setgid set
  10. Directory that is writable to others w/ sticky bit
  11. Directory that is writable to others w/out sticky bit

Next, consider the colors that are used. These include:

  • a black
  • b red
  • c green
  • d brown
  • e blue
  • f magenta
  • g cyan
  • h light grey
  • x default foreground or background

Additionally, each of these colors can be used in upper case, resulting in a bold version of the same color. So if we want everything else listed with the default colors except for directories and we wanted those listed in red, we could use the following LSCOLORS line:

export LSCOLORS=ExFxCxDxBxegedabagacad

export LSCOLORS=bxxxxxxxxxxxxxxxxxxxxx

Now let’s say that we’re going to have our executables listed in blue, directories in red and everything else in the default colors:

export LSCOLORS=bxxxxxxxexxxxxxxxxxxxx

Finally, let’s say that we’re going to retain those two settings but also have the special block with a red background and black text:

export LSCOLORS=bxxxxxxxexBxxxxxxxxxxx

Additionally you can customize the colors of your prompt (and customize how it looks and what’s included. I’ll get to the prompt customization later though, as I’ve got a little football to go watch…  Favre + Vikes!
Mac OS X

Adding Man Pages

There are a number of man pages in Mac OS X that don’t show up when you type man followed by the command – especially if you’ve gone and started bolting new open source software onto your OS that keeps its man page in its own directory structure.  If you have the path to a directory of man pages then you can view these using the man command easily once you add it to your MANPATH.  The MANPATH is an environment variable that can be set by editing a users .bash_profile directory.  Simply add the directory you’d like to scan in a new line that starts with MANPATH=.  For example if you had a bunch of man pages located in the man directory of your home folder, the following command would include them in your MANPATH:

MANPATH=~/man

If you want to undo this change, you can always just remove the offending line.  If you have multiple items, then like PHPs includes the will be separated by a :