<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2971257711362934224</id><updated>2011-11-27T17:18:05.232-08:00</updated><title type='text'>Command Line Mac</title><subtitle type='html'>The Power of the Prompt</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://commandlinemac.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>84</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2805472430042579068</id><published>2011-11-17T15:01:00.001-08:00</published><updated>2011-11-17T15:12:44.150-08:00</updated><title type='text'>Ruby: Sorting an array with multiple fields</title><content type='html'>I was working on a project today and needed to make some changes to the way an array on objects was sorted before being displayed on the screen.  The main reason I even bothered to post this is to heap a little more praise on Ruby for working the way I expected it to work.&lt;br&gt;&lt;br&gt;Here was my object (not tied to a database, just created for convenience):&lt;blockquote&gt;class Force&lt;br&gt;  attr_accessor :id&lt;br&gt;  attr_accessor :last_name&lt;br&gt;  attr_accessor :first_name&lt;br&gt;  attr_accessor :rank&lt;br&gt;  attr_accessor :shift&lt;br&gt;  attr_accessor :promoted_on&lt;br&gt;  attr_accessor :phone&lt;br&gt;  attr_accessor :totalcount&lt;br&gt;end&lt;/blockquote&gt;I needed to sort an array of these objects by rank ascending, shift ascending, then promoted_on (date) descending.&lt;br&gt;&lt;br&gt;I sorted them by concatenating the fields together and making the right comparisons.  This only works because the first two fields, rank and shift, cannot be empty. Otherwise, a simple concatenation would create undesired results.&lt;br&gt;&lt;br&gt;Sorting all fields ascending looks like this:&lt;br&gt;&lt;blockquote&gt;@forces = @forces.sort {|x,y| x.shift + x.rank + x.promoted_on.to_s &lt;=&gt; y.shift + y.rank + y.promoted_on.to_s}&lt;/blockquote&gt;To sort the promoted_on field in descending order, reverse the x,y sides for that field:&lt;br&gt;&lt;blockquote&gt;@forces = @forces.sort {|x,y| x.shift + x.rank + &lt;b&gt;y.promoted_on.to_s&lt;/b&gt; &lt;=&gt; y.shift + y.rank + &lt;b&gt;x.promoted_on.to_s&lt;/b&gt;}&lt;/blockquote&gt;No need for a special sort coding block. Ruby FTW!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2805472430042579068?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2805472430042579068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2805472430042579068'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/11/ruby-sorting-array-with-multiple-fields.html' title='Ruby: Sorting an array with multiple fields'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4653664352488456234</id><published>2011-10-06T09:56:00.001-07:00</published><updated>2011-10-06T09:56:44.527-07:00</updated><title type='text'>Steve Jobs RIP</title><content type='html'>Steve Jobs RIP&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4653664352488456234?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4653664352488456234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4653664352488456234'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/10/steve-jobs-rip.html' title='Steve Jobs RIP'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6375870162540293945</id><published>2011-09-18T12:55:00.000-07:00</published><updated>2011-09-18T18:21:18.498-07:00</updated><title type='text'>The Chromium OS experiment</title><content type='html'>&lt;b&gt;Google's Chromium OS&lt;/b&gt;&lt;br&gt;&lt;br&gt;I downloaded a bootable ISO of the Google Chromium OS release candidate.  Then, fired it up in VMware Player and took a look around.  It appears to be based on OpenSUSE Linux 11.4.  SUSE was one of the distributions I cut my teeth on in the Linux world.  I always appreciated the 9 pound manual of documentation that came with it. Very helpful for beginners and a good reference to their tools.&lt;br&gt;&lt;br&gt;I might have made a mistake when setting up the virtual machine because it complained of low memory right after booting. This could also explain the slow performance I experienced.  The desktop itself is clean and appears to be optimized to run the Chrome web browser.  There was a local word processing application, but I didn't get far enough to test it out, it was just too slow. I could not find a download link at Google, but I found one at a .eu domain.  Maybe it was a pirated or tampered version.  I am going to postpone further research until I am sure I have a good distribution.&lt;br&gt;&lt;br&gt;Updated: Turns out Google doesn't provide an image or download of the OS itself, only the source code and compilation instructions.  Also, the OS is based on Ubuntu, despite the build I got from Europe based on SUSE. ZD Net suggested that the running OS would be slow so I maybe I am not missing much at this stage of development.  I don't want to pay for a Chromebook just to run Chrome.  Another reason to keep this on hold for now.&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6375870162540293945?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6375870162540293945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6375870162540293945'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/09/chromium-os-experiment-i-downloaded.html' title='The Chromium OS experiment'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8316933857545180658</id><published>2011-07-20T13:42:00.000-07:00</published><updated>2011-07-29T13:12:47.288-07:00</updated><title type='text'>Getting by in Git</title><content type='html'>Git is the source code management system used for the Linux kernel and many other highly complex projects.  It was written by Linux Torvalds after some controversy over the proprietary Bitkeeper program that used to manage the Linux kernel.&lt;br /&gt;&lt;br /&gt;I've needed to upgrade my skills recently to use git in place of subversion because that is what my shop decided to use.  I've moved all my Rails code into a remote git server and so far, so good.&lt;br /&gt;&lt;br /&gt;One improvement is it has fewer "droppings" than subversion.  There is no hidden .svn directory in each directory with source code.  Only a single .git directory at the root of the project, plus a .gitignore file for files you don't want git to track.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Initialize project tracking&lt;/span&gt;&lt;br /&gt;git init&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Check out an existing project from remote server&lt;/span&gt;&lt;br /&gt;git clone ssh://server/git/project&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Add a file for git to track&lt;/span&gt;&lt;br /&gt;git add &lt;file&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Add all files from this directory and below for git to track&lt;/span&gt;&lt;br /&gt;git add .&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Commit all files to local repository&lt;/span&gt;&lt;br /&gt;git commit -a -m "message"&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Undo changes to a file (re-check out from repository)&lt;/span&gt;&lt;br /&gt;git checkout -- &lt;file&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Pull files from remote repository and merge with local repository&lt;/span&gt;&lt;br /&gt;git pull&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Push files to remote repository (must commit first)&lt;/span&gt;&lt;br /&gt;git push&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Move file or directory to new location&lt;/span&gt;&lt;br /&gt;git mv path destination&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Remove file or directory from the working tree&lt;/span&gt;&lt;br /&gt;git rm path&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;To create a remote repository from an existing project takes several steps&lt;/span&gt;&lt;br /&gt;cd /tmp&lt;br /&gt;git clone --bare /path/to/project (creates a /tmp/project.git directory)&lt;br /&gt;scp project.git to remote server&lt;br /&gt;cd /path/to/project&lt;br /&gt;git remote add origin ssh://server/git/project&lt;br /&gt;git config branch.master.remote origin&lt;br /&gt;git config branch.master.merge refs/heads/master&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8316933857545180658?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8316933857545180658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8316933857545180658'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/07/getting-git.html' title='Getting by in Git'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8244044749434501405</id><published>2011-05-26T14:10:00.000-07:00</published><updated>2011-05-26T14:34:52.035-07:00</updated><title type='text'>LVM basics</title><content type='html'>I've just spent a few hours with iSCSI SAN disks (EqualLogic) and Linux Logical Volume Manager (LVM).  The abstraction is even deeper than that, because Linux at work is running under VMware, so it is really VMware talking to the SAN and presenting a SCSI disk to Linux.  Since I only get into the LVM weeds a couple of times a year, I thought it would be helpful to list the steps I took to get usable disk space under Linux starting with the raw disk space.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step One - create a new partition&lt;/span&gt;&lt;br /&gt;Create a new partition with FDISK or PARTED.  Mark the partition type hex 8E for LVM. In my case, the SCSI disk appeared as /dev/sdb and the partition using all space became /dev/sdb1. LVM is capable of using a raw device (no partition type), but I stayed in familiar partitioning territory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Two - create LVM physical volume&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pvcreate /dev/sdb1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Three - create LVM volume group in the physical volume&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;vgcreate new_volume_group /dev/sdb1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Four - create LVM logical volume in the volume group&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;lvcreate --name new_logical_volume --size 100G new_volume_group&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Five - create a file system on the logical volume&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;mkfs -t ext4 /dev/mapper/new_volume_group-new_logical_volume&lt;/span&gt;&lt;br /&gt;Note: Linux device mapper automatically creates a symlink to the disk in /dev/mapper using the volume group and logical volume names.  If you choose more meaningful names than the example, the name won't look so awful.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Six - turn off automatic file system checks (optional)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;tune2fs -c 0 /dev/mapper/new_volume_group-new_logical_volume&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step Seven - add mount point in /etc/fstab&lt;/span&gt;&lt;br /&gt;Once the mount point is list in fstab, mount it manually and it is ready to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8244044749434501405?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8244044749434501405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8244044749434501405'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/05/lvm-basics.html' title='LVM basics'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8827033864904163737</id><published>2011-04-13T10:13:00.000-07:00</published><updated>2011-04-13T10:26:12.415-07:00</updated><title type='text'>Chrome Revisited</title><content type='html'>In my first &lt;a href="http://commandlinemac.blogspot.com/2010/08/google-chrome-experiment.html"&gt;serious test of Mac Chrome back in August, 2010&lt;/a&gt;, it came up short compared to other popular web browsers.  But Chrome has been evolving fast.  And since Firefox 4.0 was just released, it seemed like the right time to run another informal comparison.&lt;br /&gt;&lt;br /&gt;What a difference.  &lt;a href="http://www.google.com/chrome/intl/en/landing_chrome.html?hl=en"&gt;Chrome has become more stable&lt;/a&gt;, faster, and has made huge strides in available and useful plugins.  The plugin gap with Firefox was a glaring issue last time. As a web developer, Firefox was indispensable with the Firebug plugin, letting you drill into the CSS and JavaScript acting on individual DOM components. Chrome now has native developer tools that rival Firebug.  I am also fond of the Awesome Screenshot plugin that allows you to capture and annotate a web page from within the browser.&lt;br /&gt;&lt;br /&gt;While I have found Firefox 4.0 a nice improvement in looks and rendering speed, I have also found it leaks memory, more so on Windows than Linux or Mac.  I can rarely make it through a day without the Windows version locking up.  That may be an artifact of the slew of plugins I am running and not the Firefox core.&lt;br /&gt;&lt;br /&gt;For the last couple of weeks, I have been using Chrome as my primary browser on all platforms and have been very pleased. Competition is a great thing and I am excited to see browsers evolving again after what seemed like a long period of stagnation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8827033864904163737?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8827033864904163737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8827033864904163737'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/04/chrome-revisited.html' title='Chrome Revisited'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3414236734583476736</id><published>2011-01-23T09:10:00.000-08:00</published><updated>2011-01-23T10:16:46.452-08:00</updated><title type='text'>Android G2 and iTunes music sync</title><content type='html'>Getting music from iTunes on a Mac onto an Android G2 smart phone was an easy task.  Maybe it wasn't so easy with the first generation Android phones, but the G2 I purchased a couple of weeks ago came with everything I needed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Connecting the phone to the Mac&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My main Mac is a two year old MacBook.  The G2 came with a USB sync cable and as soon as I attached it, it opened iPhoto to upload pictures just like a camera.  But the G2 also displayed a screen to enable it as a USB disk drive.  I enabled disk mode, then took a look at the mounted volume in Finder.&lt;br /&gt;&lt;br /&gt;One of the icons on the Volume was DoubleTwist.  When I double clicked it, it started downloading the latest Mac version of DoubleTwist.  After installation, the DoubleTwist interface looked very much like iTunes.  It allows you to automatically sync all music from iTunes or just selections.&lt;br /&gt;&lt;br /&gt;Since I don't plan to listen to music often on the G2, I chose to only sync playlists.  This only syncs the music required in each playlist. There are a lot of options in DoubleTwist and the integration was seamless.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3414236734583476736?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3414236734583476736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3414236734583476736'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/01/android-g2-and-itunes-music-sync.html' title='Android G2 and iTunes music sync'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7945059788708432729</id><published>2011-01-02T20:01:00.000-08:00</published><updated>2011-01-03T09:35:53.066-08:00</updated><title type='text'>Automating FTP</title><content type='html'>People frequently need to automate FTP sessions to upload or download files.&lt;br /&gt;Most command line FTP clients, including the FTP client on the Mac, can automatically login to an FTP server by reading the &lt;span style="font-style:italic;"&gt;.netrc&lt;/span&gt; file in the user home directory.  Note that the FTP auto-login file starts with a dot in front of the name (dot netrc).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Syntax of the $HOME/.netrc&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The .netrc file can contain more than one auto-login configuration.  Each FTP server has a set of commands, the minimum being the login name and password.  You can create as many machine sections as you need. Here is a generic example:&lt;br /&gt;&lt;blockquote&gt;machine ftp.server.com&lt;br /&gt;&amp;nbsp;&amp;nbsp;login myuserID&lt;br /&gt;&amp;nbsp;&amp;nbsp;password mypassword&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Very Important: .netrc permissions!&lt;/span&gt;&lt;br /&gt;Since user IDs and passwords are stored in the .netrc file, the FTP client enforces permission checking on it.  It must be set so that no groups and no other users can read or write to it.  You can set the permissions on it with this command from the Terminal (from your home directory) once the file is created:&lt;br /&gt;chmod 700 .netrc&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Adding FTP commands in a BASH script&lt;/span&gt;&lt;br /&gt;You can embed FTP commands in a BASH script to upload and download files.&lt;br /&gt;For example, you could create a script file named &lt;span style="font-style:italic;"&gt;ftpupload.sh&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;#!/bin/bash&lt;br /&gt;# upload a file &lt;br /&gt;/usr/bin/ftp -i ftp.server.com &amp;lt;&amp;lt;ENDOFCOMMANDS&lt;br /&gt;cd backupdir&lt;br /&gt;cd subdir&lt;br /&gt;put datafile&lt;br /&gt;quit&lt;br /&gt;ENDOFCOMMANDS&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;In this example, I added the -i switch when running FTP to prevent it from prompting on multiple file uploads/downloads, even though it is only uploading one file in the example.  I also use the BASH &lt;span style="font-style:italic;"&gt;HERE document&lt;/span&gt;  feature to send commands to FTP.  When the script is run, it will auto-login using the information in the .netrc file, change to the right remote directory and upload the datafile.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Scheduling the script with Cron&lt;/span&gt;&lt;br /&gt;The last step is to get the BASH script to run unattended, say every day at 5:00 am.  The old school UNIX way is to use Cron, but the fancy new Apple way is to use a launchd XML configuration.  As long as cron is supported in OS X, I'll stick to the old school way.  I leave the launchd configuration as an exercise for the reader.&lt;br /&gt;&lt;br /&gt;Add these lines with the command "crontab -e", then save:&lt;br /&gt;&lt;blockquote&gt;# automated FTP upload&lt;br /&gt;0 5 * * * /Users/username/ftpupload.sh&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7945059788708432729?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7945059788708432729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7945059788708432729'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2011/01/automating-ftp.html' title='Automating FTP'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6744486016294095937</id><published>2010-09-15T09:14:00.000-07:00</published><updated>2010-09-15T10:07:14.204-07:00</updated><title type='text'>Dumping a Postgresql database remotely with SSH</title><content type='html'>I ran into a rare problem recently with a large Postgresql database that was filling up the local disks of a server.  The database was large, over 100 GB and about 300 million records.  There was a lot of churn and it had not been vacuumed in a long time.  When I manually ran a vacuum on it, there was not enough working disk space to complete the operation, creating a bind.&lt;br /&gt;&lt;br /&gt;What I decided to do instead of using vacuum was to dump it to a remote backup location, then drop the database and restore it from the remote dump.  I used SSH to run the remote commands.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Dump a remote Postgresql database to the local machine&lt;/span&gt;&lt;br /&gt;ssh &lt;i&gt;user@remote-database-server&lt;/i&gt; 'pg_dump database-name -t table-name' &gt; table-name.sql&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Restore a remote Postgresql database dump to the local database server&lt;/span&gt;&lt;br /&gt;ssh &lt;i&gt;user@backup-machine&lt;/i&gt; 'cat table-name.sql' | psql -d database-name&lt;br /&gt;&lt;br /&gt;Note that the dump command is run from the backup machine and the restore command is run from the database server.&lt;br /&gt;&lt;br /&gt;Also note the single quotes around certain parts of the command.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6744486016294095937?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6744486016294095937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6744486016294095937'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/09/dumping-postgresql-database-remotely.html' title='Dumping a Postgresql database remotely with SSH'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1009025875989621756</id><published>2010-08-19T16:26:00.001-07:00</published><updated>2010-08-19T16:32:20.823-07:00</updated><title type='text'>The Google Chrome experiment</title><content type='html'>When Google first announced their Chrome browser, packed with a revamped JavaScript engine (V8) and support for offline web apps, I thought I would give it a spin.  The first couple of releases were for Windows and Linux -- no Mac version.  Those early versions were a little clunky and appeared to offer no better performance than other popular browsers.   So I moved on.&lt;br /&gt;&lt;br /&gt;When the Mac version became available, it was a much more polished browser.  Another theoretical selling point was that each tab ran as a separate process so one crashed tab would not crash the whole browser.  I decided to give Chrome a serious work out on my Mac at home.&lt;br /&gt;&lt;br /&gt;Things started out well enough and performance was good.  I perused the help and learned some of the short cuts.  After about three good weeks, something went wrong.  I don't know if it was an update, a growing cache, or what, but it started slowing down.  Then, it started having problems loading pages from web sites that worked fine in other browsers.  It is possible that it even caused wireless network issues, though that is just speculation at the moment.  I need to do some more research to see if the problems were related to Chrome.&lt;br /&gt;&lt;br /&gt;For now, I am sticking with Firefox as my main browser on the Mac.  I'll come back and try Chrome out after the next major release.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1009025875989621756?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1009025875989621756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1009025875989621756'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/08/google-chrome-experiment.html' title='The Google Chrome experiment'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1149588741391930549</id><published>2010-07-01T16:36:00.001-07:00</published><updated>2010-07-01T16:48:56.767-07:00</updated><title type='text'>Finding IPs connected to your web server</title><content type='html'>&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;On Mac OS X&lt;/span&gt;&lt;br /&gt;note: this also shows outgoing connections from web browsers&lt;br&gt;&lt;br /&gt;Get all IPs connected to your web server:&lt;br /&gt;&lt;blockquote&gt;netstat -nat | sed -n -e '/ESTABLISHED/p' | awk '{print $5}' | sed 's/\./ /g' | awk '{print $1"."$2"."$3"."$4}' | sort&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Get all &lt;span style="font-style:italic;"&gt;unique&lt;/span&gt; IPs connected to your web server:&lt;br /&gt;&lt;blockquote&gt;netstat -nat | sed -n -e '/ESTABLISHED/p' | awk '{print $5}' | sed 's/\./ /g' | awk '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -n&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;On Linux&lt;/span&gt;&lt;br /&gt;Get all IPs connected to your web server:&lt;br /&gt;&lt;blockquote&gt;netstat -ntu | sed -e 's/::ffff://g' | awk '{print $5}' | cut -d : -f1 | sort -n&lt;/blockquote&gt;&lt;br /&gt;Get all &lt;span style="font-style:italic;"&gt;unique&lt;/span&gt; IPs connected to your web server:&lt;br /&gt;&lt;blockquote&gt;netstat -ntu | sed -e 's/::ffff://g' | awk '{print $5}' | cut -d : -f1 | sort | uniq -c | sort -n&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1149588741391930549?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1149588741391930549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1149588741391930549'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/07/finding-ips-connected-to-your-web.html' title='Finding IPs connected to your web server'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-11239983566256093</id><published>2010-05-16T14:38:00.001-07:00</published><updated>2010-05-16T14:38:27.974-07:00</updated><title type='text'>RIP RJD</title><content type='html'>&lt;a href="http://latimesblogs.latimes.com/music_blog/2010/05/ronnie-james-dio-dies-sabbath-rainbow-singer.html"&gt;The Last in Line&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-11239983566256093?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/11239983566256093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/11239983566256093'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/05/rip-rjd.html' title='RIP RJD'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6737514198942046262</id><published>2010-03-22T10:39:00.000-07:00</published><updated>2010-03-22T10:53:46.967-07:00</updated><title type='text'>The mysterious Data Center Technical Specialist certification</title><content type='html'>On March 4, I received an email from Novell Technical Training that I had received a Novell certification for "Data Center Technical Specialist".  This came as a surprise to me because I had not applied for this certification, taken any tests for this certification, not had I even &lt;span style="font-weight:bold;"&gt;heard&lt;/span&gt;of this certification.&lt;br /&gt;&lt;br /&gt;Due to a cross marketing agreement with the Linux Professional Institute, I had applied for and received the Novell Certified Linux Administrator certification a few weeks prior.  This seemed legitimate to me, as I had extensive experience with SUSE Linux and my Linux skills are still sharp.  I continue to perform Linux server administration as part of my daily work.&lt;br /&gt;&lt;br /&gt;However, I am not quite sure what the Data Center Technical Specialist is supposed to represent.  Confused, I wrote to Novell Training asking what the certification meant.  I received this equally mysterious reply:&lt;br /&gt;&lt;blockquote&gt;Thank you for contacting Novell Training Services.  You have received the certification as part of some changes we have made recently to our partner requirements. As part if these changes, some of the exams/certifications you have  now count toward the new certification.&lt;/blockquote&gt;&lt;br /&gt;I searched the official Novell Certification web site, and this certification does not appear anywhere.  I suspect, but can't confirm that it may be part of the Solution Provider program.  As such, it is probably more of a value to Novell sales than to an individual technician.  I remain somewhat baffled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6737514198942046262?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6737514198942046262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6737514198942046262'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/03/mysterious-data-center-technical.html' title='The mysterious Data Center Technical Specialist certification'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3497497089766834545</id><published>2010-03-03T09:59:00.000-08:00</published><updated>2010-03-03T13:18:26.541-08:00</updated><title type='text'>Fuzzy string matching in PostgreSQL</title><content type='html'>A recent project required me to use fuzzy string matching, or sound alike matching, in an application that searched a list of names.  It turns out there is a contrib module for the PostgreSQL database called &lt;a href="http://www.postgresql.org/docs/8.3/static/fuzzystrmatch.html"&gt;fuzzystrmatch&lt;/a&gt; that provides several different matching algorithms.&lt;br /&gt;&lt;br /&gt;The task at hand involved rewriting a legacy application, originally in PICK, in Ruby on Rails.  The PICK application used a soundex search to find names of people that sounded like the search string.&lt;br /&gt;&lt;br /&gt;Three algorithms are available as PostgreSQL functions (after installation of the fuzzystrmatch module).  They are &lt;span style="font-style:italic;"&gt;soundex()&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;levenshtein()&lt;/span&gt;, and &lt;span style="font-style:italic;"&gt;metaphone()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Both soundex and metaphone convert a string into character codes.  Soundex uses 4 characters and metaphone uses a configurable number of characters.  Levenshtein directly compares two strings and returns an integer indicating how well the two strings match.&lt;br /&gt;&lt;br /&gt;After some trial and error, I found that metaphone produced better results than soundex.  I didn't test the Levenshtein function.&lt;br /&gt;&lt;br /&gt;To improve the results, I added a classic substring search using &lt;span style="font-style:italic;"&gt;ILIKE&lt;/span&gt;.  The combination of ILIKE and metaphone gave me a broad, but reasonably accurate fuzzy string search.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3497497089766834545?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3497497089766834545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3497497089766834545'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/03/fuzzy-string-matching-in-postgresql.html' title='Fuzzy string matching in PostgreSQL'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2074152229463490994</id><published>2010-02-26T13:39:00.000-08:00</published><updated>2010-02-26T13:48:49.323-08:00</updated><title type='text'>Linux: fuser to find processes on TCP ports</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Note: This is for Linux only. The Mac (BSD) version of fuser does not handle TCP/UDP ports.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once or twice a year, I run into a problem where a process is using a TCP port and I need to find out which one.  I am documenting it here for the next time so I don't have to look it up in man pages.&lt;br /&gt;&lt;br /&gt;To see all processes, run fuser as root or with sudo.&lt;br /&gt;&lt;br /&gt;To list all processes connected to TCP port 22:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;fuser -n tcp 22&lt;/code&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2074152229463490994?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2074152229463490994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2074152229463490994'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/02/linux-fuser-to-find-processes-on-tcp.html' title='Linux: fuser to find processes on TCP ports'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6070480749423836548</id><published>2010-01-21T14:39:00.000-08:00</published><updated>2011-09-14T11:58:35.285-07:00</updated><title type='text'>Rails 2.x scaffolding field types</title><content type='html'>&lt;br&gt;&lt;span style="font-weight:bold;"&gt;Dude, where's my CRUD?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the powerful features of Rails 1.x was the ability to generate CReate, Update, and Delete (CRUD) admin screens automatically using the scaffolding script built into Rails.&lt;br /&gt;&lt;br /&gt;The original scaffolding read the database models and created basic, but usable screens to let you add and edit database records.  When the 2.x release of Rails came out, scaffolding lost that power.  Now, you have to manually specify each table field and type on the command line when running scaffold.  If you don't, the generated screens will be empty.&lt;br /&gt;&lt;br /&gt;Worse, a basic reference to all valid field types was missing.  Here are all the valid types I have been able to dig up:&lt;br /&gt;&lt;br /&gt;string&lt;br /&gt;text (long text, up to 64k, often used for text areas)&lt;br /&gt;datetime&lt;br /&gt;date&lt;br /&gt;integer&lt;br /&gt;binary&lt;br /&gt;boolean&lt;br /&gt;float&lt;br /&gt;decimal (for financial data)&lt;br /&gt;time&lt;br /&gt;timestamp&lt;br /&gt;&lt;br /&gt;A mapping of the scaffolding types to data types in corresponding databases can be found on &lt;a href="http://overooped.com/post/100354794/ruby-script-generate-scaffold-types"&gt;&lt;span style="font-weight:bold;"&gt;Overooped&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is an example of using 2.x scaffolding with data types, run from the Rails application root directory:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ruby script/generate scaffold &lt;span style="font-style:italic;"&gt;Modelname&lt;/span&gt; name:string title:string employed_on:date remarks:text&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br&gt;Here is an example of using rails 3.x scaffolding with data types, run from the Rails application root directory:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ruby script/rails generate scaffold &lt;span style="font-style:italic;"&gt;Modelname&lt;/span&gt; name:string title:string employed_on:date remarks:text&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6070480749423836548?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6070480749423836548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6070480749423836548'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2010/01/rails-2x-scaffolding-field-types.html' title='Rails 2.x scaffolding field types'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6578711844622098158</id><published>2009-12-24T13:32:00.000-08:00</published><updated>2009-12-27T11:56:08.872-08:00</updated><title type='text'>You ARE your operating system (among other things)</title><content type='html'>Whenever you make a choice among products with similar functions, that choice spills over into the realm of social status.&lt;br /&gt;&lt;br /&gt;Cars are a common example where social rank often goes with brand, and even within brand, by model, and even within model, by variations, upgrades, and badges.  All signify some social status.  I became acutely aware of this after purchasing a car that did not fit my image.  It was uncomfortable for everyone.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Your operating system&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can see the social aspect tied to an operating system by looking at the Apple "I'm a Mac" campaign, and the weak Microsoft "I'm a PC" campaign response.  A choice to run Linux or other operating system also carries connotations and shared group identity.  In this sense, you &lt;span style="font-weight:bold;"&gt;are&lt;/span&gt; your operating system.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Your collection of choices&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Whether conscious or not, decisions and choices about purchases you make, where choices are available, weave together part of your social tapestry.  The schools you attend, where you work, your clothes, your car, where you live, and yes, your operating system.  You are those things, at least socially.&lt;br /&gt;&lt;br /&gt;The question is, in the context of a consumer society, can a choice be made without the attachment of social status?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6578711844622098158?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6578711844622098158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6578711844622098158'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/12/you-are-your-operating-system-among.html' title='You ARE your operating system (among other things)'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3636582092960919951</id><published>2009-12-05T14:13:00.001-08:00</published><updated>2009-12-05T14:23:31.040-08:00</updated><title type='text'>Calculating the square root of 2 longhand</title><content type='html'>There are many numerical methods to calculate square roots.  This is the long hand method I learned in junior high.  It produces one (accurate) digit at a time, but the working numbers get larger each iteration.  Eventually, it bogs down because it is doing math with integers hundreds, then thousands of digits long.&lt;br /&gt;&lt;br /&gt;Still, it is fun for tinkering.  If you run this Ruby script as is, it will calculate the square root of 2 to 1,000 digits.  To adjust the precision, change the number of iterations on this line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;while iterations &lt; 1000&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here is the entire script...&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/ruby&lt;br /&gt;# calculate a square root of 2 using longhand&lt;br /&gt;&lt;br /&gt;def newroot(divisor, doubleroot)&lt;br /&gt;  # calculate new root&lt;br /&gt;  # formula is doubleroot _ * _ = closest to divisor&lt;br /&gt;  # try 9, then 8, then 7 ...&lt;br /&gt;&lt;br /&gt;  i = 9&lt;br /&gt;  while i &gt;= 0&lt;br /&gt;    multiple1 = (doubleroot.to_s + i.to_s).to_i&lt;br /&gt;    multiple2 = i&lt;br /&gt;    product = multiple1 * multiple2&lt;br /&gt;&lt;br /&gt;    if product &lt;= divisor&lt;br /&gt;      # found new root&lt;br /&gt;      root = i&lt;br /&gt;      # get modulus&lt;br /&gt;      modulus = divisor - product&lt;br /&gt;      break&lt;br /&gt;    end&lt;br /&gt;    i = i - 1&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  return root, modulus&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;roots = Array.new&lt;br /&gt;&lt;br /&gt;# the nearest root to 2 is 1&lt;br /&gt;&lt;br /&gt;root = 1&lt;br /&gt;roots.push(root)&lt;br /&gt;remainder = 2 - root&lt;br /&gt;&lt;br /&gt;doubleroot = root * 2&lt;br /&gt;divisor = remainder * 100&lt;br /&gt;&lt;br /&gt;iterations = 0&lt;br /&gt;&lt;br /&gt;while iterations &lt; 1000&lt;br /&gt;  root,remainder = newroot(divisor, doubleroot)&lt;br /&gt;  roots.push(root)&lt;br /&gt;&lt;br /&gt;  # compute new doubleroot &lt;br /&gt;&lt;br /&gt;  return root, modulus&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;roots = Array.new&lt;br /&gt;&lt;br /&gt;# the nearest root to 2 is 1&lt;br /&gt;&lt;br /&gt;root = 1&lt;br /&gt;roots.push(root)&lt;br /&gt;remainder = 2 - root&lt;br /&gt;&lt;br /&gt;doubleroot = root * 2&lt;br /&gt;divisor = remainder * 100&lt;br /&gt;&lt;br /&gt;iterations = 0&lt;br /&gt;&lt;br /&gt;while iterations &lt; 1000&lt;br /&gt;  root,remainder = newroot(divisor, doubleroot)&lt;br /&gt;  roots.push(root)&lt;br /&gt;&lt;br /&gt;  # compute new doubleroot&lt;br /&gt;  doubleroot = roots.to_s.to_i * 2&lt;br /&gt;&lt;br /&gt;  # compute divisor&lt;br /&gt;  divisor = remainder * 100&lt;br /&gt;&lt;br /&gt;  iterations = iterations + 1&lt;br /&gt;&lt;br /&gt;  print "iteration " + iterations.to_s + "\n"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;print "final roots are " + roots.to_s + "\n"&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3636582092960919951?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3636582092960919951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3636582092960919951'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/12/calculating-square-root-of-2-longhand.html' title='Calculating the square root of 2 longhand'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6602053665280947960</id><published>2009-11-10T08:56:00.000-08:00</published><updated>2009-11-10T09:37:56.456-08:00</updated><title type='text'>Root 2: 500 million glyphs</title><content type='html'>Having generated a text file with the first billion digits of the square root of 2, I started thinking about how to convert it to text.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;First Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My first try was an attempt to convert groups of 2 or 3 digits into a character using the ASCII code table.  This was not very straight forward for several reasons.  To start, many characters in the range from 0-255 are either non-printable or produce symbols or punctuation.  To get around this, I decided to only use the part of the table that started with the numbers and went through the end of the lower case letters.&lt;br /&gt;&lt;br /&gt;That left some 2 digits numbers that had to be scaled up into the useful range and many 3 digit numbers (everything greater than 255) had to be scaled down to the range. I did get a script working that accomplished this, but the results were not satisfying.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Second Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I decided to use a simpler solution and convert each pair of digits into a letter using the range 1-26.  To do this, I added one to the modulus of 26 and each digit pair and indexed it into the alphabet.  Because 26 does not go into 99 evenly, this produces a slight bias against the last few letters of the alphabet but I was will to live with the result.&lt;br /&gt;&lt;br /&gt;As an example, the first two digits are 14.  14 divided by 26 is 0 with a modulus (remainder) of 14.  Adding one to 14 is 15 returning the letter O.  The next two digits are 14 also returning O.  The next two are 21 returning the letter V.&lt;br /&gt;&lt;br /&gt;At the end of another scriptaculous ruby adventure, I had converted my billion digit file into 500 million letters.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Signals in the noise&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To make the file easy to search, I wrote the resulting text file out in 72 character lines.  Yes, this causes some loss of continuity at line breaks, but again, I was willing to live with it.&lt;br /&gt;&lt;br /&gt;I quickly found the string with my name "KEITH" 65 times.  The first occurrence was 7,398,524 digits into the square root of 2.  My wife's name appeared 125 times.&lt;br /&gt;&lt;br /&gt;I found "GOD" 33,663 times with the first appearance at 3,186 digits.&lt;br /&gt;&lt;br /&gt;As expected, the smaller the text string, the more likely it is to be found.  Most words and strings up to 6 characters can be found in the first billion digits of the square root of 2.  Strings 7 characters and longer, like "CALIFORNIA" are often not found.&lt;br /&gt;&lt;br /&gt;For fun, I ran a few searches for dates and numbers in the integer file, finding things like my birthday and dates of historic events.  Numeric strings are much easier to find.&lt;br /&gt;&lt;br /&gt;Next, I'll post one of my ruby scripts to calculate the square root of 2 digit by digit.  It is very slow and inefficient, but fun for tinkering.  I have a few more ideas for grappling with the root of 2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6602053665280947960?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6602053665280947960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6602053665280947960'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/11/root-2-500-million-glyphs.html' title='Root 2: 500 million glyphs'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6106171481563794111</id><published>2009-10-23T12:03:00.000-07:00</published><updated>2009-10-23T12:54:08.492-07:00</updated><title type='text'>Root 2: the shallow end of infinity</title><content type='html'>A couple of months ago, I got the semi-psychotic idea to search for numbers and strings in the digits of the square root of 2.  The idea is hardly unique.  There has been a fair amount of research into this area, a variation on the &lt;a href="http://en.wikipedia.org/wiki/Infinite_monkey_theorem"&gt;infinite monkeys typing on a typewriter theorem&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Why Root 2?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Because it wasn't Pi.  Pi is the probably the most studied math constant, so I wanted to start with something fundamental that wasn't pi.&lt;br /&gt;&lt;br /&gt;I needed an irrational constant, one that generated an infinite stream of random numbers, and root 2 was as good a choice as any.  I might argue that root 2 is even more commonly encountered than pi, in that it is found in the hypotenuse of a 1x1 square.  Surely, 1x1 squares are more common than circles in the modern world.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Infinite Integers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first challenge was to find or generate the integers of root 2.  With a quick search, I found up to 10 million digit files that had been created by NASA.  While a good start, I wanted a lot more than 10 million digits.  I ended up using the 1 million file from NASA as a control file to make sure that any other method I used to generate digits was validated by NASA.  My starting target was 1 billion digits, but I wanted the ability to go to an arbitrary number.&lt;br /&gt;&lt;br /&gt;When I started thinking about how to generate digits with a computer, I realized there were some unique hurdles in trying to calculate infinite precision numbers.  First, standard machine data types fail at the task.  64-bit integers give you a large work space, but floating point numbers are notorious about losing precision.  The math libraries of most languages work to about 15 digits, so those were out.&lt;br /&gt;&lt;br /&gt;I found more than &lt;a href="http://en.wikipedia.org/wiki/Methods_of_computing_square_roots"&gt;10 methods documented to compute square roots&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Baby Steps&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first attempt to calculate the square root of 2 was actually written by a colleague who was intrigued enough to implement the Babylonian method in clojure.  The first few tests seemed promising and matched the NASA file up to roughly 25,000 digits.  Where it broke down was after about 20 iterations where the run time exceeded 18 hours.  Getting to a very large number of digits did not appear to be practical.&lt;br /&gt;&lt;br /&gt;The next attempt was one I wrote using the Duplex method (in ruby).  Duplex has the advantage of computing one digit at a time and I was hoping this would avoid some of the problems with doing multiplication with millions of digits.  There may have been a flaw in my ruby implementation because it got off track past digit 53 when I compared the results with the NASA file.  I was careful to follow the example I found in Wikipedia, but I must have made some kind of mistake because it always diverged.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Standing on Shoulders&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Like any good programmer, I quickly decided to search for working code that someone else had written.  I found a very old C++ implementation, but also a handful of working programs.  The one I tried first was &lt;a href="http://numbers.computation.free.fr/Constants/PiProgram/pifast.html"&gt;PiFast&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;PiFast is a Windows program that can calculate many constants in addition to Pi.  Since my main computer is a Macbook, I loaded it into my VMware virtual machine running XP.  As you might imagine, it was more than a little CPU intensive.  After a few short trial runs, I let it loose on a 1 billion digit computation that for all intents locked my machine for about 11 hours.  At the end, I had a file of 1 billion digits, the first million of which validated perfectly against the NASA file.&lt;br /&gt;&lt;br /&gt;To validate and test the file -- a 1 gigabyte file -- I wrote a number of scripts (ruby is my scripting language of choice these days) to test the digits, and manipulate the file in several ways.&lt;br /&gt;&lt;br /&gt;In my next post, I'll talk about how I converted digits to letters and what my early searches turned up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6106171481563794111?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6106171481563794111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6106171481563794111'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/10/root-2-shallow-end-of-infinity.html' title='Root 2: the shallow end of infinity'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-817496931073899787</id><published>2009-09-25T12:17:00.000-07:00</published><updated>2009-09-25T12:26:27.752-07:00</updated><title type='text'>Introduction to AutoFS in Mac OS X</title><content type='html'>&lt;span style="font-style:italic;"&gt;Note: I originally published this article on&lt;/span&gt; &lt;a href="http://lowendmac.com"&gt;Low End Mac&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;OS X uses an AutoFS code stack based on Sun's Solaris version of Unix. Many of the advanced features are not documented very well, and this can be an issue unless you are familiar with Solaris. I was not and had to do quite a bit of digging.&lt;br /&gt;&lt;br /&gt;AutoFS is often used in enterprise environments to set up network-based home directories and other network mounts for users at login. It can also dynamically mount network shares on access.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;OS X auto_master and auto_home&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The /etc/auto_master file controls the auto-mounted Network File System (NFS) file systems. If you are going to mount NFS volumes from a Linux server, there is one gotcha that I covered in an &lt;a href="http://commandlinemac.blogspot.com/2009/06/playing-nice-with-linux-nfs.html"&gt;earlier blog post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The auto_master defines all "maps" which are collections of automounts related by mount point and organized in one file (or directory service entry). Here is what the default file looks like on my Mac:&lt;br /&gt;&lt;pre&gt;#&lt;br /&gt;# Automounter master map&lt;br /&gt;#&lt;br /&gt;+auto_master            # Use directory service&lt;br /&gt;/net                    -hosts          -nobrowse,nosuid&lt;br /&gt;/home                   auto_home       -nobrowse&lt;br /&gt;/Network/Servers        -fstab&lt;br /&gt;/-                      -static&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The plus (+) sign in front of the auto_master entry tells OS X to look in the directory service (Open Directory, LDAP, etc.) for an automount record and use it if found.&lt;br /&gt;&lt;br /&gt;Notice the /home entry is set to auto_home, and because it is not a full path, it is assumed to be /etc/auto_home. It is an example of an indirect map. The mount point in the local directory is defined, but the remote mounts are defined in the /etc/auto_home map file. Network users who login to the local machine will have their home directories mounted in /home according to the details in /etc/auto_home.&lt;br /&gt;&lt;br /&gt;Here is the default /etc/auto_home file:&lt;br /&gt;&lt;pre&gt;#&lt;br /&gt;# Automounter map for /home&lt;br /&gt;#&lt;br /&gt;+auto_home      # Use directory service&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once again, we see the plus sign telling OS X to look for an auto_home record in the directory service. No further details are defined.&lt;br /&gt;&lt;br /&gt;The last two lines in auto_master handle NFS mounts defined in the /etc/fstab file, the common file system mount table in Linux and other Unix flavors. The /etc/fstab file is deprecated in OS X and not recommended.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Applying changes to autofs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The automount process will not detect changes made to auto_master or other map files unless you tell it. This command tells the process to read all map files again:&lt;br /&gt;&lt;br /&gt;sudo automount -vc&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;AutoFS wildcards&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wildcards can be used in mount map files to allow directory substitution. For example, if you had this defined in auto_master:&lt;br /&gt;&lt;br /&gt;/opt    auto_public&lt;br /&gt;&lt;br /&gt;And this defined in /etc/auto_public:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;*       nfs.mydomain.com:/public/&amp;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, when /opt/bin was accessed, nfs.mydomain.com:/public/bin would be mounted on /opt/bin. The same would apply for any subdirectory accessed under /opt.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Other Map Types&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OS X AutoFS supports &lt;span style="font-style:italic;"&gt;direct maps&lt;/span&gt;, where the local mount points are defined inside the mount map file, and &lt;span style="font-style:italic;"&gt;indirect maps&lt;/span&gt;, where the local mount point is defined in auto_master. The wildcard example above is an indirect map. There are also &lt;span style="font-style:italic;"&gt;executable maps&lt;/span&gt; where the mount map file is actually an executable shell script that returns the names of the mount points within the trigger folder. Exploring executable maps is left as an exercise for the reader. Finally, you can define static maps in /etc/fstab or in the Directory Utility Mounts tab.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Other file system types&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;All of the examples shown use the NFS file system. OS X autofs can also handle Apple File System (AFP) and Microsoft Server Message Block (SMB) file systems.&lt;br /&gt;&lt;br /&gt;To use these file systems, add the -fstype=afp and -fstype=smbfs options when defining the remote mount points. (Note: You cannot use smbfs for remote home directories unless you are using the Microsoft Active Directory service plugin.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-817496931073899787?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/817496931073899787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/817496931073899787'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/09/introduction-to-autofs-in-mac-os-x.html' title='Introduction to AutoFS in Mac OS X'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5689099543960867535</id><published>2009-06-27T09:10:00.000-07:00</published><updated>2009-06-27T11:50:44.649-07:00</updated><title type='text'>Playing nice with Linux NFS</title><content type='html'>I naively assumed that mounting an NFS volume exported by Linux would be uneventful, and it should be.  My initial attempt to manually perform an NFS mount failed without any client side error message.&lt;br /&gt;&lt;br /&gt;Checking system logs on the Mac revealed nothing.&lt;br /&gt;&lt;br /&gt;The Linux NFS server (Red Hat Enterprise 5) complained with this warning:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;nfsd: request from insecure port (192.168.7.130:49232)!&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After some Internet sleuthing, I found Mac client side NFS tries to mount NFS volumes over high TCP ports (&gt;1024).  You must explicitly tell the Linux NFS server to accept mount requests on high ports by adding the "&lt;b&gt;insecure&lt;/b&gt;" option to /etc/exports.  For example,&lt;br /&gt;&lt;code&gt;&lt;br /&gt;/nfstest 192.168.206.0/24(rw,async,insecure)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then, NFS mounts from OS X should work as expected.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5689099543960867535?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5689099543960867535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5689099543960867535'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/06/playing-nice-with-linux-nfs.html' title='Playing nice with Linux NFS'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4295088699209828786</id><published>2009-04-12T09:54:00.000-07:00</published><updated>2009-04-12T10:02:46.467-07:00</updated><title type='text'>Automating FTP on the Mac</title><content type='html'>There is no shortage of GUI FTP programs, but kicking it old school on &lt;br /&gt;the command line allows you to easily automate uploads and downloads. &lt;br /&gt;The best part is, there is nothing to install.  Everything you need &lt;br /&gt;waits patiently behind the warm glow of a Terminal session.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Mac command line FTP program&lt;/b&gt;&lt;br /&gt;The default command line FTP program in OS X 10.5 resides at:&lt;br /&gt;&lt;code&gt;/usr/bin/ftp&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;By all outward appearances and behavior, the Mac FTP program is&lt;br /&gt;the standard BSD version.  The man page is the standard BSD &lt;br /&gt;page and contains a wealth of useful information.&lt;br /&gt;A typical command line FTP session is interactive and goes something&lt;br /&gt;like this:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;login to an FTP server&lt;/li&gt;&lt;br /&gt;&lt;li&gt;issue commands (ls (list), get (download), put (upload))&lt;/li&gt;&lt;br /&gt;&lt;li&gt;quit&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you have a repetitive FTP task, the fun quickly fades into a&lt;br /&gt;mind numbing exercise.  This is where FTP automation&lt;br /&gt;shines.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The magical .netrc file&lt;/b&gt;&lt;br /&gt;What makes FTP automation possible is a magical, little known file &lt;br /&gt;called &lt;i&gt;.netrc&lt;/i&gt;.  The .netrc file is a plain text file that is &lt;br /&gt;hidden (the file name starts with a period) and lives in the root of &lt;br /&gt;your home directory. The .netrc file allows FTP to perform automatic &lt;br /&gt;logins to FTP servers based on the name.&lt;br /&gt;&lt;br /&gt;The .netrc is not created by default.  You have to create it manually. &lt;br /&gt;To create an empty .netrc file, open a Terminal and use the following &lt;br /&gt;commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;touch .netrc&lt;br /&gt;chmod 700 .netrc&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It is &lt;b&gt;critical&lt;/b&gt; that you issue the &lt;code&gt;chmod&lt;/code&gt; command to &lt;br /&gt;set the permissions so that only the owner of the file can view it.  If &lt;br /&gt;the permissions are not set correctly, the FTP client will assume it has &lt;br /&gt;been compromised and will refuse to use it.&lt;br /&gt;&lt;br /&gt;Inside the .netrc, you define a block of settings for each FTP&lt;br /&gt;server you use, including the machine name, the login ID and the&lt;br /&gt;password.  Here is what a typical block for a mythical FTP server:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;machine myftpserver.com&lt;br /&gt;  login myuser&lt;br /&gt;  password mypassword&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There are additional settings that can be included.  Check the FTP man &lt;br /&gt;page for more.  You can test your settings by typing "ftp &lt;br /&gt;myftpserver.com" at a Terminal prompt and it should automatically login.  &lt;br /&gt;Note that you can store multiple FTP server logins in the .netrc file.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sending FTP commands from a BASH shell script&lt;/b&gt;&lt;br /&gt;Once logins are automated, the final piece of the puzzle &lt;br /&gt;is to script a set of FTP commands.  The following example uses an&lt;br /&gt;advanced BASH shell scripting technique called a "here" document&lt;br /&gt;to group the FTP commands to be sent to the server.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;/usr/bin/ftp -d myftpserver.com &lt;&lt; ftpEOF&lt;br /&gt;   prompt&lt;br /&gt;   put "*.html"&lt;br /&gt;   quit&lt;br /&gt;ftpEOF&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The FTP command is issued with the -d flag (debug mode) to make it more &lt;br /&gt;verbose.  That makes any kind of error more obvious.  The connection is &lt;br /&gt;made to myftpserver.com using the ID and password from the .netrc file. &lt;br /&gt;Once the connection is made, the rest of the commands are issued one at &lt;br /&gt;a time until the end of the "here" document at the second "ftpEOF". Note &lt;br /&gt;that any valid FTP commands can be sent.  In the example, the &lt;br /&gt;&lt;code&gt;prompt&lt;/code&gt; command tells FTP not to prompt for multiple file &lt;br /&gt;operations, then the &lt;code&gt;put&lt;/code&gt; uploads all files with an html &lt;br /&gt;extension. If you want to go the extra mile, you can extend the shell &lt;br /&gt;script and do things like reconnect to the FTP server to verify the file &lt;br /&gt;sizes of your uploads.&lt;br /&gt;&lt;br /&gt;While there are several ways you can automate FTP, the nice thing about &lt;br /&gt;this method is that it is portable to Linux or any other Unix system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4295088699209828786?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4295088699209828786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4295088699209828786'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/04/automating-ftp-on-mac.html' title='Automating FTP on the Mac'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5820234768513813504</id><published>2009-03-21T08:19:00.000-07:00</published><updated>2009-03-21T08:32:43.765-07:00</updated><title type='text'>system_profiler - gathering hardware/software configuration</title><content type='html'>Another useful command line tool, system_profiler reports detailed information about the hardware and software configuration of the Mac.&lt;br /&gt;&lt;br /&gt;It reports the same information you can find in the Apple menu / About This Mac / More Info dialog.&lt;br /&gt;&lt;br /&gt;One of the things that makes it so useful is that you can look at the configuration of a system you are connected to remotely, like through a secure shell connection.&lt;br /&gt;&lt;br /&gt;There are three details levels available:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mini - report with no personal information&lt;/li&gt;&lt;li&gt;basic - basic hardware and network information&lt;/li&gt;&lt;li&gt;full - all available information&lt;/li&gt;&lt;/ul&gt;You select which detail level by passing it using the -detailLevel switch.  For example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;system_profiler -detailLevel mini&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If no detail level is passed, the default level is full.&lt;br /&gt;&lt;br /&gt;Because it generates so much information, you typically pass the output to the "less" utility, redirect it to a text file for browsing, or filter out what you are looking for using "grep".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5820234768513813504?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5820234768513813504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5820234768513813504'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/03/systemprofiler-gathering.html' title='system_profiler - gathering hardware/software configuration'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-596990594566918411</id><published>2009-02-25T10:18:00.000-08:00</published><updated>2009-02-25T10:23:10.281-08:00</updated><title type='text'>Enable/disable Fast User Switching from the command line</title><content type='html'>To enable fast user switching, use the defaults command from the terminal:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;defaults write /Library/Preferences/.GlobalPreferences  MultipleSessionEnabled -bool YES&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To disable fast user switching:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;defaults write /Library/Preferences/.GlobalPreferences  MultipleSessionEnabled -bool NO&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-596990594566918411?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/596990594566918411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/596990594566918411'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2009/02/enable-or-disable-fast-user-switching.html' title='Enable/disable Fast User Switching from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3432338100579550283</id><published>2008-12-27T06:08:00.000-08:00</published><updated>2008-12-27T08:10:00.293-08:00</updated><title type='text'>Apple System Logger</title><content type='html'>Despite appearances, the system logging facility is unique on OS X 10.4 and newer.  The syslogd daemon used on most Unix-like operating systems was replaced with the Apple System Logger (ASL).&lt;br /&gt;&lt;br /&gt;Instead of using a new program name, Apple just used the traditional Unix system logger name.  I think this can be a source of confusion and was not a great decision.&lt;br /&gt;&lt;h4&gt;Binary Logs, then Text Logs&lt;br /&gt;&lt;/h4&gt;Instead of logging everything to text log files in /var/log, ASL logs all messages to a binary database file, &lt;span style="font-style: italic;"&gt;/var/log/asl.db&lt;/span&gt;.  From there, certain messages are written to the more familiar text based logs based on settings in /etc/syslog.conf.&lt;br /&gt;&lt;br /&gt;In a way, Apple hacked the syslogd process, but did so in a way that maintains some level of backward compatibility with the knowledge and tools of system administrators coming from other Unix-like systems.  I admit I was quite surprised to find out how this mechanism has been implemented by Apple.&lt;br /&gt;&lt;br /&gt;The binary asl.db database is cleaned periodically, removing older messages from the database and keeping it from growing indefinately.  The text based logs are still compressed and rotated as usual.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reading log files&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can use the GUI utility, Console.app, to browse the Apple binary log database.  It has a nice case insensitive search ability.&lt;br /&gt;&lt;br /&gt;The command line interface to the Apple binary log is &lt;span style="font-style: italic;"&gt;syslog&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Entering syslog with no parameters dumps the entire database.  You can pipe the output through a grep command looking for a text string.  For example,&lt;br /&gt;&lt;code&gt;&lt;br /&gt;syslog  | grep Error&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;returned a large number of errors showing someone trying to login to my system via SSH as root:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Sat Dec 20 16:18:42 white com.apple.SecurityServer[22] &lt;error&gt;: checkpw() returned -2; failed to authenticate user root (uid 0).&lt;br /&gt;&lt;/error&gt;&lt;/code&gt;&lt;br /&gt;Yikes! Not to worry, when remote logins (SSH) are enabled, the default configuration does not allow root logins.  According to the man page, you can also search for particular keys in the database using the -k option.  Unfortunately, the list of valid keys is not in the man page.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Logging from a script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally, you can send a message to the log file using the -s parameter.  Messages in the traditional syslog system are categorized by severity, or log level:&lt;br /&gt;&lt;br /&gt;  Emergency     (level 0)&lt;br /&gt;  Alert         (level 1)&lt;br /&gt;  Critical      (level 2)&lt;br /&gt;  Error         (level 3)&lt;br /&gt;  Warning       (level 4)&lt;br /&gt;  Notice        (level 5)&lt;br /&gt;  Info          (level 6)&lt;br /&gt;  Debug         (level 7)&lt;br /&gt;&lt;br /&gt;To send a Warning message, use:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;syslog -s -l 4 "this is a warning"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;produces this in the log:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Sat Dec 20 18:42:29 white syslog[40323] &lt;warning&gt;: this is a warning&lt;br /&gt;&lt;/warning&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3432338100579550283?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3432338100579550283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3432338100579550283'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/apple-system-logger.html' title='Apple System Logger'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1005973760179050694</id><published>2008-12-22T01:24:00.000-08:00</published><updated>2008-12-22T08:36:14.995-08:00</updated><title type='text'>Disabling hardware via kernel extensions</title><content type='html'>You can disable hardware components in OS X by deleting (or renaming) the kernel extension directory that contains the driver for that piece of hardware.&lt;br /&gt;&lt;br /&gt;Kernel extensions are stored in subdirectories in &lt;span style="font-style: italic;"&gt;/System/Library/Extensions&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;In some cases, there is more than one driver involved, so you need to delete or rename multiple directories.&lt;br /&gt;&lt;br /&gt;Drivers for AirPort wireless:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AppleAirPort.kext &lt;/li&gt;&lt;li&gt;AppleAirPort2.kext &lt;/li&gt;&lt;li&gt;AppleAirPortFW.kext &lt;/li&gt;&lt;/ul&gt;Drivers for Bluetooth wireless:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IOBluetoothFamily.kext &lt;/li&gt;&lt;li&gt;IOBluetoothHIDDriver.kext &lt;/li&gt;&lt;/ul&gt;Drivers for external mass storage (external hard disks or USB keys):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IOUSBMassStorageClass.kext &lt;/li&gt;&lt;li&gt;IOFireWireSerialBusProtocolTransport.kext &lt;/li&gt;&lt;/ul&gt;You may have delete or rename the directories again after a system update because an update may restore the drivers.  After removing the drivers, reboot to make sure the hardware is disabled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1005973760179050694?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1005973760179050694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1005973760179050694'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/disabling-hardware-via-kernel.html' title='Disabling hardware via kernel extensions'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4712778718127085617</id><published>2008-12-19T11:29:00.000-08:00</published><updated>2008-12-20T18:48:21.336-08:00</updated><title type='text'>Another way to enable and disable root</title><content type='html'>I stumbled across another way to enable and disable root.  There is a program called &lt;code&gt;dsenableroot&lt;/code&gt; that can be used to both enable and disable the root account.&lt;br /&gt;&lt;br /&gt;The full path is /usr/sbin/dsenableroot and you must be an admin level user to run it.  In both cases, you will be prompted for your own user password.  When root is enabled, you are prompted to set the root password.&lt;br /&gt;&lt;br /&gt;This sequence enables root:&lt;br /&gt;&lt;code&gt;&lt;br /&gt; dsenableroot&lt;br /&gt;username = keithw&lt;br /&gt;user password:&lt;br /&gt;root password:&lt;br /&gt;verify root password:&lt;br /&gt;&lt;br /&gt;dsenableroot:: ***Successfully enabled root user.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This sequence disables root:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;dsenableroot -d&lt;br /&gt;username = keithw&lt;br /&gt;user password:&lt;br /&gt;&lt;br /&gt;dsenableroot:: ***Successfully disabled root user.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I generally like to have root enabled.  Here is my &lt;a href="http://commandlinemac.blogspot.com/2008/12/how-to-enable-os-x-root-user.html"&gt;older post on enabling root&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4712778718127085617?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4712778718127085617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4712778718127085617'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/another-way-to-enable-and-disable-root.html' title='Another way to enable and disable root'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6145688424509153702</id><published>2008-12-16T16:24:00.000-08:00</published><updated>2008-12-16T16:25:30.682-08:00</updated><title type='text'>Power settings from the command line</title><content type='html'>By request, I did a little digging to find out how to view and set power settings from the command line.&lt;br /&gt;&lt;br /&gt;The command to use is &lt;code&gt;pmset&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Instead of inventing the wheel again, please see this &lt;a href="http://www.macos.utah.edu/documentation/administration/pmset.html"&gt;most excellent article at University of Utah&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6145688424509153702?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6145688424509153702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6145688424509153702'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/power-settings-from-command-line.html' title='Power settings from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-829275151294622039</id><published>2008-12-16T16:16:00.000-08:00</published><updated>2008-12-16T16:24:40.595-08:00</updated><title type='text'>Speeding MacBook 802.11g connections</title><content type='html'>&lt;p&gt; My wife got a new MacBook a few weeks ago and was complaining of slow 802.11g wireless speeds at home. Normal troubleshooting went nowhere. Configuring the access point a little differently improved the situation. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;My wife took the MacBook into an Apple store and diagnostics were run on it showing no connection or performance issues. At home, it was still slow. This was odd because I have a slightly older MacBook and an even older Linux laptop working fine on the same wireless network. &lt;/p&gt;  I searched the Interwebs and found a post on an Apple related forum, forget where now, that suggested Macs &lt;i&gt;liked&lt;/i&gt; Channel 11 on 802.11g networks.  &lt;p&gt;With nothing to lose, I logged into the LinkSys access point and changed it to listen on Channel 11 (2.462 Ghz) by default. After this change, the new MacBook wireless performance was much better. I have no idea if there is some affinity for Channel 11 in Apple's hardware or software stack, or if there is less interference on that frequency, or if there is some other explanation. In any case, I thought it was worth sharing. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-829275151294622039?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/829275151294622039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/829275151294622039'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/speeding-macbook-80211g-connections.html' title='Speeding MacBook 802.11g connections'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4913386304801288621</id><published>2008-12-16T15:48:00.000-08:00</published><updated>2008-12-16T15:49:42.157-08:00</updated><title type='text'>Intro to ipfw</title><content type='html'>The low level firewall built into FreeBSD, ipfw, is also a part of OS X. It is one of the juicy UNIX bits that came along for the ride. The program itself lives at /sbin/ipfw and is a stateful packet filter capable of controlling access to and from specific IP addresses, ports, or combinations of each.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Firewall in System Preferences&lt;/h4&gt; &lt;p&gt; The firewall settings in Preferences are application level, and are separate from the low level rules set by ipfw. &lt;/p&gt; &lt;p&gt;On Leopard, you can get to the Firewall settings by going into System Preferences, select the Security icon, then the Firewall tab. The default setting is to allow all incoming connections. This is a little misleading because OS X comes with network services generally locked down until you enable them. &lt;/p&gt; &lt;p&gt;If you enable sharing, for example web sharing via the Apache 2 server in the Sharing Preferences, you will see Web Sharing appear in the firewall box in System Preferences. For most people, this level of control is fine, especially if you have another firewall between you and the Internet. For advanced configurations, ipfw can meet your needs. &lt;/p&gt;  &lt;h4&gt;Listing ipfw rules&lt;/h4&gt; &lt;p&gt; To list all active ipfw rules:&lt;br /&gt;&lt;code&gt; sudo ipfw list &lt;/code&gt; &lt;/p&gt; &lt;p&gt;Each rule is assigned a number up to 65535. Lower numbered rules are executed first, and if they don't apply to the packet in question, it moves down the list until it matches a rule. It is possible for a packet to be injected back into the rules, but usually a packet matches one rule and is either accepted, denied, or routed to a new destination. &lt;/p&gt;  &lt;h4&gt;Clearing all ipfw rules&lt;/h4&gt; &lt;p&gt; To list all active ipfw rules:&lt;br /&gt;&lt;code&gt; sudo ipfw flush &lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Creating custom rules&lt;/h4&gt; &lt;p&gt;The command line interface to ipfw is somewhat arcane, and you can get yourself into trouble if you don't know exactly what ports you need open and why. &lt;a href="http://www.ibiblio.org/macsupport/ipfw/"&gt;Here is an article that has some sample configurations&lt;/a&gt; and command line syntax examples. &lt;/p&gt; &lt;p&gt; While I normally prefer the command line to GUI tools, if you are just starting to use ipfw, I recommend the very friendly &lt;a href="http://www.hanynet.com/noobproof/"&gt;NoobProof&lt;/a&gt;, a program that offers a useful GUI front end to ipfw. &lt;/p&gt; &lt;p&gt; NoobProof comes preconfigured with all the common Mac services that you can enable or disable at the network level using ipfw. It also has an install tool to create a script that saves your configuration and starts it automatically after a reboot. It is a truly wonderful tool and a much safer way to get started with ipfw. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4913386304801288621?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4913386304801288621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4913386304801288621'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/intro-to-ipfw.html' title='Intro to ipfw'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-9114354484688319868</id><published>2008-12-16T15:46:00.001-08:00</published><updated>2008-12-16T15:46:47.128-08:00</updated><title type='text'>Airport command line utility</title><content type='html'>OS X Daily reports on a hidden but useful command line utility to monitor and tweak wireless connections called &lt;a href="http://osxdaily.com/2007/01/18/airport-the-little-known-command-line-wireless-utility/"&gt;airport&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-9114354484688319868?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/9114354484688319868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/9114354484688319868'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/airport-command-line-utility.html' title='Airport command line utility'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4693186573574412916</id><published>2008-12-16T14:28:00.000-08:00</published><updated>2008-12-16T14:29:07.601-08:00</updated><title type='text'>Date validation in Ruby using the Date object</title><content type='html'>Ruby has a date library to help you manage and manipulate dates. The date library provides Date and Date/Time objects that can be used to validate dates. In addition to straight Ruby, this helps work around a particularly nasty problem in version 1.x scaffolding date fields created by Rails.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Date object&lt;/h4&gt; &lt;p&gt; To use the date library, add this line near the top of your Ruby program:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;require 'date'&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The date library provide the Date object and the DateTime object, which adds time attributes to the Date object. To create a new Date object, pass the year, month, and day to the new Date constructor:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;mydate = Date.new(2008, 7, 11)&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To get the current date, use the Date.now method.  You can access different attributes of a date object like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; mydate.year&lt;br /&gt;mydate.month&lt;br /&gt;mydate.day &lt;/code&gt; &lt;/p&gt; &lt;p&gt; Converting a date object to a string returns a "YYYY-MM-DD" format.  For example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;mydate.to_s&lt;br /&gt;"2008-07-11"&lt;br /&gt;&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;A simple validate function&lt;/h4&gt; &lt;p&gt; One way to test for a valid date is to try to create a Date object. If the object is created, the date is valid, and if not, the date is invalid. Here is a function that accepts year, month, and day, then returns true if the date is valid and false if the date is invalid.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;  def test_date(yyyy, mm, dd)&lt;br /&gt;   begin&lt;br /&gt;     @mydate = Date.new(yyyy, mm, dd)&lt;br /&gt;     return true&lt;br /&gt;   rescue ArgumentError&lt;br /&gt;     return false&lt;br /&gt;   end&lt;br /&gt; end&lt;/pre&gt;  &lt;p&gt; The creation of the date object is wrapped in a begin...rescue...end block so that the error can be trapped if the date is invalid. Ruby throws an ArgumentError if the date is invalid and in that case, the function returns false. This version uses an instance variable (@mydate) because I wrote it to be used in a Rails application. &lt;/p&gt;  &lt;h4&gt;The nasty date problem in 1.x Rails scaffolding&lt;/h4&gt; &lt;p&gt;In version 1.x of Rails scaffolding, date fields in the edit view are generated with three drop down boxes, one for the year, one for the month, and one for the day. However, you are free to select invalid month/day combinations like February 30 and November 31. When these parameters are passed to the Rails update function in a scaffolding generated controller, it fails. &lt;/p&gt; &lt;p&gt;The crude solution I used to work around it was to edit the date prior to the attempt to save the record. In this case, the view sends the year to the controller in the dob(1i) field, the month in dob(2i), and the day in dob(3i). I convert them to integers, then call the function above to validate the date. If the date is invalid, I set a flash message and return to the edit screen.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;    # date validation code&lt;br /&gt;   @allparms = params[:dependent]&lt;br /&gt;   @yyyy = @allparms["dob(1i)"].to_i&lt;br /&gt;   @mm = @allparms["dob(2i)"].to_i&lt;br /&gt;   @dd = @allparms["dob(3i)"].to_i&lt;br /&gt;&lt;br /&gt;   if test_date(@yyyy, @mm, @dd) == false&lt;br /&gt;     flash[:error] = "Invalid date " + @mm.to_s + "/" + @dd.to_s + "/" + @yyyy.to_s&lt;br /&gt;     redirect_to :action =&gt; 'edit', :id =&gt; params[:id]&lt;br /&gt;     return&lt;br /&gt;   end&lt;/pre&gt; It seems like this rather basic problem would have been worked out in the Rails scaffolding, but it wasn't. I haven't tested Rails 2.0 scaffolding to see if it has similar issues. Other people have come up with more comprehensive solutions, like the &lt;a href="http://www.methods.co.nz/rails_date_kit/rails_date_kit.html"&gt;Rails date kit&lt;/a&gt;.  Take a look at something like that if you want more than a quick and dirty solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4693186573574412916?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4693186573574412916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4693186573574412916'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/date-validation-in-ruby-using-date.html' title='Date validation in Ruby using the Date object'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4898616077147120494</id><published>2008-12-16T14:25:00.000-08:00</published><updated>2008-12-16T14:27:03.086-08:00</updated><title type='text'>Beginning a Rails app -- for beginners</title><content type='html'>&lt;p&gt; After some trial and error, I got my first significant Ruby on Rails application off the ground. By significant, I mean a dozen related tables, about 20 controllers, and some tricky business logic. I had been exploring Rails for a while and created a few toy applications, but hammering this one out still presented a challenge. &lt;/p&gt; If you are used to programming CGI, PHP, or any application not built on a Model-View-Controller (MVC) framework, the learning curve is steep. While I can't offer up best practices -- I still have too much to learn -- I can offer up how-the-hell-do-I-get-started practices. For my own benefit, I created a list of steps to ease the pain of getting started.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Don't start here&lt;/h4&gt; &lt;p&gt;As I mentioned, unless you are coming from another MVC framework, the learning curve is kind of steep. Rails has lots of nooks and crannies, lots of helpers and shortcuts that are not obvious at first. So, even though this is a beginning Rails article, it is not a good place to start learning about Rails. I suggest starting with a good book. &lt;/p&gt; &lt;p&gt; The three books I always have at hand when working in Rails are: &lt;/p&gt;&lt;ul type="square"&gt;&lt;li&gt; Programming Ruby: The Pragmatic Programmers' Guide (pickaxe)&lt;/li&gt;&lt;li&gt;Agile Web Development with Rails&lt;/li&gt;&lt;li&gt;Rails Cookbook&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt; Also, I spent no time telling you &lt;a href="http://lowendmac.com/ed/winston/08kw/rails-posgresql-leopard.html"&gt;how to install or set up Rails on your system&lt;/a&gt;. There are many places to find such information, and if you are running a Mac, you already have Rails installed, though you may need to set up your database. &lt;/p&gt;  &lt;h4&gt;Four terminals at Rails central&lt;/h4&gt; &lt;p&gt;I do my text editing with vim (and sometimes nano), performing all work in the Terminal. Textmate and other GUI editors are popular but I prefer to stay in the Terminal. I have found that 4 terminal windows (or tabs) is ideal for working on a Rails application. That's 4 terminals for each Rails application, so if I was going to work on two at the same time, (unlikely), I would open 8. &lt;/p&gt; &lt;p&gt;I keep the Terminals ordered left to right and dedicate the first to working on Models, the next one for Views, the next one for Controllers, and the fourth one for performing other tasks such as debugging, reviewing logs, running scripts, etc. Keeping them in MVC order helps me stay organized while working and lets me switch between related views and controllers quickly. &lt;/p&gt; &lt;p&gt; Of course, I also have a browser window open to test changes as I go. &lt;/p&gt;  &lt;h4&gt;Start here&lt;/h4&gt; &lt;p&gt; Keep in mind, these are not rules, just basic guidelines that can help you approach a new project. &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;ol&gt;&lt;li&gt;create the app structure with "rails appname", this command generates the directory structure for the application and all the configuration files&lt;/li&gt;&lt;li&gt;create the database and tables (outside of rails), this is not the "rails" way, using migrations, but I prefer to do create/modify my database outside of rails&lt;/li&gt;&lt;li&gt;configure /config/database.yml with database details&lt;/li&gt;&lt;li&gt;create models, one per database table in app/models/&lt;/li&gt;&lt;li&gt;add validate helpers and validate methods to models in app/models/&lt;/li&gt;&lt;li&gt;create initial controllers/views using scaffolding with "ruby script/generate scaffold &lt;i&gt;Model-name&lt;/i&gt;"; run once for each table/model using the singular form of the table name for the controller. (The model name is capitalized and singular).&lt;/li&gt;&lt;li&gt;add business logic to a controller and set instance variables with data that will be needed in the view&lt;/li&gt;&lt;li&gt;customize the default template in /app/views/layouts/. Layouts are used to hold common HTML and embedded ruby such as headers and footers for your pages.  Usually, there is one layout per controller.&lt;/li&gt;&lt;li&gt;fill in the views (often rhtml files), one for each method in the controller.  Views and layouts control the presentation.&lt;/li&gt;&lt;li&gt;repeat each step above starting with step 6 (the scaffolding step) for each table/model in your application, you can come back and add or change models later&lt;/li&gt;&lt;li&gt;create new controllers not related to any models with "ruby script/generate controller &lt;i&gt;Controller-name&lt;/i&gt;" and add methods and views as needed&lt;/li&gt;&lt;li&gt;edit config/routes.rb to set the default URL for the application, rename public/index.html to index.html.old,&lt;br /&gt;e.g. map.connect '', :controller =&gt; "main", :action =&gt; "list"&lt;br /&gt;it must be the first map in the routes file.&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt;For pure data entry forms, create an empty controller method with a corresponding view. The view will contain the form and call a different method to accept the data and display the results (in yet another view). &lt;/p&gt; &lt;p&gt;If authentication is needed, use a "before_filter" at the top of each controller to handle logins and set session data. &lt;/p&gt; &lt;p&gt;In Rails version prior to 2.0, the scaffold script generates non-RESTful code, while in 2.0 and later, it generates RESTful code. This is a concern if you were used to the way Rails worked before 2.0. I am not sure RESTful is really better, but either way it can be confusing if you upgrade to Rails 2.0 in the middle of developing an application and find that scaffolding no longer works the same way. &lt;/p&gt;  &lt;h4&gt;Rails is flexible&lt;/h4&gt; &lt;p&gt;One of nice things about Rails is that it is flexible. You can use Rails helpers when constructing your views and web forms, or you can code them using standard HTML. If I was not comfortable using a particular form helper or could not get the syntax just right, I fell back to coding it in regular HTML. Rails had no problems merging form helpers and regular HTML in the same form within a view. In many parts of Rails, it is not all or nothing. You can use all, some, or none of the shortcuts. &lt;/p&gt; &lt;p&gt;The ease of modifying applications is another strength of Rails. It is relatively easy to add new functionality, tables, or features. You don't have to figure out everything before you start. It is also easy to rewire your application if you don't like the way it flows between screens or the way the pages are linked together. &lt;/p&gt;  &lt;h4&gt;Testing&lt;/h4&gt; &lt;p&gt;I think the official best practice to test a Rails app is to write test scripts that assert conditions and report problems found. I haven't used test scripts yet, my skills are not advanced enough. Up to now, I have relied on three other techniques. &lt;/p&gt; &lt;p&gt;The first is using the "script/debugger" to stop my application at certain points so I can display the values of objects and variables. I think the script/debugger was either removed or replaced in Rails 2.0. &lt;/p&gt; &lt;p&gt; The quick and dirty way to test is to write data to &lt;b&gt;:flash&lt;/b&gt; and view the contents of variables that way. The flash is a built in hash, part of the session data, used to display informational or error messages to the user. It is an easy way to debug simple problems. &lt;/p&gt; &lt;p&gt; For deeper problems, I write data to the log file using the &lt;i&gt;logger&lt;/i&gt; object. It takes a little time to sift through all the stuff in the development log file, but you can see trends and what is passing through the application before and after the trouble spot. &lt;/p&gt;  &lt;h4&gt;Railsbrain&lt;/h4&gt; &lt;p&gt; Finally, I want to point out an extremely useful reference web site for working with Rails: &lt;a href="http://railsbrain.com/"&gt;Railsbrain&lt;/a&gt;.  It has an Ajaxy API reference for multiple versions of Rails along with syntax and sample code. &lt;/p&gt; &lt;p&gt;I expect to come back to this article in six months and laugh at the inefficiency of the way I started doing Rails, but for now, it was enough to get that first useful application done. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4898616077147120494?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4898616077147120494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4898616077147120494'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/beginning-rails-app-for-beginners.html' title='Beginning a Rails app -- for beginners'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4270644990053977239</id><published>2008-12-16T10:35:00.000-08:00</published><updated>2008-12-16T10:36:00.146-08:00</updated><title type='text'>Ruby Snippets</title><content type='html'>As I get deeper into the Ruby world, it is helpful to have a few snippets of working code and syntax for common tasks to copy as needed. I expect to add to this tiny reference over time.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;updated July 9, 2008 to add a one liner to remove DOS line endings from a text file&lt;/i&gt;.&lt;br /&gt;&lt;h4&gt;Formatting numbers&lt;/h4&gt; &lt;p&gt; To format numbers, use the sprintf method. &lt;/p&gt;&lt;pre&gt;x = 1.00&lt;br /&gt;puts "x is $" + sprintf("%#0.2f", x)&lt;br /&gt;puts "x is " + sprintf("%#2d", x)&lt;/pre&gt;  &lt;p&gt; The output is: &lt;/p&gt;&lt;pre&gt;x is $1.00&lt;br /&gt;x is  1&lt;br /&gt;&lt;/pre&gt;   &lt;h4&gt;The defined? method&lt;/h4&gt; &lt;p&gt; The defined? method can be used on any object to see if it exists. &lt;/p&gt;&lt;pre&gt;x = 1&lt;br /&gt;if defined? x&lt;br /&gt; puts "x is defined"&lt;br /&gt;end&lt;/pre&gt;   &lt;h4&gt;Case statements&lt;/h4&gt; &lt;p&gt; Case statements are a more elegant way to handle a large number of conditions than using nested if statements. &lt;/p&gt;&lt;pre&gt;x = 3&lt;br /&gt;case x&lt;br /&gt;when "1"&lt;br /&gt; result = "x is 1"&lt;br /&gt;when "2"&lt;br /&gt; result = "x is 2"&lt;br /&gt;when "3"&lt;br /&gt; result = "x is 3"&lt;br /&gt;else&lt;br /&gt; result = "x is something else"&lt;br /&gt;end&lt;/pre&gt;   &lt;h4&gt;Substrings&lt;/h4&gt; &lt;p&gt; Ruby has (at least) two ways to reference parts of a string object.  One is to use the slice method: &lt;/p&gt;&lt;pre&gt;x = "abcde"&lt;br /&gt;y = x.slice(0,1)&lt;/pre&gt; The result is y = "a". &lt;pre&gt;x = "abcde"&lt;br /&gt;y = x.slice(-1,1)&lt;/pre&gt; The result is y = "e". &lt;pre&gt;x = "abcde"&lt;br /&gt;y = x.slice(2,3)&lt;/pre&gt; The result is y = "cde".  &lt;p&gt; The second way is to treat the string object as an array of characters like the C programming language. &lt;/p&gt;&lt;pre&gt;x = "abcde"&lt;br /&gt;y = x[2,3]&lt;/pre&gt; The result is y = "cde".    &lt;h4&gt;One liner to edit a file in place&lt;/h4&gt; &lt;i&gt;These one liners are also in the general Ruby article.&lt;/i&gt;&lt;br /&gt;&lt;p&gt; This command edits a file in place, performing a global text search/replace.  The &lt;i&gt;-p&lt;/i&gt; switch tells ruby to place your code in the loop &lt;code&gt;while gets; ...; print; end&lt;/code&gt;.  The &lt;i&gt;-i&lt;/i&gt;  tells ruby to edit files in place, and &lt;i&gt;-e&lt;/i&gt; indicates that a one line program follows.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ruby -p -i -e '$_.gsub!(/248/,"949")' file.txt&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;One liner to remove DOS line endings from a file&lt;/h4&gt; &lt;p&gt; A Unix or Mac text file uses a single line feed character to mark the end of a line (hex 0A). Files created on DOS or Windows use two characters, carriage return and line feed (hex 0D 0A). This command edits a file in place, removing the carriage returns.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ruby -p -i -e '$_.gsub!(/\x0D/,"")' file.txt&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;One liner to edit files in place and backup each one to *.old&lt;/h4&gt; &lt;p&gt; &lt;code&gt;ruby -p -i.old -e '$_.gsub!(/248/,"949")' *.txt&lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4270644990053977239?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4270644990053977239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4270644990053977239'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/ruby-snippets.html' title='Ruby Snippets'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1496609247482613129</id><published>2008-12-16T10:33:00.000-08:00</published><updated>2008-12-16T10:34:14.078-08:00</updated><title type='text'>Boot Camp</title><content type='html'>&lt;p&gt; Boot Camp is a set of tools to make dual booting an Intel Mac with Windows XP or Vista easy. The main reason you might want to dual boot as opposed to running Windows in emulation is for the extra performance from running natively. You might need this for gaming or a demanding application like CAD or photoshop where running in a virtual is just too slow. &lt;/p&gt; &lt;p&gt; You must have a CD or DVD with the full version of Windows XP or Vista.  An upgrade disk will not work. &lt;/p&gt;&lt;h4&gt;Update firmware&lt;/h4&gt; &lt;p&gt;Before beginning the process, Apple recommends updating the firmware on your Mac to the latest version. If you are applying all software updates, then you are probably already at the latest revision. If you are not sure, run the Software Update command from the Apple menu. &lt;/p&gt;  &lt;h4&gt;Boot Camp Assistant&lt;/h4&gt; &lt;p&gt;The next step is to run the Boot Camp Assistant program in the Utilities application folder. The first button in the assistant prompts you to print the installation and setup guide. I &lt;i&gt;highly&lt;/i&gt; recommend you take that advice. I didn't and (temporarily) ended up with a Mac that would not boot. The guide is 25 pages long and covers all the details to get Windows installed. For that reason, I'll just cover the juicy bits and tell you the mistakes I made along the way. &lt;/p&gt; &lt;p&gt;The assistant provides a disk partitioning tool that lets you carve out part of your disk for Windows. I allocated 12 GB and proceeded to installation. &lt;/p&gt;  &lt;h4&gt;Installing Windows&lt;/h4&gt; &lt;p&gt; I don't own Vista, so the rest of this article applies to Windows XP Pro SP2. &lt;/p&gt;&lt;p&gt;The installation of Windows works exactly like it does on any PC. When you get to the part where you have to choose what partition to install Windows on, select the one labeled &lt;b&gt;[BOOTCAMP]&lt;/b&gt;. Also, it is important to have Windows format the partition (as either NTFS or FAT32), or it will not be able to boot back into the partition after copying its files to disk. The mistake I made was not formatting the disk. Even though the Windows installer could copy files to the disk, it was not able to boot back into the partition, leaving my Mac temporarily out of order. &lt;/p&gt; &lt;p&gt;I was able to get back into OS X by holding down the mouse button during boot, which ejected the Windows CD. Then I printed the installation guide, where I learned about the formatting requirement. &lt;/p&gt;  &lt;h4&gt;Installing Windows drivers&lt;/h4&gt; &lt;p&gt;After Windows is installed, the next step is to install all the drivers for the Apple hardware. This was one of the best thought out parts of the process shows Apple's superior focus on human interface design. All you have to do is insert the OS X DVD while in Windows and it will start the driver installation wizard. Apple includes drivers for the video, audio, built-in camera, wireless airport, bluetooth, and more. It was the most painless Windows installation I have ever done. &lt;/p&gt;  &lt;h4&gt;Booting between OS X and Windows&lt;/h4&gt; &lt;p&gt;To boot into OS X from Windows, you have two options. The first is to right click on the Boot Camp tray icon that gets installed during the driver procedure and select the option to boot back into OS X. You can also choose to make OS X the default boot option in the Windows Boot Camp control panel applet. &lt;/p&gt; &lt;p&gt; To boot into Windows from OS X, go to System Preferences / Start Up Disk and select the Windows partition as the default. &lt;/p&gt; &lt;p&gt; Finally, you can select which operating system to start at boot time by holding down the Option button. &lt;/p&gt;  &lt;h4&gt;Keyboard quirks on a Macbook&lt;/h4&gt; &lt;p&gt;The differences in Apple and Windows keyboards is a source of minor annoyance. The keys are mapped in a reasonably intelligent way, but there are enough differences between the systems that some Windows features are awkard to use. &lt;/p&gt; &lt;p&gt;For example, to perform a right click, you hold two fingers on the trackpad and click the mouse button -- not a natural maneuver. The installation guide has a table that shows which keys and combinations map to Windows equivalents. Fortunately, most applications have some ability to map keys to make using them more comfortable. &lt;/p&gt;  &lt;h4&gt;Getting rid of Windows&lt;/h4&gt; &lt;p&gt;Finally, the Boot Camp Assistant program has an option that lets you delete the Windows partition and restore the space set aside for use with OS X again. So, experimenting with a dual boot set up is not a one way ticket. Easy to try, easy to undo. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1496609247482613129?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1496609247482613129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1496609247482613129'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/boot-camp.html' title='Boot Camp'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8162623584184909242</id><published>2008-12-16T10:31:00.000-08:00</published><updated>2008-12-16T10:32:34.289-08:00</updated><title type='text'>Ruby</title><content type='html'>&lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; is a popular text processing language that has gained a lot of momentum over the last few years, mostly due to the rise of &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;.  It has a lot of the good things from Perl, but implements a fully object oriented model and syntax.&lt;br /&gt;&lt;br /&gt;Ruby is part of the default install of OS X.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Working with Ruby gems&lt;/h4&gt; &lt;p&gt; Gems are Ruby packages that can be installed to extend the language or provide additional functions. Gems are managed using the &lt;code&gt;gem&lt;/code&gt; command.  To find all Ruby gems (packages) currently installed:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;gem list&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To install a new gem:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;gem install &lt;i&gt;package&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To update the gems package manager:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;update_rubygems&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Taint mode&lt;/h4&gt; &lt;p&gt; For untrusted scripts, add -T flag to ruby at the start of the script:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/ruby -T&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;One liner to edit a file in place&lt;/h4&gt; &lt;p&gt; This command edits a file in place, performing a global text search/replace.  The &lt;i&gt;-p&lt;/i&gt; switch tells ruby to place your code in the loop &lt;code&gt;while gets; ...; print; end&lt;/code&gt;.  The &lt;i&gt;-i&lt;/i&gt;  tells ruby to edit files in place, and &lt;i&gt;-e&lt;/i&gt; indicates that a one line program follows.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ruby -p -i -e '$_.gsub!(/248/,"949")' file.txt&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;One liner to remove DOS line endings from a file&lt;/h4&gt; &lt;p&gt; A Unix or Mac text file uses a single line feed character to mark the end of a line (hex 0A). Files created on DOS or Windows use two characters, carriage return and line feed (hex 0D 0A). This command edits a file in place, removing the carriage returns.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ruby -p -i -e '$_.gsub!(/\x0D/,"")' file.txt&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;One liner to edit files in place and backup each one to *.old&lt;/h4&gt; &lt;p&gt; &lt;code&gt;ruby -p -i.old -e '$_.gsub!(/248/,"949")' *.txt&lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8162623584184909242?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8162623584184909242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8162623584184909242'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/ruby.html' title='Ruby'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8487521061226957549</id><published>2008-12-16T10:30:00.002-08:00</published><updated>2008-12-16T10:31:31.679-08:00</updated><title type='text'>Intel vs. PowerPC Macs</title><content type='html'>I recently purchased a new Intel Macbook to replace my trusty iBook G4. Much has been written about the Apple's switch from PowerPC to Intel processors and there is no denying the market power of Intel, but I have some comments now that I have spent a little time with both kinds of Mac.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;RISC vs. CISC&lt;/h4&gt; &lt;p&gt; When comparing Intel and PowerPC micro processors, a common theme &lt;i&gt;used to be&lt;/i&gt; the Intel complex instruction set (CISC) vs. the IBM reduced instruction set (RISC). This line of reasoning may have had some merit in the 1980s or early 1990s, but processor architecture has blurred, with each family incorporating the best designs of the other. I don't read much about this any more because it mostly doesn't apply. &lt;/p&gt;  &lt;h4&gt;Big endian vs. little endian&lt;/h4&gt; &lt;p&gt; The &lt;a href="http://en.wikipedia.org/wiki/Endianness"&gt;endianness of a processor&lt;/a&gt; refers to the byte order of data in memory. Specifically, big endian processors, (traditionally the PowerPC line), stored the most significant bytes first, while little endian, (the Intel line), stored the significant bytes last. If you have ever debugged data or instructions in memory, big endian is the logical way you would expect to see things, a more natural or human way to read memory. Little endian data looks garbled to me. &lt;/p&gt; &lt;p&gt;I started my programming life long ago on an IBM mainframe (big endian) and wrote quite a few lines of assembly language. I actually enjoyed working with the mainframe register architecture and assembly was a joy. When I started working with Intel PCs, assembly language became a nightmare. The registers could be addressed partially using one mneumonic, fully with another, and the debugger showed bytes in the strange little endian order. It was a real buzz kill. &lt;/p&gt; &lt;p&gt;Today, with optimizing compilers and high level languages, it doesn't make much difference any more. Most modern languages are so high level (my current favorite is Ruby), that endianess is transparent. Some processors can even be programmed to change their endianess. So, other than personal preference, and a slight distrust of engineers that prefer little endian, this is a difference that doesn't carry much weight. &lt;/p&gt;  &lt;h4&gt;Power, heat, and batteries&lt;/h4&gt; &lt;p&gt;PowerPC processors have nearly always been more power efficient than Intel. This translates into less heat (less time running a cooling fan), and longer battery life. The battery life between my new Intel Core 2 Duo Macbook and my G4 iBook is dramatic. Even though the G4 is over 2 years old, it still gets about an hour and half of extra battery life. Certainly, part of that is because it also has a smaller and dimmer screen, but the processor architecture is also a factor. I was shocked at how fast the Macbook battery ran out the first week I had it. It is still better than a Windows laptop, but a step backward compared to the G4. &lt;/p&gt;  &lt;h4&gt;Binaries&lt;/h4&gt; &lt;p&gt;The operating system was not the only thing that had to be compiled to run on Intel processors. To take advantage of native speed, every application had to be recompiled. Some software vendors took their time building Intel binaries. Apple provided the "Universal binary" solution ahead of the switch so the application hit wasn't too harsh. &lt;/p&gt;  &lt;h4&gt;The virtual plus&lt;/h4&gt; &lt;p&gt;Apart from the ability of Intel to supply Apple with enough processors, the switch enabled fast virtual machine technology that doesn't rely on software emulation to work. Applications like Parallels and Vmware Fusion give the Intel based Macs a vastly improved capability to run Windows, Linux, and other operating systems with OS X as the host. I tried running Linux on the free Q virtual machine on the G4 and it was almost too slow to use. Running VMware Fusion, I have a couple of Linux distributions running graphical X desktops at near native speed. In this sense, the switch to Intel was a virtual plus. &lt;/p&gt;  &lt;h4&gt;Does it matter?&lt;/h4&gt; &lt;p&gt;How you weigh the positives and negatives above determines how you view the switch. In the end, the best things about a Mac still exist in the Intel world, and apart from the good folks at IBM, Motorola, and Intel, most people won't notice. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8487521061226957549?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8487521061226957549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8487521061226957549'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/intel-vs-powerpc-macs.html' title='Intel vs. PowerPC Macs'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3367023127031496414</id><published>2008-12-16T10:30:00.001-08:00</published><updated>2008-12-16T10:30:44.177-08:00</updated><title type='text'>How to turn off Dashboard</title><content type='html'>The Dashboard is a handy feature of OS X to keep information flakes and small tools at the ready.&lt;br /&gt;&lt;p&gt; To turn Dashboard off, run the following command from the Terminal:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; defaults write com.apple.dashboard mcx-disabled -boolean yes &lt;/code&gt; &lt;/p&gt; &lt;p&gt; To turn Dashboard on:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; defaults write com.apple.dashboard mcx-disabled -boolean no &lt;/code&gt; &lt;/p&gt; &lt;p&gt; Because Dashboard is a component of the Dock, you need to restart the Dock after making either change:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; killall -1 Dock &lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3367023127031496414?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3367023127031496414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3367023127031496414'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/how-to-turn-off-dashboard.html' title='How to turn off Dashboard'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4921150221094714435</id><published>2008-12-16T10:28:00.000-08:00</published><updated>2008-12-16T10:30:07.417-08:00</updated><title type='text'>Advanced BASH scripting guide</title><content type='html'>User &lt;i&gt;forbade&lt;/i&gt; pointed out this great guide from the Linux Documentation Project:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tldp.org/LDP/abs/abs-guide.pdf"&gt;Advanced BASH scripting (pdf)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is also &lt;a href="http://tldp.org/guides.html"&gt;available in other formats&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4921150221094714435?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4921150221094714435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4921150221094714435'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/advanced-bash-scripting-guide.html' title='Advanced BASH scripting guide'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2431570560155470771</id><published>2008-12-16T10:25:00.002-08:00</published><updated>2008-12-16T10:27:03.032-08:00</updated><title type='text'>Amazon S3 from the command line</title><content type='html'>Amazon.com offers a variety of web services to make building highly scalable web applications easier. One of those services is called the &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=46"&gt;Simple Storage Service (S3)&lt;/a&gt;. It provides a way to store and retrieve files (up to 5 GB each) on Amazon's distributed servers. S3 has both a SOAP and REST API. You can use the S3 REST API with only the native command line utilities installed by default in OS X Leopard (and Linux).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Why use Amazon S3?&lt;/h4&gt; &lt;p&gt; Amazon S3 is designed to be robust, fast, and inexpensive. It is ideal for serving small images or small files for web sites. It is also a good solution for off site backups (less than 5 GB) because the storage is redundant and inexpensive. For very large backup files, it is not the best solution because of the file size limitation (which can be worked around in some cases), and because the bandwidth is prohibitive. &lt;/p&gt;  &lt;h4&gt;How does S3 work?&lt;/h4&gt; &lt;p&gt;While S3 is cheap, it is not free. To use it, you first need to sign up with Amazon Web Services and obtain an access key ID and secret key. The access keys are required to authenticate to Amazon and to use the API. &lt;/p&gt; &lt;p&gt; Conceptually, S3 stores files (objects) in &lt;i&gt;buckets&lt;/i&gt;. First, you create a bucket, then you store objects in the bucket. The combination of the bucket and object ID must be unique. To S3, all objects are binary blobs. You can attach some meta data to an object when it is stored, but S3 doesn't verify that the meta data accurately describes the object. &lt;/p&gt; &lt;p&gt;With the REST API, standard HTTP transactions are used to GET, PUT, and DELETE objects in buckets. There is no incremental update option. To update an object, upload and replace it with the new version. &lt;/p&gt;  &lt;h4&gt;Using S3 from BASH&lt;/h4&gt; &lt;p&gt;As part of a consulting project, I was asked to upload rotating backup files to S3. The backup files consisted of compressed source code and database dumps. &lt;/p&gt; &lt;p&gt;I started by looking at the sample code on the Amazon developer site. I downloaded some working PHP code that used the REST API and began hacking on it. However, I ran into a serious problem when I tested uploading one of the backups. The sample code was designed for small files that could be uploaded in a single HTTP transaction. It had a limitation of 1 MB, while my backup files were around 250 MB. I could have tried to retool the code to break apart the backup file and upload in chunks but that seemed daunting. Instead, I went back to the developer site and found a &lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1081&amp;amp;categoryID=47"&gt;set of BASH scripts&lt;/a&gt; that use the &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;openssl&lt;/code&gt; utilities to handle the heavy lifting.   &lt;/p&gt; &lt;p&gt; There are two scripts in the package provided by the developer "nescafe5", &lt;code&gt;hmac&lt;/code&gt; and &lt;code&gt;s3&lt;/code&gt;.  The &lt;code&gt;s3&lt;/code&gt; script is the main script and it calls &lt;code&gt;hmac&lt;/code&gt; to calculate the hashes needed to authenticate to S3.  Then, it uses &lt;code&gt;curl&lt;/code&gt; to upload, download, list, or delete the objects in a bucket.  It can also create and destroy buckets. &lt;/p&gt; &lt;p&gt; To use the &lt;code&gt;s3&lt;/code&gt; script, you need to store your Amazon secret key in a text file and set two environment variables. The INSTALL file included with the package has all the details. The only tricky part I ran into, and from the comments on Amazon, other people ran into, is how to create the secret key text file. &lt;/p&gt; &lt;p&gt;If you open a text editor like vim or nano, copy in your secret key and save the file, the editors will add a new line character (hex 0A) to the end of the file. The script requires the file to be exactly 40 bytes, the length of the secret key, or it will complain and stop. To create the text file without a new line, use the &lt;code&gt;echo&lt;/code&gt; command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; echo -n "secret-key" &gt; secret-key-file.txt &lt;/code&gt; &lt;/p&gt; &lt;p&gt; The -n switch tells echo to not include a new line character and results in a text file of exactly 40 bytes. Once I got the key file created correctly, the &lt;code&gt;s3&lt;/code&gt; script started working, and I was able to upload, download, and list objects in S3. &lt;/p&gt; &lt;p&gt; Here is an example of a test script I used:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;# export required variables&lt;br /&gt;export S3_ACCESS_KEY_ID="99XC79990C39996AR999"&lt;br /&gt;export S3_SECRET_ACCESS_KEY="secret-key-file.txt"&lt;br /&gt;&lt;br /&gt;# store a file&lt;br /&gt;./s3 put bucketname objectname /path/to/local/file&lt;br /&gt;&lt;br /&gt;# list objects in a bucket&lt;br /&gt;./s3 ls bucketname&lt;br /&gt;&lt;br /&gt;# download a file&lt;br /&gt;./s3 get bucketname objectname /path/to/local/file&lt;br /&gt;&lt;/pre&gt;  &lt;h4&gt;Mac and Linux friendly&lt;/h4&gt; &lt;p&gt; I tested the s3 scripts on both OS X Leopard and Red Hat Enterprise Linux 4 and they worked perfectly on both.  &lt;a href="http://www.amazon.com/gp/browse.html?node=3435361"&gt;Amazon Web Services&lt;/a&gt; offers powerful solutions to some tough problems. Other services offered include the Elastic Compute Cloud (EC2) for virtual servers, Simple Queue Service (SQS) for passing messages between applications, and Mechanical Turk for delegating work to humans. There is some truly cutting edge stuff going on at Amazon. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2431570560155470771?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2431570560155470771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2431570560155470771'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/amazon-s3-from-command-line.html' title='Amazon S3 from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-110386037568466638</id><published>2008-12-16T10:25:00.001-08:00</published><updated>2008-12-16T10:25:32.961-08:00</updated><title type='text'>Say say say</title><content type='html'>The &lt;code&gt;say&lt;/code&gt; command tells your Mac to talk back, reciting either a string of text or reading an entire file.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;To have the computer read a string of text&lt;/h4&gt; &lt;p&gt; Open a Terminal and type:&lt;br /&gt;&lt;code&gt; say "This is a string of text." &lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;To have the computer read text from a file&lt;/h4&gt; &lt;p&gt; Open a Terminal and type:&lt;br /&gt;&lt;code&gt; say -f /path/to/text/file &lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Using a different voice&lt;/h4&gt; &lt;p&gt; The speech synthesis system comes with several voices. You can see all the voices available in System Preferences / Speech. The default voice selected in System Preferences is used unless a different one is specified with the &lt;code&gt;-v&lt;/code&gt; switch.  For example, to use the "Kathy" voice:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; say -v Kathy "This is a string of text." &lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-110386037568466638?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/110386037568466638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/110386037568466638'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/say-say-say.html' title='Say say say'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7109914826738998133</id><published>2008-12-16T10:24:00.000-08:00</published><updated>2008-12-16T10:25:05.555-08:00</updated><title type='text'>Installing a .dmg application from the command line</title><content type='html'>&lt;p&gt; An intrepid reader asked the following question:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; How do you install a .dmg package from the command line? &lt;/code&gt; &lt;/p&gt; &lt;p&gt; Many applications are distributed as disk images, a compressed binary format. If you double click a disk image in the Finder, it is mounted automatically. Once mounted, installation of the application is typically done by dragging an icon to the Applications folder. The same can be accomplished from the command line using two commands, &lt;code&gt;hdiutil&lt;/code&gt; and &lt;code&gt;cp&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt; The following steps show the installation of a popular VNC client for OS X called "Chicken of the VNC". It can be used as a remote desktop client for Linux, Mac, or Windows hosts. &lt;/p&gt; &lt;p&gt; The download file is named "cotvnc-20b4.dmg".  Here are the steps needed to install it remotely from the command line.&lt;br /&gt;&lt;i&gt;note: this technique can be used from a local Terminal window or a remote SSH connection.&lt;/i&gt; &lt;/p&gt;  &lt;h4&gt;Mount the disk image&lt;/h4&gt; &lt;p&gt; The first step is to mount (or attach) the disk image.  From the command line, use:&lt;br /&gt;&lt;code&gt; hdiutil mount cotvnc-20b4.dmg &lt;/code&gt;&lt;br /&gt;I received the following output:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;Checksumming Driver Descriptor Map (DDM : 0)…&lt;br /&gt;    Driver Descriptor Map (DDM : 0): verified   CRC32 $767AD93D&lt;br /&gt;Checksumming Apple (Apple_partition_map : 1)…&lt;br /&gt;    Apple (Apple_partition_map : 1): verified   CRC32 $DD66DE0F&lt;br /&gt;Checksumming disk image (Apple_HFS : 2)…&lt;br /&gt;..............................................................................&lt;br /&gt;         disk image (Apple_HFS : 2): verified   CRC32 $EF1F362F&lt;br /&gt;Checksumming  (Apple_Free : 3)…&lt;br /&gt;                   (Apple_Free : 3): verified   CRC32 $00000000&lt;br /&gt;verified   CRC32 $F5A3FFA1&lt;br /&gt;/dev/disk1           Apple_partition_scheme          &lt;br /&gt;/dev/disk1s1         Apple_partition_map             &lt;br /&gt;/dev/disk1s2         Apple_HFS                       /Volumes/Chicken of the VNC&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; A mounted disk image appears on the Desktop, in the Finder, and more importantly shows up as a directory in /Volumes. In this case, the last line of output from hdiutil showed exactly where the disk image was mounted. &lt;/p&gt; &lt;p&gt;Sometimes when a disk image is mounted, it will prompt you to agree to a license first. In that case, the text that would normally appear in a GUI dialog box instead appears in the Terminal window. Once you scroll to the bottom of the agreement, you can type in Y to continue or N to stop. The Firefox disk image is one example of a package that displays a license before mounting. &lt;/p&gt;  &lt;h4&gt;Install the application&lt;/h4&gt; &lt;p&gt; Use the &lt;code&gt;cp&lt;/code&gt; command to copy the application to /Applications:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo cp -R "/Volumes/Chicken of the VNC/Chicken of the VNC.app" /Applications&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The &lt;code&gt;-R&lt;/code&gt; switch means to copy recursively, in other words, copy everything from that location including all subdirectories and files below. &lt;i&gt;It is important to leave off the trailing "/" from the "Chicken of the VNC.app" directory, or the command will not copy the directory itself, just the contents&lt;/i&gt;.  After entering your password, the application will be installed and ready to use. &lt;/p&gt; &lt;p&gt; Most applications can simply be copied to the /Applications directory. However, some are distributed in a .pkg format and must be installed using the &lt;code&gt;installer&lt;/code&gt; command instead of &lt;code&gt;cp&lt;/code&gt;.  To install a .pkg, use this command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo installer -package /path/to/package -target "/Volumes/Macintosh HD"&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Unmount the disk image&lt;/h4&gt; &lt;p&gt; To tidy up, return to your home directory and unmount the disk image:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; cd ~&lt;br /&gt;hdiutil unmount "/Volumes/Chicken of the VNC/" &lt;/code&gt; &lt;/p&gt; &lt;p&gt; You should see this message after the unmount:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; "/Volumes/Chicken of the VNC/" unmounted successfully. &lt;/code&gt; &lt;/p&gt; &lt;p&gt; Installing applications from a .dmg package at the command line is not something you need to do every day. But it is a nice tool to have if you want to install an application on a remote server or script the installation of a package to a group of desktop Macs. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7109914826738998133?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7109914826738998133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7109914826738998133'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/installing-dmg-application-from-command.html' title='Installing a .dmg application from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3825123800531375471</id><published>2008-12-16T10:22:00.000-08:00</published><updated>2008-12-16T10:24:29.076-08:00</updated><title type='text'>Updating Apple software from the command line</title><content type='html'>Macs check for system updates on their own (by default) and prompt you when there are updates to apply to your system. If you want to update immediately, like after a fresh OS X install, you can check for updates by clicking on the Apple menu icon, then Software Update. However, if you want to update a system remotely -- a frequent need for remote servers -- you can do it from the command line.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The softwareupdate command&lt;/h4&gt; &lt;p&gt; Use the &lt;code&gt;softwareupdate&lt;/code&gt; (all one word) command to check for updates or install them.  Here are some commonly used switches:&lt;br /&gt;&lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Switch&lt;/th&gt;     &lt;th&gt;Effect&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;&lt;code&gt;--list&lt;/code&gt;&lt;/td&gt;     &lt;td&gt;list available updates&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;&lt;code&gt;--install&lt;/code&gt;&lt;/td&gt;     &lt;td&gt;install all available updates&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;&lt;code&gt;--install &lt;i&gt;packagename&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;     &lt;td&gt;install only &lt;i&gt;packagename&lt;/i&gt;&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;&lt;code&gt;--schedule on&lt;/code&gt;&lt;/td&gt;     &lt;td&gt;turn automatic checking on&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;&lt;code&gt;--schedule off&lt;/code&gt;&lt;/td&gt;     &lt;td&gt;turn automatic checking off&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;br /&gt;&lt;p&gt; If you check for new software and there is nothing to apply, you get output like this:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;iBook-G4:~ keithw$ softwareupdate --list&lt;br /&gt;Software Update Tool&lt;br /&gt;Copyright 2002-2007 Apple&lt;br /&gt;&lt;br /&gt;No new software available.&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt; When updates are available, you get output like this:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;iBook-G4:~ keithw$ softwareupdate --list&lt;br /&gt;Software Update found the following new or updated software:&lt;br /&gt;  * iLifeSupport82-8.2&lt;br /&gt;       iLife Support (8.2), 2770K [recommended]&lt;br /&gt;  * QuickTime-7.4.1&lt;br /&gt;       QuickTime (7.4.1), 59940K [recommended] [restart]&lt;br /&gt;  * MacOSXUpd10.5.2-10.5.2&lt;br /&gt;       Mac OS X Update (10.5.2), 349324K [recommended] [restart]&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt; To install updates, use the &lt;code&gt;--install --all&lt;/code&gt; option:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;iBook-G4:~ root# softwareupdate --install --all&lt;br /&gt;Software Update Tool&lt;br /&gt;Copyright 2002-2007 Apple&lt;br /&gt;&lt;br /&gt;Downloading iLife Support       0..20..40..60..80..100&lt;br /&gt;Verifying iLife Support&lt;br /&gt;waiting iLife Support&lt;br /&gt;waiting QuickTime&lt;br /&gt;Downloading Mac OS X Update     0..20..40..60..80..100&lt;br /&gt;Verifying Mac OS X Update&lt;br /&gt;waiting Mac OS X Update&lt;br /&gt;Installing iLife Support        0..20..40..60..80..100&lt;br /&gt;Done iLife Support&lt;br /&gt;Installing QuickTime    0..20..40..60..80..100&lt;br /&gt;Done QuickTime&lt;br /&gt;Installing Mac OS X Update      0..20..40..60..80..100&lt;br /&gt;Done Mac OS X Update&lt;br /&gt;Done.&lt;br /&gt;&lt;br /&gt;You have installed one or more updates that requires that you restart your&lt;br /&gt;computer.  Please restart immediately.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3825123800531375471?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3825123800531375471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3825123800531375471'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/updating-apple-software-from-command.html' title='Updating Apple software from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5826773044930938183</id><published>2008-12-16T10:21:00.000-08:00</published><updated>2008-12-16T10:22:43.915-08:00</updated><title type='text'>Syncing Palm devices with the Mac via Bluetooth</title><content type='html'>&lt;p&gt; Until I figured out how to sync my Palm based Treo smartphone with the Palm Desktop on my iBook, I had no use for bluetooth. Before then, bluetooth was one of those technologies that was around but that I largely ignored. Now, the thought of syncing via USB cable seems so 20th century. As a bonus, I cover how to transfer camera images from the Treo to the Mac via bluetooth. &lt;/p&gt; &lt;p&gt;This article documents all the steps needed to set up wireless syncing via bluetooth between a Treo and Palm Desktop for the Mac. Since there are a variety of Palm based devices and OS X versions, it is offered as is. Just because it &lt;i&gt;"works for me"&lt;/i&gt; doesn't mean it will work for you.  At the least, you may get some useful hints for your situation. &lt;/p&gt;  &lt;h4&gt;Hardware&lt;/h4&gt; &lt;p&gt; My main Mac is currently an iBook G4 1.33 Ghz running Leopard (OS X 10.5.1). My Palm device is a Treo 650 smartphone running Palm OS Garnet (5.4.8). Both devices have native bluetooth wireless hardware. &lt;/p&gt; &lt;p&gt; &lt;a href="http://en.wikipedia.org/wiki/Bluetooth"&gt;Bluetooth&lt;/a&gt; is a low power, short range radio technology (wireless) designed to link devices together in a personal area network. Bluetooth 1.x operates over distances of about 10 meters with a data transfer rate of 720 kbps. While the low data rate is useless for large files, it works great for syncing Palm data or sending a few images back and forth. &lt;/p&gt;  &lt;h4&gt;Installing Palm Desktop&lt;/h4&gt; &lt;p&gt; My first stop was the &lt;a href="http://palm.com/"&gt;Palm web site&lt;/a&gt; where I downloaded the latest Palm Desktop software for Mac. The version I downloaded was 4.2.1 rev D which came in disk image (.dmg) format. I mounted the disk image and ran the installer. At the end of the installation, a reboot is required, probably to load the background processes cleanly. &lt;/p&gt;  &lt;h4&gt;Bluetooth configuration on the Mac&lt;/h4&gt; &lt;p&gt;After the reboot, I visited System Settings and went into the Sharing settings. There I enabled bluetooth sharing and required pairing for all actions. Pairing is the process of introducing bluetooth devices to one another using a shared &lt;i&gt;passkey&lt;/i&gt;. I learned later that pairing was not really required for Palm syncing, but I prefer to use it for file transfer so I checked all the pairing boxes. &lt;/p&gt; &lt;a href="http://www.commandlinemac.com/images/articles/sharing-crop.gif" target="_blank"&gt;&lt;img src="http://www.commandlinemac.com/images/articles/20080106132442362_1.gif" alt="" width="400" height="327" /&gt;&lt;/a&gt;  &lt;h4&gt;Configuring HotSync manager&lt;/h4&gt; &lt;p&gt;Staying on the Mac, go to Applications and open the Palm folder containing all the Palm Desktop applications. Run the HotSync Manager, go to the Connection Settings tab, and enable the &lt;i&gt;bluetooth-pda-sync-port&lt;/i&gt;. &lt;/p&gt; &lt;a href="http://www.commandlinemac.com/images/articles/bluetooth-sync-port-crop.gif" target="_blank"&gt;&lt;img src="http://www.commandlinemac.com/images/articles/20080106132442362_2.gif" alt="" width="400" height="285" /&gt;&lt;/a&gt; &lt;p&gt; The dialog box on my screen cut off the name, but if you select it, you can see the full name beneath the list of selections. It is the second choice in the list, below the bluetooth-modem. &lt;/p&gt; &lt;p&gt;As a final check of the Mac set up, I opened a Terminal and ran the following command to verify that the Palm Transport Monitor was running in the background:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; iBook-G4:~ keithw$ &lt;b&gt;ps aux | grep Palm&lt;/b&gt;&lt;br /&gt;keithw 130 0.1 0.3 154888 3468 ?? S 6:01PM 0:04.04 /System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp /Applications/Palm/Palm Desktop/Contents/Resources/Palm Desktop Background.app/Contents/MacOSClassic/Palm Desktop Background&lt;br /&gt;keithw 131 0.0 0.3 118108 3628 ?? S 6:01PM 0:00.79 /System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp /Applications/Palm/Transport Monitor/Contents/MacOSClassic/Transport Monitor &lt;/code&gt;&lt;/p&gt;  &lt;h4&gt;Bluetooth configuration on the Palm Treo&lt;/h4&gt; &lt;p&gt;On the Treo, go to the Communications group and open the Bluetooth application (it uses the Bluetooth icon). Make sure bluetooth is "On" and Discoverable is set to "Yes". &lt;/p&gt; &lt;p&gt;Then, click the "Setup Devices" button and on the next screen, click the "HotSync Setup" button. This starts a wizard-like procedure with 4 steps. The instructions use PC terminology and may appear confusing, but all of the Mac side set up should be done. Click Next to continue. &lt;/p&gt; &lt;p&gt; Step 1: says to create a virtual serial port on your PC, just click Next. &lt;/p&gt; &lt;p&gt; Step 2: We've already enabled the bluetooth-pda-sync-port in HotSync Manager, so just click Next. &lt;/p&gt; &lt;p&gt; Step 3: The local serial port is already enabled on the Mac, so click Next. &lt;/p&gt; &lt;p&gt;Step 4: click on the Launch HotSync button, it should start the first HotSync immediately. The "HotSync Progress" dialog should appear on the Mac indicating the first HotSync is under way. &lt;/p&gt; &lt;img src="http://www.commandlinemac.com/images/articles/20080106132442362_3.gif" alt="" width="358" height="218" /&gt; &lt;p&gt;Depending on how much data you have on your Palm, the first HotSync may take a long time. It has to transfer all of your data over bluetooth to the Mac. After the first HotSync is complete, only changed data will be transfered and HotSyncs will typically be quick. &lt;/p&gt;&lt;br /&gt; &lt;h4&gt;Transferring files via bluetooth&lt;/h4&gt; &lt;p&gt;Like most cell phones today, the Treo has a built in camera. Even though it is low resolution, it is still useful and convenient. I was looking for a zero cost way to transfer photos from the Treo to the Mac. Bluetooth was the answer. &lt;/p&gt;  &lt;h4&gt;Bluetooth configuration on the Mac&lt;/h4&gt; &lt;p&gt; See the section above with the same title for details and a screenshot for configuring bluetooth. &lt;/p&gt; &lt;p&gt;While pairing may not be absolutely required, I think it is the best practice to require it. Otherwise, anyone wandering by with a bluetooth device could upload files to your Mac. I can think of a lot of bad scenarios that might arise out of that configuration. &lt;/p&gt;  &lt;h4&gt;Pairing the Treo and Mac&lt;/h4&gt; &lt;p&gt;On the Treo, open the Bluetooth application (it uses the Bluetooth icon). Make sure bluetooth is "On" and Discoverable is set to "Yes". Then, click the "Trusted Devices" button, then "Add Device". &lt;/p&gt; &lt;p&gt; Select the Mac (it must also be discoverable) and click OK. &lt;/p&gt; &lt;p&gt; The Treo will prompt for a &lt;i&gt;passkey&lt;/i&gt;. Enter any sequence of digits (I only used 4 digits). Enter the same passkey on the Mac when prompted. Pairing is a one time set up procedure and you won't need to remember the passkey after they are paired. &lt;/p&gt;  &lt;h4&gt;Sending an image (or any file) to the Mac&lt;/h4&gt; &lt;p&gt; To send a camera image file, open any image on the Treo in the Media application.  Then, open the Media menu and select Send... &lt;/p&gt; &lt;p&gt;In the Send with dialog, choose Bluetooth..., then select the Mac you are paired with, then OK. The file will be sent and the Mac will prompt you to accept it. &lt;/p&gt; &lt;p&gt;After you accept it, the file is saved in the folder you configured in bluetooth sharing, the "Download" folder in my case. It will have a file name similar to "Photo_112307_003.jpg". &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5826773044930938183?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5826773044930938183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5826773044930938183'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/syncing-palm-devices-with-mac-via.html' title='Syncing Palm devices with the Mac via Bluetooth'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2547823412886916756</id><published>2008-12-14T18:01:00.000-08:00</published><updated>2008-12-19T12:10:26.767-08:00</updated><title type='text'>How to enable the OS X root user</title><content type='html'>The following information was found at spy-hill.com.&lt;br /&gt;&lt;br /&gt;This is the easiest method to enable the "root" account on a Mac if you are more of a CLI person:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Log in on the &lt;em&gt;Admin&lt;/em&gt; account. (Your normal, every day user account should not have administrative privileges!).  &lt;p&gt; &lt;/p&gt;&lt;/li&gt;&lt;li&gt; Open up a command shell in the Terminal application with     &lt;br /&gt;    &lt;tt&gt;Macintosh HD -&gt; Applications -&gt; Utilities      -&gt; Terminal&lt;/tt&gt;. &lt;br /&gt;&lt;br /&gt;&lt;p&gt;At the command prompt type this command:&lt;/p&gt;&lt;blockquote class="example"&gt;%   sudo passwd root Enter Password:  Changing password for root New password:   Verify password: &lt;/blockquote&gt;  The first password you are asked for is the already existing password for the &lt;em&gt;Admin&lt;/em&gt; account, to prove that you are authorized to make changes to this system. After that, you enter the new root password (twice, for verification). That is all, the "root" account is now enabled,  with that password.&lt;/li&gt;&lt;/ol&gt;    &lt;!-- ============================================================================= --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2547823412886916756?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2547823412886916756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2547823412886916756'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/how-to-enable-os-x-root-user.html' title='How to enable the OS X root user'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5956869474710404616</id><published>2008-12-14T15:54:00.000-08:00</published><updated>2008-12-14T15:55:05.090-08:00</updated><title type='text'>Screenshots from the command line</title><content type='html'>Use the &lt;code&gt;screencapture&lt;/code&gt; utility to initiate a screenshot from the command line.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Take a screenshot and save the result to a file&lt;/h4&gt; &lt;p&gt; This command can be used to take a screenshot with a 10 second delay (-T 10) and save the result in jpg format (-t jpg) to a file named &lt;i&gt;screen.jpg&lt;/i&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;screencapture -T 10 -t jpg screen.jpg&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If the file format is not specified, a png file is saved. The time delay lets you change desktops if you are using Spaces (the multiple desktop feature in Leopard) before the screenshot is taken. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5956869474710404616?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5956869474710404616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5956869474710404616'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/screenshots-from-command-line.html' title='Screenshots from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4982620322816647792</id><published>2008-12-14T10:08:00.001-08:00</published><updated>2008-12-14T10:08:37.700-08:00</updated><title type='text'>How to find out which files were installed with a Mac package</title><content type='html'>Installing a Mac package is usually a process of dragging an icon from an installer to the Applications folder. This creates a new directory in the Applications folder with the application files inside it. Sometimes, additional files are installed in other places. To see everything that was installed, use the &lt;code&gt;/Library/Receipts&lt;/code&gt; directory and the &lt;code&gt;lsbom&lt;/code&gt; utility.&lt;br /&gt;&lt;br /&gt;&lt;p&gt; An applications that follows Mac standards will leave a record of what was installed in the &lt;code&gt;/Library/Receipts/&lt;i&gt;app-name&lt;/i&gt;&lt;/code&gt; directory. &lt;/p&gt; &lt;p&gt; Within that directory, there should be a Contents subdirectory, and inside that, an &lt;code&gt;Archive.bom&lt;/code&gt; file. The .bom file is a "bill of materials" with a list of all the files that belong to that application, the full path to their location, and other details like the UNIX permissions, file size, and checksum. &lt;/p&gt; &lt;p&gt;However, the bill of materials is a binary file. To extract information from it, use the list bill of materials command line utility, &lt;code&gt;lsbom&lt;/code&gt;. &lt;/p&gt;  &lt;h4&gt;To list all files and related information in a BOM file:&lt;/h4&gt; &lt;p&gt; &lt;code&gt;lsbom &lt;i&gt;BOMfile&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;h4&gt;To list only the files without related information in a BOM file:&lt;/h4&gt; &lt;p&gt; &lt;code&gt;lsbom -s &lt;i&gt;BOMfile&lt;/i&gt;&lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4982620322816647792?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4982620322816647792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4982620322816647792'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/how-to-find-out-which-files-were.html' title='How to find out which files were installed with a Mac package'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1039267933354236221</id><published>2008-12-14T10:06:00.000-08:00</published><updated>2008-12-18T08:55:30.465-08:00</updated><title type='text'>Using hdiutil</title><content type='html'>The &lt;code&gt;hdiutil&lt;/code&gt; program is a native Apple command line utility for working with disk images. It uses the DiskImages framework. Disk images (usually with a .dmg, .img, or .iso file name extension) are often used for distributing programs and for burning CDs/DVDs.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating a disk image from a folder&lt;/b&gt; &lt;p&gt; &lt;code&gt;hdiutil create test.dmg -srcfolder /path/to/folder/&lt;/code&gt; &lt;/p&gt; &lt;p&gt; Once the disk image is created, it can be mounted, copied, or sent like any other file. &lt;/p&gt;  &lt;h4&gt;Mounting a disk image&lt;/h4&gt; &lt;p&gt; To mount (or attach) a disk image, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hdiutil mount test.dmg&lt;/code&gt; &lt;/p&gt; &lt;p&gt;A mounted disk image appears on the Desktop, in the Finder, and shows up as a directory in /Volumes. All removable media, such as CDs, DVDs, external disks, and USB flash drives are mounted in /Volumes. &lt;/p&gt;  &lt;h4&gt;Unmounting a disk image&lt;/h4&gt; &lt;p&gt; To unmount (or detach) a disk image, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hdiutil unmount &lt;i&gt;/dev/device-name&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The  device name is usually something like /dev/disk3s2.  You can also unmount it using the &lt;code&gt;/Volumes/mountpoint&lt;/code&gt; if you know where it was mounted:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hdiutil unmount /Volumes/mountpoint&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Burning an ISO to CD (or DVD)&lt;/h4&gt; &lt;p&gt; First, load a blank CD, then:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hdiutil burn &lt;i&gt;cd-image.iso&lt;/i&gt;&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Create an encrypted disk image&lt;/h4&gt; &lt;p&gt; This creates a 10 MB encrypted disk image and internally formats it as a journaled HFS+ file system (the OS X default):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hdiutil create -encryption -size 10m -volname encdata test.dmg -fs HFS+J &lt;/code&gt; &lt;/p&gt; &lt;p&gt;During the creation of the disk image, you will be prompted for a password that will allow access to the contents of the disk image. You must remember the password or anything you put into the image will be lost. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1039267933354236221?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1039267933354236221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1039267933354236221'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/using-hdiutil.html' title='Using hdiutil'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7389026269334978360</id><published>2008-12-14T07:47:00.000-08:00</published><updated>2008-12-14T07:49:28.802-08:00</updated><title type='text'>Apache Authentication and Authorization using LDAP</title><content type='html'>The Lightweight Directory Access Protocol (LDAP) is frequently used to implement a centralized directory server.  There are two popular open source LDAP solutions, &lt;a href="http://www.openldap.org/"&gt;&lt;/a&gt;OpenLDAP and&lt;a href="http://www.redhat.com/directory_server/"&gt;&lt;/a&gt; Red Hat Directory Server.   According to the Apache documentation, Novell LDAP and iPlanet Directory Server are also supported. This article focuses on OpenLDAP, but the concepts and examples should be applicable to the others.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note: originally published October 31, 2007 on &lt;/i&gt;linux.com&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Information in OpenLDAP&lt;/h4&gt; &lt;p&gt; LDAP was designed as a simplified, or "lightweight", version of the &lt;a&gt;ITU-T X.500 directory specification&lt;/a&gt;.  The default set of schemas contain all of the information you would find in traditional Linux system files like &lt;code&gt;/etc/passwd&lt;/code&gt; and &lt;code&gt;/etc/group&lt;/code&gt;, or Sun's Network Information System (NIS). The schemas are malleable and are often extended to contain additional demographic information or customized for specific applications. &lt;/p&gt; &lt;p&gt; Following is an example of a typical LDAP user record in LDAP Data Interchange Format (LDIF): &lt;/p&gt;&lt;pre&gt;dn: uid=keithw,ou=People,dc=company,dc=com&lt;br /&gt;uid: keithw&lt;br /&gt;cn: Keith Winston&lt;br /&gt;objectClass: account&lt;br /&gt;objectClass: posixAccount&lt;br /&gt;objectClass: top&lt;br /&gt;objectClass: shadowAccount&lt;br /&gt;userPassword: {crypt}$1$M/PZEwdp$KHjSay8JILX01YAHxjfc91&lt;br /&gt;shadowLastChange: 13402&lt;br /&gt;shadowMax: 99999&lt;br /&gt;shadowWarning: 7&lt;br /&gt;loginShell: /bin/bash&lt;br /&gt;uidNumber: 2741&lt;br /&gt;gidNumber: 420&lt;br /&gt;homeDirectory: /home/keithw&lt;br /&gt;gecos: Keith Winston&lt;/pre&gt;  &lt;p&gt; The LDAP database can be queried with a number of tools, including the command line &lt;code&gt;ldapsearch&lt;/code&gt; program, one of the standard OpenLDAP utilities. If you are new to LDAP, the terminology and syntax may be difficult at first. Taking the time to learn the LDAP search syntax will pay off later if you want to craft advanced policies using non-standard attributes. &lt;/p&gt;  &lt;h4&gt;Configuring Apache 2.2&lt;/h4&gt; &lt;p&gt; Apache modules have been available for LDAP since at least version 1.3.  If you have used mod_auth_ldap in the past, you should be aware that the bundled authentication and authorization modules have been refactored in version 2.2. The latest LDAP modules are loaded with these directives, usually in the &lt;code&gt;httpd.conf&lt;/code&gt; file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; LoadModule ldap_module /path/to/mod_ldap.so LoadModule authnz_ldap_module /path/to/mod_authnz_ldap.so &lt;/code&gt; &lt;/p&gt; &lt;p&gt; Once the modules are loaded, you can control access by querying the directory for particular attributes.  The key directive to point Apache at the LDAP server is &lt;code&gt;AuthLDAPUrl&lt;/code&gt;.  A generic AuthLDAPUrl directive looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; AuthLDAPUrl ldap://ldap.company.com/ou=People,dc=company,dc=com?uid &lt;/code&gt; &lt;/p&gt; &lt;p&gt; It defines the LDAP server, the base distinguished name (DN), the attribute to use in the search (usually Uid within the People organizational unit). For complex policies, you may need extra search filters. &lt;/p&gt; &lt;p&gt; The next few sections show working examples of directives to enforce common policies.  Each set of directives can be placed in the main Apache configuration file or in &lt;code&gt;.htaccess&lt;/code&gt; files. &lt;/p&gt;  &lt;h4&gt;Any valid user&lt;/h4&gt; &lt;p&gt; This set of directives allows access to the current directory to all valid users in the LDAP directory.  Apache will ask the browser for a user ID and password and check that against the directory.  If you are familiar with Apache Basic Authentication, there are only a few new directives to learn. &lt;/p&gt;&lt;pre&gt;Order deny,allow&lt;br /&gt;Deny from All&lt;br /&gt;AuthName "Company.com Intranet"&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthBasicProvider ldap&lt;br /&gt;AuthzLDAPAuthoritative off&lt;br /&gt;AuthLDAPUrl ldap://ldap.company.com/ou=People,dc=company,dc=com?uid&lt;br /&gt;Require valid-user&lt;br /&gt;Satisfy any&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; &lt;code&gt;AuthBasicProvider ldap&lt;/code&gt; is necessary so Apache knows to query an LDAP directory instead of a local file. &lt;/p&gt; &lt;p&gt; &lt;code&gt;AuthzLDAPAuthoritative off&lt;/code&gt; must be explicitly set because the default setting is "on" and authentication attempts for valid-user will fail otherwise.  This is a tricky setting because other policies, like &lt;code&gt;Require ldap-user&lt;/code&gt;, need the setting to be "on".  Setting this value off also allows other authentication methods to mixed with LDAP. &lt;/p&gt; &lt;p&gt; The &lt;code&gt;Satisfy any&lt;/code&gt; directive is not strictly required in this case because we are only testing one condition. &lt;/p&gt;  &lt;h4&gt;List of users&lt;/h4&gt; &lt;p&gt; This set of directives allows access to the current directory to the users listed in the &lt;code&gt;Require ldap-user&lt;/code&gt; directive. &lt;/p&gt;&lt;pre&gt;Order deny,allow&lt;br /&gt;Deny from All&lt;br /&gt;AuthName "Company.com Intranet"&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthBasicProvider ldap&lt;br /&gt;AuthzLDAPAuthoritative on&lt;br /&gt;AuthLDAPUrl ldap://ldap.company.com/ou=People,dc=company,dc=com?uid&lt;br /&gt;Require ldap-user keithw joeuser&lt;br /&gt;Satisfy any&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; &lt;code&gt;AuthzLDAPAuthoritative on&lt;/code&gt; could be omitted since the default setting is "on", but left here for clarity. &lt;/p&gt; &lt;p&gt; Note the AuthLDAPUrl setting does not change. As in previous examples, it searches the directory for a matching Uid. &lt;/p&gt;  &lt;h4&gt;Member of a group&lt;/h4&gt; &lt;p&gt; This set of directives allows access to the current directory to users who are either primary or secondary members of the group specified in the &lt;code&gt;Require ldap-group&lt;/code&gt; directive. &lt;/p&gt; &lt;p&gt; The group configuration may be the most difficult due to the schema design of directories that were converted from NIS (as mine was). Referring back to the user LDIF record, notice the &lt;code&gt;gidNumber&lt;/code&gt; attribute has a value of 420, the number assigned to the &lt;i&gt;infosys&lt;/i&gt; group in my directory.  It corresponds to the primary group of the user.  However, the LDAP entry for each group only lists users who are secondary members of the group, using the &lt;code&gt;memberUid&lt;/code&gt; attribute. See below for a snippet of a group record: &lt;/p&gt;&lt;pre&gt;dn: cn=infosys,ou=Group,dc=company,dc=com&lt;br /&gt;objectClass: posixGroup&lt;br /&gt;gidNumber: 420&lt;br /&gt;memberUid: user1&lt;br /&gt;memberUid: user2&lt;br /&gt;memberUid: user3&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt; We need another test, &lt;code&gt;Require ldap-attribute&lt;/code&gt;,  to pick up the primary users of the group because they are not listed with the group itself.  Here are the Apache directives: &lt;pre&gt;Order deny,allow&lt;br /&gt;Deny from All&lt;br /&gt;AuthName "Company.com Intranet"&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthBasicProvider ldap&lt;br /&gt;AuthzLDAPAuthoritative on&lt;br /&gt;AuthLDAPUrl ldap://ldap.company.com/ou=People,dc=company,dc=com?uid&lt;br /&gt;AuthLDAPGroupAttribute memberUid&lt;br /&gt;AuthLDAPGroupAttributeIsDN off&lt;br /&gt;Require ldap-group cn=infosys,ou=Group,dc=company,dc=com&lt;br /&gt;Require ldap-attribute gidNumber=420&lt;br /&gt;Satisfy any&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; &lt;code&gt;AuthzLDAPAuthoritative on&lt;/code&gt; could be omitted since the default setting is "on", but left here for clarity. &lt;/p&gt; &lt;p&gt; &lt;code&gt;AuthLDAPGroupAttribute memberUid&lt;/code&gt; indicates which attibute in the LDAP group record to match with the Uid.  In this case, memberUid.  A group record contains one memberUid attribute for each (non primary) member of the group. &lt;/p&gt; &lt;p&gt; &lt;code&gt;AuthLDAPGroupAttributeIsDN off&lt;/code&gt; tells Apache to use the distinguished name of the client when checking for group membership. Otherwise, the username will be used. In my OpenLDAP directory, only the username was from NIS.  The default setting is "on" so setting it off was required. An LDAP directory may store the entire distinguished name, so this setting may be change based on your directory. &lt;/p&gt; &lt;p&gt; &lt;code&gt;Require ldap-group&lt;/code&gt; grants access to members of the "infosys" group.  For multiple groups, add an additional directive for each. &lt;/p&gt; &lt;p&gt; &lt;code&gt;Require ldap-attribute gidNumber=420&lt;/code&gt; handles the primary users of group 420, the "infosys" group. Without this condition, primary users would be denied access. For multiple groups, add an additional directive for each. &lt;/p&gt; &lt;p&gt; The &lt;code&gt;Satisfy any&lt;/code&gt; directive is required because we are testing multiple conditions and want the successful test of any condition to grant access. &lt;/p&gt;  &lt;h4&gt;Combination of users and groups&lt;/h4&gt; &lt;p&gt; This example is a union of the user and group directives, but otherwise, there is nothing new. &lt;/p&gt;&lt;pre&gt;Order deny,allow&lt;br /&gt;Deny from All&lt;br /&gt;AuthName "Company.com Intranet"&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthBasicProvider ldap&lt;br /&gt;AuthzLDAPAuthoritative on&lt;br /&gt;AuthLDAPUrl ldap://ldap.company.com/ou=People,dc=company,dc=com?uid&lt;br /&gt;AuthLDAPGroupAttribute memberUid&lt;br /&gt;AuthLDAPGroupAttributeIsDN off&lt;br /&gt;Require ldap-group cn=infosys,ou=Group,dc=company,dc=com&lt;br /&gt;Require ldap-attribute gidNumber=420&lt;br /&gt;Require ldap-user keithw joeuser&lt;br /&gt;Satisfy any&lt;br /&gt;&lt;/pre&gt;   &lt;h4&gt;Debug and deploy&lt;/h4&gt; &lt;p&gt; Testing LDAP authentication from a web browser can be frustrating because the only thing you know is that access was granted or not.  You don't get any kind of feedback on why something did not work.  For verbose information on each step in the process, set the "LogLevel debug" option in Apache. &lt;/p&gt; &lt;p&gt; With debugging active, Apache will record the connection status to the LDAP server, what attributes and values were requested, what was returned, and why conditions were met or not met. It can be invaluable in fine tuning LDAP access controls. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7389026269334978360?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7389026269334978360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7389026269334978360'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/apache-authentication-and-authorization.html' title='Apache Authentication and Authorization using LDAP'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8835837497134862467</id><published>2008-12-13T19:50:00.000-08:00</published><updated>2008-12-13T19:51:15.380-08:00</updated><title type='text'>Using diskutil</title><content type='html'>The &lt;code&gt;diskutil&lt;/code&gt; program is a native Apple command line utility for manipulating disks, partitions, and RAID sets. This includes magnetic hard disks, CDs/DVDs, and flash drives. Most options, except "list", require root access.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Finding out about disks in your system&lt;/h4&gt; &lt;p&gt; For information on all available disks and their partitioning, use:&lt;br /&gt;&lt;code&gt;diskutil list&lt;/code&gt; &lt;/p&gt; &lt;p&gt; For more detailed information on a particular disk or partition, use:&lt;br /&gt;&lt;code&gt;diskutil info &lt;i&gt;disk-or-partition&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The default Apple partitioning scheme uses the last physical partition on a disk for storing data.  Here is sample output from &lt;code&gt;diskutil list&lt;/code&gt; showing a hard disk and a CD.  The UNIX device name is shown first, along with the contents of each partition:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;/dev/disk0&lt;br /&gt;  #:                       TYPE NAME                    SIZE       IDENTIFIER&lt;br /&gt;  0:     Apple_partition_scheme                        *74.5 Gi    disk0&lt;br /&gt;  1:        Apple_partition_map                         31.5 Ki    disk0s1&lt;br /&gt;  2:                  Apple_HFS Macintosh HD            74.4 Gi    disk0s3&lt;br /&gt;/dev/disk1&lt;br /&gt;  #:                       TYPE NAME                    SIZE       IDENTIFIER&lt;br /&gt;  0:        CD_partition_scheme                        *718.1 Mi   disk1&lt;br /&gt;  1:     Apple_partition_scheme                         625.3 Mi   disk1s1&lt;br /&gt;  2:        Apple_partition_map                         31.5 Ki    disk1s1s1&lt;br /&gt;  3:                  Apple_HFS Dungeon Siege Disc 2    625.0 Mi   disk1s1s2&lt;/pre&gt;  &lt;p&gt; Here is sample output from &lt;code&gt;diskutil info&lt;/code&gt; on a disk partition:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;diskutil info /dev/disk0s3&lt;br /&gt;  Device Identifier:        disk0s3&lt;br /&gt;  Device Node:              /dev/disk0s3&lt;br /&gt;  Part Of Whole:            disk0&lt;br /&gt;  Device / Media Name:      Untitled 3&lt;br /&gt;&lt;br /&gt;  Volume Name:              Macintosh HD&lt;br /&gt;  Mount Point:              /&lt;br /&gt;  File System:              Journaled HFS+&lt;br /&gt;                            Journal size 8192 KB at offset 0x256000&lt;br /&gt;  Owners:                   Enabled&lt;br /&gt;&lt;br /&gt;  Partition Type:           Apple_HFS&lt;br /&gt;  Bootable:                 Is bootable&lt;br /&gt;  Media Type:               Generic&lt;br /&gt;  Protocol:                 ATA&lt;br /&gt;  SMART Status:             Verified&lt;br /&gt;  Volume UUID:              EE8C4FFD-6C4B-302D-B096-DCF81D4E13FB&lt;br /&gt;&lt;br /&gt;  Total Size:               74.4 Gi (79892103168 B) (156039264 512-byte blocks)&lt;br /&gt;  Free Space:               26.8 Gi (28731383808 B) (56115984 512-byte blocks)&lt;br /&gt;&lt;br /&gt;  Read Only:                No&lt;br /&gt;  Ejectable:                No&lt;br /&gt;  Whole:                    No&lt;br /&gt;  Internal:                 Yes&lt;/pre&gt;   &lt;h4&gt;Checking partitions for integrity and fixing them&lt;/h4&gt; &lt;p&gt; You can use &lt;code&gt;diskutil&lt;/code&gt; to check the file system data structure of a partition (e.g., /dev/disk0s3) with:&lt;br /&gt;&lt;code&gt;diskutil verifyVolume &lt;i&gt;partition&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If errors are you found, you can fix them with:&lt;br /&gt;&lt;code&gt;diskutil repairVolume &lt;i&gt;partition&lt;/i&gt;&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Checking partitions for UNIX permission problems and repairing them&lt;/h4&gt; &lt;p&gt; You can use &lt;code&gt;diskutil&lt;/code&gt; to check the UNIX permissions on a partition with:&lt;br /&gt;&lt;code&gt;diskutil verifyPermissions &lt;i&gt;partition&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If errors are you found, you can fix them with:&lt;br /&gt;&lt;code&gt;diskutil repairPermissions &lt;i&gt;partition&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If permissions get accidentally changed on some system files, it could cause strange behavior or disable certain features of the system. &lt;/p&gt;  &lt;h4&gt;Finding out about RAID sets&lt;/h4&gt; &lt;p&gt; RAID is usually used in servers to provide additional protection from hard disk failure.  For information on RAID sets, use:&lt;br /&gt;&lt;code&gt;diskutil listRAID&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Other diskutil options&lt;/h4&gt; &lt;p&gt; In addition to the options listed above, &lt;code&gt;diskutil&lt;/code&gt; can be used to reformat disks or partitions, erase writable CDs/DVDs, securely erase data, etc. Here are some of the other features:&lt;br /&gt;&lt;/p&gt;&lt;ul type="square"&gt;&lt;li&gt;u[n]mount - Unmount a single volume&lt;/li&gt;&lt;li&gt;unmountDisk - Unmount an entire disk (all volumes)&lt;/li&gt;&lt;li&gt;eject - Eject a removable disk&lt;/li&gt;&lt;li&gt;mount - Mount a single volume&lt;/li&gt;&lt;li&gt;mountDisk - Mount an entire disk (all mountable volumes)&lt;/li&gt;&lt;li&gt;eraseDisk - Erase an existing disk, removing all volumes&lt;/li&gt;&lt;li&gt;eraseVolume - Erase an existing volume&lt;/li&gt;&lt;li&gt;reformat - Reformat an existing volume&lt;/li&gt;&lt;li&gt;eraseOptical - Erase an optical media (CD/RW, DVD/RW, etc.)&lt;/li&gt;&lt;li&gt;zeroDisk - Erase a disk, writing zeros to the media&lt;/li&gt;&lt;li&gt;randomDisk - Erase a disk, writing random data to the media&lt;/li&gt;&lt;li&gt;secureErase - Securely erase a disk or freespace on a volume&lt;/li&gt;&lt;li&gt;resizeVolume - Resize a volume, increasing or decreasing its size&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt; See the man page for even more! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8835837497134862467?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8835837497134862467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8835837497134862467'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/using-diskutil.html' title='Using diskutil'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6051103775206437567</id><published>2008-12-13T19:26:00.000-08:00</published><updated>2008-12-13T19:34:08.849-08:00</updated><title type='text'>Copy and paste inside a shell script</title><content type='html'>The Terminal application supports copy and paste from the Edit menu or using the standard keyboard shortcuts. In addition, two native Apple command line programs, &lt;code&gt;pbcopy&lt;/code&gt; and &lt;code&gt;pbpaste&lt;/code&gt;, allow you to copy and paste text from the clipboard within a shell script.&lt;br /&gt;&lt;br /&gt;&lt;p&gt; &lt;code&gt;pbcopy&lt;/code&gt;  takes standard in and places it in the specified pasteboard (the clipboard).  For example, to capture the output of the &lt;code&gt;ls -1&lt;/code&gt; command, pipe the output to pbcopy:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ls -1 |  pbcopy&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now, the results can be pasted into any program that supports the clipboard. &lt;/p&gt;  &lt;code&gt;pbpaste&lt;/code&gt; writes the contents of the pasteboard (the clipboard) to standard out. For example, to paste the contents of the clipboard into a text file called "output.txt", use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;pbpaste &gt; output.txt&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6051103775206437567?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6051103775206437567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6051103775206437567'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/copy-and-paste-inside-shell-script.html' title='Copy and paste inside a shell script'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6873582553615318806</id><published>2008-12-13T19:23:00.000-08:00</published><updated>2008-12-13T19:24:25.708-08:00</updated><title type='text'>Defaults -- setting preferences from the command line</title><content type='html'>The &lt;code&gt;defaults&lt;/code&gt; program allows users to read, write, and delete Mac OS X user preferences from the command line. OS X applications use the defaults system to record user preferences and other information that must be maintained when the applications aren't running. Setting preferences is usually done (more easily) from the GUI, but some options are not available in the GUI.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Property lists&lt;/h4&gt; &lt;p&gt; User preferences and application settings are stored in files called property lists (with an extension of &lt;i&gt;.plist&lt;/i&gt;). These files can store binary values, so they can sometimes look meaningless if you view the raw file. Aside from the Preferences dialogs, property list files can be updated with the Property List Editor application (part of the developer tools), or with the &lt;code&gt;defaults&lt;/code&gt; command line program. &lt;/p&gt; &lt;p&gt; User defaults belong to domains, which typically correspond to individual applications. For example, the domain for Firefox is &lt;code&gt;org.mozilla.firefox&lt;/code&gt; with the settings saved in a file called org.mozilla.firefox.plist. Each domain has a dictionary of keys and values representing its defaults; for example, "Default Font" = "Helvetica". Keys are always strings, but values can be complex data structures comprising arrays, dictionaries, strings, and binary data. &lt;/p&gt; &lt;p&gt; User plist files are saved in &lt;code&gt;~/Library/Preferences/&lt;/code&gt;, while system wide plist files are stored in &lt;code&gt;/Library/Preferences/&lt;/code&gt;. &lt;/p&gt; &lt;p&gt; When you update a setting using &lt;code&gt;defaults&lt;/code&gt;, it only affects the current user. &lt;/p&gt;  &lt;h4&gt;View preferences&lt;/h4&gt; &lt;p&gt; To see all user preferences, use:&lt;br /&gt;&lt;code&gt;defaults read&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The output list will be very long because every setting for every application will be printed. &lt;/p&gt; &lt;p&gt; To see all Firefox user preferences, use:&lt;br /&gt;&lt;code&gt;defaults read org.mozilla.firefox&lt;/code&gt; &lt;/p&gt; &lt;p&gt;Note that Firefox stores most of it's settings in Firefox specific files, and not in Apple's defaults system. The same is true in Windows where most of the Firefox settings are not in the Windows registry. &lt;/p&gt;  &lt;h4&gt;Update or delete a preference&lt;/h4&gt; &lt;p&gt; To update a key use:&lt;br /&gt;&lt;code&gt;defaults write &lt;i&gt;domain&lt;/i&gt; { key 'value' }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Of course, you have to know the name of the key and the acceptable values you can use ahead of time. &lt;/p&gt; &lt;p&gt; To delete a key use:&lt;br /&gt;&lt;code&gt;defaults delete &lt;i&gt;domain&lt;/i&gt; key&lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6873582553615318806?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6873582553615318806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6873582553615318806'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/defaults-setting-preferences-from.html' title='Defaults -- setting preferences from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3139450936947112555</id><published>2008-12-13T17:57:00.000-08:00</published><updated>2008-12-13T17:58:11.446-08:00</updated><title type='text'>Nvram</title><content type='html'>The &lt;code&gt;nvram&lt;/code&gt; utility is used to view and set Open Firmware NVRAM variables. Open Firmware, (aka non-volatile RAM), controls system boot options. To change a variable, you must run nvram as root.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Viewing Open Firmware variables&lt;/h4&gt; &lt;p&gt; There are about 50 Open Firmware variables. To view all variables, use:&lt;br /&gt;&lt;code&gt;nvram -p&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Setting Open Firmware variables&lt;/h4&gt; &lt;p&gt; You must be root to set a variable.  To set a variable, assign a value with an equals sign:&lt;br /&gt;&lt;code&gt;nvram &lt;i&gt;scroll-lock=false&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; After setting a variable, they are saved during the next clean restart or shutdown. &lt;/p&gt; &lt;p&gt; To set multiple variables at once, list them in a text file in &lt;i&gt;variable=value&lt;/i&gt; format, one per line.&lt;br /&gt;Then, feed them all to nvram with:&lt;br /&gt;&lt;code&gt;nvram -f &lt;i&gt;text-file&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; You can also create new variables by simply assigning a value to a new variable name. It won't have any meaning to the system unless some application reads it, but it is a nice option. &lt;/p&gt;  &lt;h4&gt;Deleting Open Fireware variables&lt;/h4&gt; &lt;p&gt; To delete a variable, use:&lt;br /&gt;&lt;code&gt;nvram -d &lt;i&gt;variable&lt;/i&gt;&lt;/code&gt; &lt;/p&gt;          &lt;div class="story-footer"&gt;         &lt;br /&gt;        &lt;br /&gt;              &lt;/div&gt;  &lt;div class="block-divider"&gt; &lt;/div&gt;            &lt;!-- reserved for social news links         &lt;table border="0" width="100%"&gt;           &lt;tr&gt;             &lt;td style="align:center; vertical-align:top;"&gt;               &lt;a href="http://digg.com/submit?phase=2&amp;amp;url=&amp;amp;title=&amp;amp;bodytext=&amp;amp;topic="&gt;Digg this&lt;/a&gt;              &lt;/td&gt;           &lt;/tr&gt;         &lt;/table&gt; --&gt;                                           &lt;span class="block-helpicon"&gt;              &lt;/span&gt;     &lt;h2&gt;&lt;br /&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3139450936947112555?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3139450936947112555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3139450936947112555'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/nvram.html' title='Nvram'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5044287884512579770</id><published>2008-12-13T14:38:00.000-08:00</published><updated>2008-12-13T14:39:03.720-08:00</updated><title type='text'>Sysctl</title><content type='html'>Sysctl is a kernel utility that allows you to query and set kernel variables. It is rare that you need to tinker with a running OS X kernel, but special applications may require it.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Viewing kernel variables&lt;/h4&gt; &lt;p&gt; There are over 100 kernel state variables.  To view a specific variable, use:&lt;br /&gt;&lt;code&gt;sysctl &lt;i&gt;variable-name&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To view all variables, use:&lt;br /&gt;&lt;code&gt;sysctl -a&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;Setting kernel variables&lt;/h4&gt; &lt;p&gt; You must be root to set a kernel variable.  To set a kernel variable, use the -w switch:&lt;br /&gt;&lt;code&gt;sysctl -w &lt;i&gt;variable-name=value&lt;/i&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If you are running OS X as a file server and have a lot of people connecting and sharing files, you might want to increase the maximum number of open files allowed by the kernel. This can be tuned using the &lt;code&gt;kern.maxfiles&lt;/code&gt; variable.  The default value is 12288.  To increase it to 50000, use:&lt;br /&gt;&lt;code&gt; sysctl -w &lt;i&gt;kern.maxfiles=50000&lt;/i&gt;&lt;/code&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5044287884512579770?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5044287884512579770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5044287884512579770'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/sysctl.html' title='Sysctl'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-6330234874672698843</id><published>2008-12-13T14:21:00.001-08:00</published><updated>2008-12-13T14:21:59.266-08:00</updated><title type='text'>Diagnostic command line tools</title><content type='html'>OS X comes with a number of command line tools to measure system performance and individual application performance. Using these tools, you can track down bottlenecks and discover misbehaving applications -- those acting like rude, thoughtless, little pigs.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;top&lt;/h4&gt; &lt;p&gt; The &lt;code&gt;top&lt;/code&gt; program shows a full screen of stats on overall CPU usage, memory usage, load average, and how many resources each process is using. The default mode for top is an interactive display that updates once per second. Applications are sorted by CPU usage in descending order. To quit while in interactive mode, type &lt;code&gt;q&lt;/code&gt;. &lt;/p&gt; &lt;pre&gt;Processes:  64 total, 3 running, 1 stuck, 60 sleeping... 204 threads   16:21:14&lt;br /&gt;Load Avg:  0.52, 0.43, 0.25     CPU usage:  9.3% user, 22.9% sys, 67.8% idle&lt;br /&gt;SharedLibs: num =   27, resident = 11.0M code, 1.02M data, 3.44M LinkEdit&lt;br /&gt;MemRegions: num = 11872, resident =  388M + 9.48M private,  111M shared&lt;br /&gt;PhysMem:   117M wired,  393M active,  374M inactive,  885M used,  138M free&lt;br /&gt;VM: 5.57G + 21.5M   284085(0) pageins, 19704(0) pageouts&lt;br /&gt;&lt;br /&gt; PID COMMAND      %CPU   TIME   #TH #PRTS #MREGS RPRVT  RSHRD  RSIZE  VSIZE&lt;br /&gt;23002 mdimport     0.1%  0:00.38   4    62    52   996K  4.27M  3.01M  40.0M&lt;br /&gt;22998 top         12.3%  0:24.47   1    19    22   476K   476K   900K  27.0M&lt;br /&gt;22977 lookupd      0.0%  0:00.09   2    34    37   400K  1.06M  1.16M  28.5M&lt;br /&gt;22971 mdimport     0.0%  0:00.31   3    60    46   864K  3.37M  2.76M  39.0M&lt;br /&gt;19117 firefox-bi  10.1% 12:34:42  10   196   781   143M  59.6M   155M   983M&lt;br /&gt;18711 bash         0.0%  0:00.14   1    14    17   216K   884K   748K  27.2M&lt;br /&gt;18710 login        0.0%  0:00.02   1    16    37   124K   516K   460K  26.9M&lt;br /&gt;17409 httpd        0.0%  0:00.00   1    11    87   104K  2.47M   476K  31.9M&lt;br /&gt;7211 usbmuxd      0.0%  0:00.02   2    23    23   164K   436K   284K  27.0M&lt;br /&gt;7193 iTunesHelp   0.0%  0:01.38   2    55    99   608K  4.67M  1.55M   108M&lt;br /&gt;4618 Terminal     4.2% 27:15.18  10   173   228  3.91M+ 16.5M+ 9.18M+  135M+&lt;br /&gt; 717 AppleSpell   0.0%  0:00.28   1    32    36   284K  2.06M   860K  37.7M&lt;br /&gt; 712 System Eve   0.0%  0:03.10   1    62   109   928K  7.02M  1.30M   109M&lt;br /&gt; 682 cupsd        0.0%  0:58.79   2    30    25   568K  1.03M   844K  27.8M&lt;br /&gt; 380 DashboardC   0.0%  0:56.12   3    78   160  3.59M  6.57M  4.13M   116M&lt;br /&gt; 379 DashboardC   0.0%  0:07.55   4    86   158  5.75M  6.66M  6.56M   115M&lt;br /&gt;&lt;/pre&gt; &lt;p&gt; Top can also be run in batch mode where it writes output to the terminal a set number of times, then quits. This is ideal for feeding data to a parsing program for generating your own stats or filtering. For example, to show top output once, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;top -l 1&lt;/code&gt;&lt;br /&gt;&lt;i&gt;note: top minus el one&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To sort the output by CPU usage, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;top -l 1 -o cpu&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To sort the output by resident memory usage (physical memory), use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;top -l 1 -o rsize&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To sort the output by virtual memory usage (total memory), use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;top -l 1 -o vsize&lt;/code&gt; &lt;/p&gt;  &lt;h4&gt;fs_usage&lt;/h4&gt; &lt;p&gt; Report system calls and page faults related to filesystem activity in real-time. It is a continuous display and if unfiltered, is overwhelming. It is usually best to limit the output to a single process or to watch network activity. It must be run as &lt;i&gt;root&lt;/i&gt;. &lt;/p&gt; &lt;p&gt; To limit the output to a process or command name, include it at the end of the command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;fs_usage 19117&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To limit the output to just network related system calls, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;fs_usage -f network&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To limit the output to just filesystem related system calls, use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;fs_usage -f filesys&lt;/code&gt; &lt;/p&gt; &lt;p&gt; See also &lt;a href="http://www.commandlinemac.com/article.php?story=20070725182559756"&gt;lsof&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;vm_stat&lt;/h4&gt;  The &lt;code&gt;vm_stat&lt;/code&gt; program displays Mach (the kernel) virtual memory statistics.  It is useful to seeing if your system is memory starved.  &lt;p&gt; Here is the output from vm_stat: &lt;/p&gt;&lt;pre&gt;Mach Virtual Memory Statistics: (page size of 4096 bytes)&lt;br /&gt;Pages free:                    63416.&lt;br /&gt;Pages active:                 103005.&lt;br /&gt;Pages inactive:                68102.&lt;br /&gt;Pages wired down:              27621.&lt;br /&gt;"Translation faults":      308932364.&lt;br /&gt;Pages copy-on-write:         7961115.&lt;br /&gt;Pages zero filled:         204818181.&lt;br /&gt;Pages reactivated:           1571266.&lt;br /&gt;Pageins:                      279532.&lt;br /&gt;Pageouts:                      19704.&lt;br /&gt;Object cache: 1693448 hits of 4581511 lookups (36% hit rate)&lt;br /&gt;&lt;/pre&gt; If &lt;code&gt;Pages free&lt;/code&gt; is low, you need more memory to run all your applications.  &lt;p&gt; You can add an interval (in seconds) as a parameter to vm_stat and it will show your memory and paging activity in real time. For example, &lt;code&gt;vm_stat 1&lt;/code&gt; will output a new line every second -- useful to see if memory is taking a beating with a lot Pageins/Pageouts, but it won't pinpoint an offending application. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-6330234874672698843?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6330234874672698843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/6330234874672698843'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/diagnostic-command-line-tools.html' title='Diagnostic command line tools'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2964224531321532682</id><published>2008-12-13T12:17:00.000-08:00</published><updated>2008-12-13T12:18:49.672-08:00</updated><title type='text'>30 days with JFS</title><content type='html'>&lt;p&gt; The &lt;a href="http://jfs.sourceforge.net/"&gt;Journaled File System (JFS)&lt;/a&gt; is a little known file system open sourced by IBM in 1999 and available in the official kernel sources since 2002.  It originated inside IBM as the standard file system on the AIX line of UNIX servers, and later OS/2.  IBM ships JFS2 with AIX today.  Despite its pedigree, JFS has not received the publicity or widespread usage of other Linux file systems like EXT2/3 and ReiserFS.  To learn more about JFS, I installed it as my root file system. &lt;/p&gt; &lt;i&gt;note: originally published September 14, 2007 on&lt;/i&gt; linux.com&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Features&lt;/h4&gt; &lt;p&gt; I installed Slackware 12 on a laptop choosing JFS as the file system during installation.  I performed no special partitioning and created one JFS file system to hold everything.  Installation was uneventful and the system booted normally from Grub.  Not all distributions offer JFS as an install option, and some may not have JFS compiled into their default kernels.  While Fedora and SUSE can use JFS, they both default to EXT3.  Slackware, Debian, Ubuntu, and their derivatives are good choices if you want to try JFS. &lt;/p&gt; &lt;p&gt; One of the first things I noticed was the absence of a &lt;code&gt;lost+found&lt;/code&gt; directory, a relic of lesser file systems. &lt;/p&gt; &lt;p&gt; JFS is a fully 64-bit file system. With the default block size of 4 KB, it supports a maximum file system size of 4 petabytes (less if smaller block sizes are used). The minimum file system size supported is 16 MB. The JFS transaction log has a default size of 0.4% of the aggregate size, rounded up to a megabyte boundary. The maximum size of the log is 32 MB.  One interesting aspect of the layout on disk is the fsck working space, a small area allocated within the file system for keeping track of block allocation if there is not enough RAM to track a large file system at boot time. &lt;/p&gt; &lt;p&gt; JFS dynamically allocates space for disk inodes, freeing the space when it is no longer required.  This eliminates the possibility of running out of inodes due to a large number of small files.  As far as I can tell, JFS is the only file system in the kernel with this feature.  For performance and efficiency, the contents of small directories are stored within the directory's inode. Up to eight entries are stored in-line within the inode, excluding the self [.] and parent [..] entries. Larger directories use a B+tree keyed on name for faster retrieval. Internally, extents are used to allocate blocks to files, leading to compact, efficient use of space even as files grow in size.  This is also available in XFS, and is a major new feature in EXT4. &lt;/p&gt; &lt;p&gt; JFS supports both sparse and dense files.  Sparse files allow data to be written to random locations within a file without writing intervening file blocks.  JFS reports the file size as the largest used block, while only allocating actually used blocks.  Sparse files are useful for applications that require a large logical space but only use a portion of the space.  With dense files, blocks are allocated to fill the entire file size, whether data is written to them or not. &lt;/p&gt; &lt;p&gt; In addition to the standard permissions, JFS supports basic extended attributes, such as the immutable (i) and append-only (a) attributes.  I was able to successfully set and test them with the lsattr and chattr programs.  I could not find definitive information on access control list support under Linux. &lt;/p&gt;  &lt;h4&gt;Logging&lt;/h4&gt; &lt;p&gt; The main design goal of JFS was to provide fast crash recovery for large file systems, avoiding the long file system check (fsck) times of older UNIX file systems.  That was also the primary goal of file systems like EXT3 and ReiserFS.  Unlike EXT3, journaling was not an add-on to JFS, but baked into the design from the start.  For high performance applications, the JFS transaction log file can be created on an external volume if specified when the file system is first created. &lt;/p&gt; &lt;p&gt; JFS only logs operations on meta-data, maintaining the consistency of the file system structure, but not necessarily the data.  A crash might result in stale data, but the files should remain consistent and usable. &lt;/p&gt; &lt;p&gt; Here is a list of the file system operations logged by JFS: &lt;/p&gt;&lt;ul type="square"&gt;&lt;li&gt;File creation (create)&lt;/li&gt;&lt;li&gt;Linking (link)&lt;/li&gt;&lt;li&gt;Making directory (mkdir)&lt;/li&gt;&lt;li&gt;Making node (mknod)&lt;/li&gt;&lt;li&gt;Removing file (unlink)&lt;/li&gt;&lt;li&gt;Rename (rename)&lt;/li&gt;&lt;li&gt;Removing directory (rmdir)&lt;/li&gt;&lt;li&gt;Symbolic link (symlink)&lt;/li&gt;&lt;li&gt;Truncating regular file&lt;/li&gt;&lt;/ul&gt;   &lt;h4&gt;Utilities&lt;/h4&gt; &lt;p&gt; A suite of utilities is provided to manage JFS file systems. You must be the root user to use them. &lt;/p&gt; &lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Utility&lt;/th&gt;     &lt;th&gt;Description&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_debugfs&lt;/td&gt;     &lt;td&gt; shell based JFS file system editor, allows changes to the ACL, uid/gid. mode, time, etc. You can also alter data on disk, but only by entering hex strings, not the most efficient way to edit a file.     &lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_fsck&lt;/td&gt;     &lt;td&gt;replay the JFS transaction log, check and repair a JFS device, should on ly be run on an unmounted or read only file system, run automatically at boot.&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_fscklog&lt;/td&gt;     &lt;td&gt;extract a JFS fsck service log into a file. &lt;code&gt;jfs_fscklog -e /dev/hd a6&lt;/code&gt; extracts the binary log to file fscklog.new, to view, use &lt;code&gt;jfs_fscklog -d fscklog.new&lt;/code&gt;   &lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_logdump&lt;/td&gt;     &lt;td&gt;dump the journal log, a plaint text file that shows data on each transac tion in the log file.&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_mkfs&lt;/td&gt;     &lt;td&gt;create a JFS formatted partition, use the &lt;code&gt;-j journal_device&lt;/code&gt;  option to create an external journal (1.0.18 or later)&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;jfs_tune&lt;/td&gt;     &lt;td&gt;adjust tunable file system parameters on JFS. I didn't find options that  looked like they might improve performance, the &lt;code&gt;-l&lt;/code&gt; option lists th e superblock info&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt; Here is what a dump of the superblock information looks like: &lt;/p&gt;&lt;pre&gt;root@slackt41:~# jfs_tune -l /dev/hda6&lt;br /&gt;jfs_tune version 1.1.11, 05-Jun-2006&lt;br /&gt;&lt;br /&gt;JFS filesystem superblock:&lt;br /&gt;&lt;br /&gt;JFS magic number:       'JFS1'&lt;br /&gt;JFS version:            1&lt;br /&gt;JFS state:              mounted&lt;br /&gt;JFS flags:              JFS_LINUX  JFS_COMMIT  JFS_GROUPCOMMIT  JFS_INLINELOG&lt;br /&gt;Aggregate block size:   4096 bytes&lt;br /&gt;Aggregate size:         12239720 blocks&lt;br /&gt;Physical block size:    512 bytes&lt;br /&gt;Allocation group size:  16384 aggregate blocks&lt;br /&gt;Log device number:      0x306&lt;br /&gt;Filesystem creation:    Wed Jul 11 01:52:42 2007&lt;br /&gt;Volume label:           ''&lt;/pre&gt;   &lt;h4&gt;Crash Testing&lt;/h4&gt; &lt;p&gt; White papers and man pages are no substitute for the harsh reality of a server room.  To test the recovery capabilities of JFS, I started crashing my system (forced power off) with increasing workloads.  I repeated each crash twice to see if my results were consistent. &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Crash workload&lt;/th&gt;     &lt;th&gt;Recovery&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;console (no X) running text editor with one open file&lt;/td&gt;     &lt;td&gt;about 2 seconds to replay the journal log, changes I had not saved in th e editor were missing but the file was intact&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;X window system with KDE, gimp, nvu, and text editor in xte rm all with open files&lt;/td&gt;     &lt;td&gt;about 2 seconds to replay the journal log, all open files were intact, u nsaved changes were missing&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;X window system with KDE, gimp, nvu, and text editor all with open files , plus a shell script that inserted records into a MySQL (ISAM) table.  The scri pt I wrote was an infinite loop and I let it run for a couple of minutes to make  sure some records were flushed to disk.&lt;/td&gt;     &lt;td&gt;about 3 seconds to replay the journal log, all open files intact, databa se intact with a few thousand records inserted, but the timestamp on the table f ile had been rolled back one minute.&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt; In all cases, these boot messages appeared...&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;**Phase 0 - Replay Journal Log&lt;br /&gt;-|----- (spinner appeared for a couple of seconds, then went away)&lt;br /&gt;Filesystem is clean&lt;/pre&gt;  &lt;p&gt; Throughout the crash testing, no file system corruption occurred and the longest log replay time I experienced was about 3 seconds. &lt;/p&gt;  &lt;h4&gt;Conclusion&lt;/h4&gt; &lt;p&gt; While my improvised crash tests were not a good simulation a busy server, JFS did hold up well, and recovery time was fast.  All file level applications I tested, like tar and rsync, worked flawlessly and lower level programs like truecrypt also worked as expected.  After 30 days of kicking and prodding, this gave me a high level of confidence in JFS and I am content trusting my data to it.  JFS may not have been marketed as effectively as others, but is a solid choice in the long list of quality Linux file systems. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2964224531321532682?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2964224531321532682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2964224531321532682'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/30-days-with-jfs.html' title='30 days with JFS'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4738203220421638522</id><published>2008-12-13T12:13:00.000-08:00</published><updated>2008-12-13T12:15:50.164-08:00</updated><title type='text'>MacPorts, Up and Running</title><content type='html'>&lt;p&gt; &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; is a system designed to let you easily install and manage free, open source software on OS X. Until late in 2006, the project was named DarwinPorts. There are disk image downloads available for 10.3 (Panther), 10.4 (Tiger), and 10.5 (Leopard). If you have a different version, you can download the source code and compile it. &lt;/p&gt; &lt;p&gt; &lt;i&gt;updated for MacPorts 1.6 and Leopard on January 16, 2008&lt;/i&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Ports concept&lt;/h4&gt; &lt;p&gt;If you are new the "ports" concept, the way the system works may be hard to grasp. The ports system was developed in the BSD community as a way to easily install and manage software on any BSD system. It was designed to automate the manual process programmers followed to port software from one Unix-like system to another. Most of the software in the ports repository is written in the C language and requires a C compiler. &lt;/p&gt; &lt;p&gt;When a particular package is requested, the ports system checks the version of the system it is running on, the version of the available source code, then downloads the source, applies any patches needed for it run on the local system, compiles it, and installs it. The design of the ports system only requires package maintainers to write scripts that handle any differences in the local system (like library versions, hardware architecture, compiler versions, etc.). The heavy lifting is done by the ports system itself. &lt;/p&gt; &lt;p&gt;This system is ingenious and works well in most situations, but you may occasionally run into a package that doesn't work. If that happens, it is usually because the source program was recently updated and the port scripts haven't caught up. &lt;/p&gt;  &lt;h4&gt;Universal ports&lt;/h4&gt; &lt;p&gt;An Apple enhancement to the original ports system allows some software to be built (compiled) as universal binaries. This option may be desirable if you share binaries between Intel and PPC Macs, or plan to upgrade soon and don't want to install your ports again. &lt;/p&gt;  &lt;h4&gt;Installing MacPorts&lt;/h4&gt; &lt;p&gt; According to the &lt;a href="http://trac.macosforge.org/projects/macports/wiki/InstallingMacPorts"&gt;MacPorts wiki&lt;/a&gt;, there are three critical steps that must be done prior to installing MacPorts: &lt;/p&gt;&lt;ol&gt;&lt;li&gt;Install Xcode Tools&lt;/li&gt;&lt;li&gt;Install XWindows (X11)&lt;/li&gt;&lt;li&gt;Set the shell environment&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt;Both Xcode Tools (which includes the compiler), and X11 are available on the Mac DVDs. They can also be downloaded from the Apple developer web site. I had already installed Xcode and XWindows, so the only thing I needed to do was modify my &lt;code&gt;$HOME/.bash_login&lt;/code&gt; file to include the /opt/local directories in my PATH and set the DISPLAY variable with "export DISPLAY=:0.0". See the wiki page for additional details. &lt;/p&gt; &lt;p&gt; After setting my shell environment, I downloaded version 1.6 of the MacPorts disk image for 10.5 (Leopard) from the &lt;a href="http://svn.macports.org/repository/macports/downloads/"&gt;download area&lt;/a&gt;.  I mounted the disk image and ran the .pkg installer to install MacPorts.  It completed with no errors. &lt;/p&gt; &lt;p&gt; If you want to tweak the port system configuration, the default location of the global config file is &lt;code&gt;/opt/local/etc/macports/macports.conf&lt;/code&gt;. &lt;/p&gt;  &lt;h4&gt;Getting started&lt;/h4&gt; &lt;p&gt; Once the ports system was installed, I followed the wiki recommendation and updated MacPorts itself with this Terminal command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo port -d selfupdate&lt;/code&gt; &lt;/p&gt; &lt;p&gt; Next, I installed a simple program to see what kind of output the system produced.  Here is the output from installing &lt;code&gt;dos2unix&lt;/code&gt;, a program that changes the line endings of a text file from DOS to UNIX format.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;sudo port install dos2unix&lt;br /&gt;Password:&lt;br /&gt;---&gt;  Fetching dos2unix&lt;br /&gt;---&gt;  Attempting to fetch dos2unix-3.1.tar.gz from http://fresh.t-systems-sfr.com/linux/src/&lt;br /&gt;---&gt;  Verifying checksum(s) for dos2unix&lt;br /&gt;---&gt;  Extracting dos2unix&lt;br /&gt;---&gt;  Configuring dos2unix&lt;br /&gt;---&gt;  Building dos2unix with target all&lt;br /&gt;---&gt;  Staging dos2unix into destroot&lt;br /&gt;---&gt;  Installing dos2unix 3.1_0&lt;br /&gt;---&gt;  Activating dos2unix 3.1_0&lt;br /&gt;---&gt;  Cleaning dos2unix&lt;/pre&gt;  &lt;p&gt;When the port command finished, I had a freshly compiled dos2unix program sitting in /opt/local/bin/. Everything is nicely isolated in /opt/local/ to prevent any port program from interfering with the original Apple system. &lt;/p&gt; &lt;p&gt;One of more powerful features of ports is that it understands program dependencies. If you ask it to install a program that requires other programs or libraries to run, the ports system first installs the required components, then completes your request. For example, I wanted to install wget, a useful command line tool to download files or mirror web sites. I started the install with:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sudo port install wget&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After starting it, I walked away. When I came back 30 minutes later, ports was still still installing dependencies. There were five dependencies that got installed first:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;expat&lt;br /&gt;libiconv&lt;br /&gt;gettext&lt;br /&gt;zlib&lt;br /&gt;openssl&lt;/pre&gt;  &lt;p&gt; If you start a port install and your system seems sluggish, check to see if ports is still downloading and compiling dependencies. &lt;/p&gt;  &lt;h4&gt;Uninstalling MacPorts&lt;/h4&gt; &lt;p&gt;Because of the way MacPorts files are isolated, it can be easily removed. To uninstall both the MacPorts system and all ports installed, the wiki lists the following files and directories to delete:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;/opt/local/&lt;br /&gt;/Applications/MacPorts/&lt;br /&gt;/Library/Tcl/macports1.0/&lt;br /&gt;/Library/LaunchDaemons/org.macports.*&lt;br /&gt;/Library/StartupItems/DarwinPortsStartup&lt;/pre&gt;  &lt;p&gt; To my surprise, my installation did not include these files and directories:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;/Applications/MacPorts/&lt;br /&gt;/Library/LaunchDaemons/org.macports.*&lt;br /&gt;/Library/StartupItems/DarwinPortsStartup&lt;/pre&gt;  &lt;p&gt; Since the system appears to be fully functional, it is possible that this part of the wiki is slightly out of date. &lt;/p&gt; &lt;p&gt; &lt;i&gt;Update January 10, 2008: Seth Milliken wrote in and noted that these directories are only created if you install a port that uses them, e.g. installing a Cocoa app will create /Applications/MacPorts/. &lt;/i&gt; &lt;/p&gt;  &lt;h4&gt;Common port commands&lt;/h4&gt; &lt;p&gt; Here are some commands you may find useful while learning to use the ports system. &lt;/p&gt; &lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Command&lt;/th&gt;     &lt;th&gt;Result&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port install &lt;i&gt;package&lt;/i&gt;&lt;/td&gt;     &lt;td valign="top"&gt;installs a package&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port uninstall &lt;i&gt;package&lt;/i&gt;&lt;/td&gt;     &lt;td valign="top"&gt;uninstalls a package&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port installed&lt;/td&gt;     &lt;td valign="top"&gt;shows all ports currently installed&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port uninstalled&lt;/td&gt;     &lt;td valign="top"&gt;shows all ports &lt;i&gt;not&lt;/i&gt; currently installed, you may want to pipe the output of this command to grep to limit the output&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port search &lt;i&gt;regex&lt;/i&gt;&lt;/td&gt;     &lt;td valign="top"&gt;search for a port whose name matches the regex&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port info package&lt;/td&gt;     &lt;td valign="top"&gt;shows meta information on a package&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top"&gt;port list&lt;/td&gt;     &lt;td valign="top"&gt;shows the latest version of all available ports&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt; See the port man page for additional options. &lt;/p&gt;  &lt;h4&gt;Filling in the holes&lt;/h4&gt; &lt;p&gt;MacPorts can sometimes provide a software solution the default Apple software does not. For me, that usually means a command line or system oriented tool, but there are plenty of GUI applications available, too. The MacPorts team has done a nice job "porting" the ports system to the Mac. It is one of the most popular features of BSD, and one of the reasons I am running a Mac today. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4738203220421638522?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4738203220421638522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4738203220421638522'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/macports-up-and-running.html' title='MacPorts, Up and Running'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1816621495430450228</id><published>2008-12-13T11:30:00.001-08:00</published><updated>2008-12-13T11:31:54.342-08:00</updated><title type='text'>Learn to Talk AWK</title><content type='html'>&lt;p&gt; When it comes to slicing and dicing text, few tools are as powerful, or as underutilized, as awk.  The name AWK was coined from the initials of it's authors, Aho, Weinberger, and Kernighan.  Yes, the same Kernighan of the famous K&amp;amp;R C Programming Language book.  In the Linux world, every distribution includes the GNU version, gawk, (/bin/awk is usually a symbolic link to /bin/gawk). OS X ships with the BSD version of awk, more closely related to the original UNIX awk.  The focus of the article is on the core  features common among POSIX-compliant awks. &lt;/p&gt; &lt;p&gt; &lt;i&gt;note: originally published January 16, 2006 on &lt;a href="http://linux.com/"&gt;linux.com&lt;/a&gt;&lt;br /&gt;updated for OS X on October 2, 2007&lt;/i&gt;&lt;/p&gt;&lt;h4&gt;Basic command line usage&lt;/h4&gt;&lt;br /&gt;&lt;p&gt; The awk utility is a small program that executes awk language scripts, often one-liners, but just as adeptly larger programs saved in a text file.  For example, to execute an awk script saved in the file prg1.awk, and have it process the file, data1, you could use this command: &lt;/p&gt; &lt;p&gt; &lt;code&gt;awk -f prg1.awk data1&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The result is written to standard out, so it is usually piped to a result file. &lt;/p&gt; &lt;p&gt; Another command line parameter commonly used is &lt;code&gt;-F&lt;/code&gt; to change the default field separator of a blank space.  The field separator can also be changed within an awk program.  To tell awk how to split data into fields from a comma separated variable (CSV) file, you would use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;awk -F"," -f prg1.awk data1&lt;/code&gt; &lt;/p&gt; &lt;p&gt; You may also include more than one data file to process and awk will keep running until it runs out of data:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;awk -F"," -f prg1.awk data1 data2 data3 data4 data5&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If you want to assign a value to a variable before execution of the program, use the -v option:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;awk -v AMOUNT=100 prg1.awk data1&lt;/code&gt; &lt;/p&gt; &lt;h4&gt;Behold the power&lt;/h4&gt; &lt;p&gt; The power of awk comes from how much it does automatically for you when crunching text files, and from the simple elegance of the language. When you feed awk a text file, it does the following things for you:&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Opens and reads all input files listed on the command line&lt;/li&gt;&lt;li&gt;Handles memory management for all variables&lt;/li&gt;&lt;li&gt;Parses each line and splits it into fields using the field separator (the       default is a blank space, but can be changed)&lt;/li&gt;&lt;li&gt;Presents each line of text to your program as variable $0&lt;/li&gt;&lt;li&gt;Presents each field from each line in predefined variables, starting with       $1, $2, ... $N&lt;/li&gt;&lt;li&gt;Maintains many internal variables for your use such as (but not limited to ):     &lt;ul&gt;&lt;li&gt;RS = record separator&lt;/li&gt;&lt;li&gt;FS = field separator&lt;/li&gt;&lt;li&gt;NF = number of fields in the current record&lt;/li&gt;&lt;li&gt;NR = number of records processed so far&lt;/li&gt;&lt;/ul&gt;   &lt;/li&gt;&lt;li&gt;Automatically handles conversion between internal data types       (string, floating point, array)&lt;/li&gt;&lt;li&gt;Executes the BEGIN block before processing any records (a good place to       initialize variables)&lt;/li&gt;&lt;li&gt;Executes the END block after processing all records (a good place to       calculate report totals)&lt;/li&gt;&lt;li&gt;Closes all input files listed on the command line&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt; The awk language uses only three internal data types: strings, floating point numbers, and arrays.  Variables do not have to be defined before they are used.  Awk handles converting data from one type to another as necessary.  If you add two strings together using the addition operator (+) and they contain numeric values, you get a numeric result. If a string is used in an arithmetic operation but can't be converted to a number, it is converted to zero.  Usually, awk does what you want when handling data conversion. &lt;/p&gt; &lt;p&gt; It can open, read, and write to more files than those listed on the command line by using the getline function or redirecting output from within a program.  It has access to a set of internal functions that include math, string manipulation, formatted printing (similar to the C language printf), and miscellaneous functions like pseudo-random numbers.  You can also create your own functions or function libraries that can be used in several programs.  All of this is packed into an executable usually about 500k in size.  Programmers can typically become proficient in awk within a day.  Complete references are available in a single book.  You don't need a "bookshelf" of dead trees and CDs to master awk. &lt;/p&gt; &lt;p&gt; Implementations or ports of awk are available on nearly every platform, making your scripts reasonably portable. &lt;/p&gt; &lt;h4&gt;AWK in the real world&lt;/h4&gt; &lt;p&gt; Here is a short example of an awk application I created to import a list of email addresses and names from Novell Groupwise to PHPList (a mailing list manager).  The list was exported from Groupwise in vCard File format (VCF), a text based format.  Here is an example entry from the VCF file:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;BEGIN:VCARD&lt;br /&gt;VERSION:2.1&lt;br /&gt;X-GWTYPE:USER&lt;br /&gt;FN:Bar, Foo&lt;br /&gt;ORG:;GREEN&lt;br /&gt;EMAIL;WORK;PREF:foobar@yahoo.com&lt;br /&gt;N:Bar;Foo&lt;br /&gt;X-GWUSERID:foobar&lt;br /&gt;X-GWADDRFMT:0&lt;br /&gt;X-GWIDOMAIN:yahoo.com&lt;br /&gt;X-GWTARGET:TO&lt;br /&gt;END:VCARD&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; The target format was a CSV file that PHPList could import into an existing mailing list.  I needed to extract the name (from the record that starts with "FN" and the email address from the record that starts with "EMAIL".  These records are easy to identify and a small awk script does the job nicely. &lt;/p&gt; &lt;p&gt; I started construction of the script by setting up a custom record separator and a block of code to handle each record type.  I saved the script in a text file called extract-emails.awk.  Note that the &lt;i&gt;.awk&lt;/i&gt; file extension is just convention, the file containing awk commands can be named anything.  This was the beginning of the script:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; BEGIN { FS = ":" }&lt;br /&gt;&lt;br /&gt;/^FN/ {&lt;br /&gt;# handle name here&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/^EMAIL/ {&lt;br /&gt;# handle email address here&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; The BEGIN block is run once before any records are read.  It sets the field separator to a colon so awk will split the fields of the file when a colon is encountered. &lt;/p&gt; &lt;p&gt; The regular expressions /^FN/ and /^EMAIL/ tell awk to look for the characters "FN" or "EMAIL" at the start of a record, and if a match is found, run the associated block of code between the curly braces.  This kind of regular expression match is common in awk but not required.  A block of code with no match expression is run for every record processed by awk.  I added a couple of comments (lines starting with "#") to document what each part of the script does. &lt;/p&gt; &lt;p&gt; Looking at the VCF data, I noticed that the "FN" record always precedes the "EMAIL" record, so I ordered the code blocks to process the records that way.  Awk reads and executes a script in the order it appears. Many times, the order of the code will not matter, but in this case it does.  The name is related to the email and I need to retain that relationship as the file is read, so I saved the name in an internal variable, then wrote both the email address and name to standard out while processing the email record. &lt;/p&gt; &lt;p&gt; Getting back to the task, let's complete the name section.  The goal is to reformat the name from "lastname, firstname" into "firstname lastname", removing the comma.  Here was my solution for the name:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; /^FN/ {&lt;br /&gt;# handle name here&lt;br /&gt;fullname = tolower($2)&lt;br /&gt;split(fullname, names, ",")&lt;br /&gt;name = names[2] names[1]&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/p&gt; Knowing that awk has split up the incoming records into fields using a colon as the field separator, the field variables for the example "FN" record contain the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; $1 = "FN"&lt;br /&gt;$2 = "Bar, Foo"&lt;br /&gt;&lt;/code&gt;  &lt;p&gt; Working with the $2 variable, I used a built in awk function, towlower(), to convert the names to lowercase and stored the result in a variable called "fullname".  Next, I used the split function to break the name into first and last name parts, with the result stored in an array called "names".  Finally, I glued the name back together in the desired order, without the comma, and stored that result in a variable called "name". &lt;/p&gt; &lt;p&gt; There is very little to do inside the email code block.  Awk provides the email address to us in the $2 variable (note that $2 in the "EMAIL" record is different than $2 in the "FN" record).  For consistency, I converted it to lowercase, then used the print function to write both the email address and name to standard out, with a comma separating the values.  Here is the complete script:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; BEGIN { FS = ":" }&lt;br /&gt;&lt;br /&gt;/^FN/ {&lt;br /&gt;# handle name here&lt;br /&gt;fullname = tolower($2)&lt;br /&gt;split(fullname, names, ",")&lt;br /&gt;name = names[2] names[1]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/^EMAIL/ {&lt;br /&gt;# handle email address here&lt;br /&gt;mail = tolower($2)&lt;br /&gt;print mail "," name&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt; &lt;/p&gt; &lt;h4&gt;A sprinkle of shell glue&lt;/h4&gt; &lt;p&gt; To pull it all together, we need a little shell glue.  A small shell script allows us to call awk with the command line parameters we want and to easily redirect the output to a file.  It is also handy to run a shell script when you are testing.&lt;br /&gt;&lt;br /&gt;&lt;code&gt; #!/bin/sh&lt;br /&gt;# Extract e-mail addresses from VCF file for PHPList.&lt;br /&gt;awk -f extract-emails.awk groupwise.vcf &gt; phplist-emails.txt&lt;br /&gt;&lt;/code&gt; &lt;/p&gt; &lt;p&gt; Awk can be used as an intermediate step in a larger shell script where the output is fed into another utility such as sort, grep, or another awk script. &lt;/p&gt; &lt;p&gt; Finally, here is a sample of the output:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;foobar@yahoo.com, foo bar&lt;br /&gt;barbaz@yahoo.com, bar baz&lt;br /&gt;&lt;/pre&gt;  &lt;h4&gt;Where AWK falls short&lt;/h4&gt; &lt;p&gt; There are certain tasks that are beyond the capabilities of awk.  For instance, if you need to do anything that communicates using network sockets, awk is not your best bet. Similarly, if you need to process binary files, awk falls short.  The latest version of GNU awk does have some rudimentary network capabilities, but Perl, PHP, and Ruby are much better equipped for those tasks. &lt;/p&gt; &lt;h4&gt;A million household uses&lt;/h4&gt; &lt;p&gt; Awk is an expert tool for text processing, and the roots of Perl are clear in it's design.  It is powerful enough to handle almost any kind of text crunching or reporting, while being very easy to learn and use. There is a lot of competition and many choices when it comes to scripting languages, but I still find awk the best choice for many problems. Although awk is employed most often for smaller problems, it can be used for large applications.  I worked on a 12,000 line awk application used to adjudicate dental claims. This application was the core system for a successful million dollar business.  Despite being a common utility on every Linux system, awk remains relatively obscure. If you take the time to learn it, the rewards will last a lifetime. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1816621495430450228?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1816621495430450228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1816621495430450228'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/learn-to-talk-awk.html' title='Learn to Talk AWK'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-824670834528944686</id><published>2008-12-13T10:56:00.000-08:00</published><updated>2008-12-13T11:28:44.484-08:00</updated><title type='text'>Cron fields and crontabs</title><content type='html'>&lt;b&gt;Crontab fields&lt;/b&gt;&lt;br /&gt;&lt;p&gt; Here is a typical crontab entry and the definition of cron fields:&lt;br /&gt;&lt;code&gt;00 03 * * *  /tmp/zing.sh&lt;/code&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;minute&lt;/li&gt;&lt;li&gt;hour&lt;/li&gt;&lt;li&gt;day of the month&lt;/li&gt;&lt;li&gt;month of the year&lt;/li&gt;&lt;li&gt;day of the week&lt;/li&gt;&lt;li&gt;program or command to run&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt; An asterisk (*) in any field means run every time for this field.&lt;br /&gt;Ranges (X-Y) and steps (X-Y/Z) can also be defined. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;User crontabs (including the root user)&lt;/b&gt;&lt;br /&gt;&lt;p&gt; To edit a user crontab (including root):&lt;br /&gt;&lt;code&gt;crontab -e&lt;/code&gt; &lt;/p&gt; &lt;p&gt; To delete a crontab:&lt;br /&gt;&lt;code&gt;crontab -r&lt;/code&gt; &lt;/p&gt;  &lt;b&gt;System crontab&lt;/b&gt;&lt;br /&gt;&lt;p&gt; The system crontab is stored in /etc/crontab.  It can be changed (as root) with a text editor. &lt;/p&gt; &lt;p&gt; The system crontab has one extra field before the program to run, which is the user to run the command as (usually root). &lt;/p&gt;  &lt;h4&gt;Periodic jobs in OS X Tiger&lt;/h4&gt; &lt;p&gt; The system cron jobs were replaced in Tiger with launch daemons, in /System/Library/LaunchDaemons/. There are daily, weekly, and monthly launch daemons for system maintenance. They run shell scripts in /etc/periodic/. &lt;/p&gt; &lt;p&gt;The system shell scripts will run user scripts on the same schedule if they exist. To take advantage of this, simply create your own local scripts called &lt;code&gt;/etc/daily.local, /etc/weekly.local, or /etc/monthly.local&lt;/code&gt;.  They are run as root. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-824670834528944686?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/824670834528944686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/824670834528944686'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/cron-fields-and-crontabs.html' title='Cron fields and crontabs'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-306262477241654464</id><published>2008-12-13T09:04:00.000-08:00</published><updated>2008-12-13T10:56:00.942-08:00</updated><title type='text'>Spotlight on the command line</title><content type='html'>&lt;p&gt; In addition to the traditional command line search programs, locate and find, OS X provides a command line interface to the Spotlight search system (mdfind). &lt;/p&gt; &lt;p&gt; While I can't find it documented anywhere, my guess is that "mdfind" stands for "meta data find". &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Simple spotlight search&lt;/h4&gt; &lt;code&gt;mdfind &lt;i&gt;searchterm&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Search in a specific directory&lt;/h4&gt; &lt;code&gt;mdfind -onlyin /Users/keithw &lt;i&gt;searchterm&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Search for specific meta data&lt;/h4&gt; &lt;code&gt;mdfind "kMDItemAuthor == '*Donaldson*'"&lt;/code&gt;  &lt;h4&gt;List available meta data fields&lt;/h4&gt; &lt;code&gt;mdls &lt;i&gt;filename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Turn off spotlight indexing for a volume&lt;/h4&gt; &lt;code&gt;mdutil -i off &lt;i&gt;volumename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Turn on spotlight indexing for a volume&lt;/h4&gt; &lt;code&gt;mdutil -i on &lt;i&gt;volumename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Show the status of spotlight indexing for a volume&lt;/h4&gt; &lt;code&gt;mdutil -s &lt;i&gt;volumename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;How spotlight does its magic&lt;/h4&gt; &lt;p&gt;Unlike the locate program and database, spotlight recognizes and indexes file system changes almost immediately. How is that possible? The magic happens in the kernel, which sends notices of file system changes to a special character device named &lt;code&gt;/dev/fsevents&lt;/code&gt;.  Spotlight  monitors this special device and learns about new files that need to be indexed.  There is no published API for &lt;code&gt;/dev/fsevents&lt;/code&gt;, as far as I can tell. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-306262477241654464?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/306262477241654464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/306262477241654464'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/spotlight-on-command-line.html' title='Spotlight on the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4779725880803383222</id><published>2008-12-13T08:58:00.001-08:00</published><updated>2008-12-13T09:02:23.420-08:00</updated><title type='text'>Surfing the Keyboard in BASH</title><content type='html'>You are probably familiar with common keyboard sequences like Ctrl-C to end a program, but there are dozens of useful shortcuts you can use in BASH to edit the command line, move around your command history, and control jobs. I've collected 18 useful Ctrl and Meta (Option) sequences to make you more productive in BASH. So grab your 'board and leave the wet suit at home, the water is warm this time of year.&lt;br /&gt;&lt;br /&gt;&lt;h4 style="font-weight: bold;"&gt;Command Line Editing&lt;/h4&gt; &lt;p&gt; BASH keyboard sequences come in two flavors, Ctrl and Meta. Ctrl sequences are straightforward, you hold down the Ctrl key while pressing another key. On a PC with Linux, the Meta key is usually mapped to Alt, but on a Mac, it is usually mapped to the Esc key. Since the Esc key is poorly placed for serious keyboarding, I suggest mapping the Meta key to the Option key. &lt;/p&gt; &lt;p&gt;To map Meta to Option in the OS X Terminal, use the menu and go to Terminal / Window Settings, select Keyboard in the drop down box at the top, and check 'Use option key as meta key'. &lt;img src="http://www.commandlinemac.com/images/articles/20070823141438826_1.gif" alt="" align="right" height="438" width="267" /&gt; &lt;/p&gt; &lt;p&gt;To map Meta to Option in iTerm, use the menu and go to Bookmarks / Manage Profile, expand Keyboard Profiles, select Global, and check the 'Option Key as Meta' radio button. &lt;/p&gt; &lt;p&gt; With that out of the way, here are some shortcuts to edit commands. &lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Key Sequence&lt;/th&gt;     &lt;th align="center"&gt;Result&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-A&lt;/td&gt;     &lt;td&gt;moves the cursor to the beginning of the line&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-E&lt;/td&gt;     &lt;td&gt;moves the cursor to the end of the line&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-D&lt;/td&gt;     &lt;td&gt;deletes the character under the cursor&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-F&lt;/td&gt;     &lt;td&gt;moves the cursor forward one character&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-B&lt;/td&gt;     &lt;td&gt;moves the cursor backward one character&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-K&lt;/td&gt;     &lt;td&gt;deletes from the cursor to the end of the line&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Option-B&lt;/td&gt;     &lt;td&gt;moves the cursor back one word&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Option-F&lt;/td&gt;     &lt;td&gt;moves the cursor forward one word&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Option-L&lt;/td&gt;     &lt;td&gt;downcase a word starting from the cursor&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Option-U&lt;/td&gt;     &lt;td&gt;upcase a word starting from the cursor&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;   &lt;h4&gt;Moving through history&lt;/h4&gt; &lt;p&gt; BASH records all commands you enter in a personal history file called &lt;code&gt;.bash_history&lt;/code&gt; in your home directory. Notice the dot (.) at the start of the name, indicating it is a hidden file. Finder won't show you hidden files without some tweaking, but you can easily see hidden files in Terminal with the &lt;code&gt;ls -a&lt;/code&gt; command. If you are paranoid, BASH has options to turn history off, but it is very useful if you work much at the command line. Here are the history shortcuts: &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Key Sequence&lt;/th&gt;     &lt;th&gt;Result&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-R&lt;/td&gt;     &lt;td&gt;start an incremental reverse history search, Ctrl-J to stop&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-S&lt;/td&gt;     &lt;td&gt;start an incremental forward history search, Ctrl-J to stop&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-J&lt;/td&gt;     &lt;td&gt;stop incremental search, leaving command to edit&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-P (also up arrow)&lt;/td&gt;     &lt;td&gt;fetch the previous command from history&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-N (also down arrow)&lt;/td&gt;     &lt;td&gt;fetch the next command from history&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Incremental searches work by matching the string entered with the most recent history command that contains the string. The more you type, the more accurate the match. Use Ctrl-J (or the left or right arrow keys) to end the search, leaving the matched command on the command line ready to either edit or run. &lt;/p&gt;  &lt;h4&gt;Job Control&lt;/h4&gt; &lt;p&gt; OK, nothing new here...&lt;br /&gt;&lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Key Sequence&lt;/th&gt;     &lt;th&gt;Result&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-Z&lt;/td&gt;     &lt;td&gt;suspends the foreground job, returns control to user&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-C&lt;/td&gt;     &lt;td&gt;send signal 3 (SIGQUIT) to the foreground job&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;   &lt;h4&gt;Miscellaneous&lt;/h4&gt; &lt;p&gt; &lt;/p&gt;&lt;table&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;Key Sequence&lt;/th&gt;     &lt;th&gt;Result&lt;/th&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td&gt;Ctrl-X Ctrl-V&lt;/td&gt;     &lt;td&gt;show current version of BASH&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;All examples given above are default key bindings in BASH. There are additional BASH functions that are not automatically bound to a key sequence. To see all current key bindings, plus all unmapped functions, run this command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;bind -P&lt;/code&gt; &lt;/p&gt; &lt;p&gt; If you want to set your own key sequences or macros, you can define them in a readline run control file in your home directory called &lt;i&gt;.inputrc&lt;/i&gt; (you will need to create one). Readline is a library that provides command line control for BASH. To define a new key sequence, edit the .inputrc file and enter your new definitions one per line. You need to use the readline syntax as follows:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;key-sequence: function&lt;/code&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;\C- means Ctrl plus another key&lt;br /&gt;\M- means Meta (Option) plus another key&lt;br /&gt;\e is the ESC character&lt;br /&gt;\\ is a backslash&lt;br /&gt;\" is a double quote&lt;br /&gt;\' is a single quote&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; For example, to bind Option-z (meta-z) to the tty-status function, add this line to your &lt;i&gt;.inputrc&lt;/i&gt; file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;"\M-z": tty-status&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Close Terminal and start a new shell so it reads the .inputrc file, then try Option-z and you should see something like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;load: 0.61 cmd: bash 10561 running 0.00u 0.00s&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can create your own key sequences for anything BASH supports, or change them to taste. Few people have a burning desire to change the default BASH key sequences, but if you need to change your keyboard surfing style, you know how... dude. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4779725880803383222?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4779725880803383222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4779725880803383222'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/surfing-keyboard-in-bash.html' title='Surfing the Keyboard in BASH'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-5190293543759486005</id><published>2008-12-13T08:57:00.000-08:00</published><updated>2011-08-16T08:27:29.248-07:00</updated><title type='text'>PostgreSQL</title><content type='html'>PostgreSQL is a robust and powerful open source database. It has more advanced features than any other open source database and scales well with huge datasets and high traffic loads.&lt;br /&gt;&lt;br /&gt;By default, PostgreSQL listens on TCP port 5432. &lt;/p&gt; &lt;p&gt; It is not installed by default in OS X.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump all databases&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;code&gt;pg_dumpall --clean &gt; databases.sql&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a database with compression (-Fc)&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;code&gt;pg_dump -Fc --file=database.sql --clean &lt;i&gt;database&lt;/i&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a database, plain text, one schema only (-n)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;pg_dump -Fp --file=filename.sql -n &lt;i&gt;schema&lt;/i&gt; --clean &lt;i&gt;database&lt;/i&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a single table&lt;/b&gt;&lt;br&gt;&lt;br /&gt;Specify the schema with the table name (if applicable) with &lt;code&gt;pg_dump &lt;i&gt;[-d database]&lt;/i&gt; -t &lt;i&gt;schema.table&lt;/i&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a table definition (no data)&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;code&gt;pg_dump -s &lt;i&gt;[-d database]&lt;/i&gt; -t &lt;i&gt;schema.table&lt;/i&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Restore a database from a dump file&lt;/h4&gt; &lt;code&gt;pg_restore -Fc database.sql&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Restore a single table from a dump file&lt;/h4&gt; &lt;code&gt;pg_restore -v -e -Ft -d database -t tablename dumpfile.tar&lt;/code&gt;&lt;br /&gt;note: in this case, the dump file is in tar format, the database to restore to is after the -d switch and the table to restore is after the -t switch.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Copy data from a file into a table (from the psql client)&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;code&gt;COPY table-name FROM '/path/to/filename' DELIMITER 'delimiter';&lt;/code&gt;&lt;br&gt;&lt;br /&gt;note: the file must be readable by postgresql (make it 755),&lt;br&gt;&lt;br /&gt;the default delimiter is tab.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Copy data from a table to a file (from the psql client)&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;code&gt;COPY table-name TO '/path/to/filename' DELIMITER 'delimiter';&lt;/code&gt;&lt;br&gt;&lt;br /&gt;note: the directory and file must be writable by postgresql,&lt;br&gt;&lt;br /&gt;the default delimiter is tab&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Start the PostgreSQL interactive terminal&lt;/h4&gt;&lt;br /&gt;&lt;code&gt;psql&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Psql - show a list of databases&lt;/h4&gt; &lt;code&gt;\l&lt;/code&gt;&lt;br /&gt;&lt;i&gt;Lowercase L, not the number 1&lt;/i&gt;  &lt;h4&gt;Psql - show all users&lt;/h4&gt; &lt;code&gt;select * from pg_user;&lt;/code&gt;  &lt;h4&gt;Psql - show all tables (including system tables)&lt;/h4&gt; &lt;code&gt;select * from pg_tables;&lt;/code&gt;  &lt;h4&gt;Psql - show tables in the current context (database/schema)&lt;/h4&gt; &lt;code&gt;\d&lt;/code&gt;  &lt;h4&gt;Psql - show description of &lt;i&gt;tablename&lt;/i&gt;&lt;/h4&gt; &lt;code&gt;\d &lt;i&gt;tablename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Psql - show description of &lt;i&gt;tablename&lt;/i&gt;, along with constraints,  rules,  and triggers&lt;/h4&gt; &lt;code&gt;\d+ &lt;i&gt;tablename&lt;/i&gt;&lt;/code&gt;  &lt;h4&gt;Psql - change current database&lt;/h4&gt; &lt;code&gt;\c database;&lt;/code&gt;  &lt;h4&gt;Psql - show all schemas in the current database&lt;/h4&gt; &lt;code&gt;\dn&lt;/code&gt;  &lt;h4&gt;Psql - Grant permissions on a schema to a user&lt;/h4&gt; &lt;code&gt;GRANT ALL ON myschema TO user;&lt;/code&gt;  &lt;h4&gt;Psql - quit psql&lt;/h4&gt; &lt;code&gt;\q&lt;/code&gt;  &lt;h4&gt;Psql - show help&lt;/h4&gt; &lt;code&gt;\?&lt;/code&gt;  &lt;h4&gt;Psql - copy a table to a tab delimeted file&lt;/h4&gt; &lt;code&gt;COPY &lt;i&gt;table&lt;/i&gt; TO 'table.txt';&lt;/code&gt;  &lt;h4&gt;Psql - load a table from a tab delimeted file&lt;/h4&gt; &lt;code&gt;COPY &lt;i&gt;table&lt;/i&gt; FROM 'table.txt';&lt;/code&gt;  &lt;h4&gt;Psql - show permissions on database objects&lt;/h4&gt; &lt;code&gt;\z [object]&lt;/code&gt;&lt;br /&gt;&lt;code&gt; r -- SELECT ("read")&lt;br /&gt;w -- UPDATE ("write")&lt;br /&gt;a -- INSERT ("append")&lt;br /&gt;d -- DELETE&lt;br /&gt;R -- RULE&lt;br /&gt;x -- REFERENCES (foreign keys)&lt;br /&gt;t -- TRIGGER&lt;br /&gt;X -- EXECUTE&lt;br /&gt;U -- USAGE&lt;br /&gt;C -- CREATE&lt;br /&gt;T -- TEMPORARY&lt;br /&gt;arwdRxt -- ALL PRIVILEGES (for tables)&lt;br /&gt;* -- grant option for preceding privilege&lt;br /&gt;/yyyy -- user who granted this privilege&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;b&gt;Psql - getting or setting sequence values&lt;/b&gt;&lt;br /&gt;Get current value of a sequence:&lt;br /&gt;&lt;code&gt;SELECT currval('this_id_seq');&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Set current value of a sequence to 1000:&lt;br /&gt;&lt;code&gt;SELECT setval('this_id_seq', 1000);&lt;/code&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;h4&gt;Run the vacuum utility&lt;/h4&gt;&lt;br /&gt;&lt;code&gt;vacuumdb --verbose --analyze --all&lt;/code&gt;&lt;br /&gt;Note: vacuum reclaims space from deleted records and updates indexes. It should be set up in cron. Newer versions of postgresql may run vacuum automatically. &lt;h4&gt;Increase perfomance with shared memory&lt;/h4&gt; &lt;p&gt;One effective performance tuning tip for Postgresql is to increase the shared memory buffers. This might require adding RAM to the server. Many Linux distros default to 32MB of shared memory, controlled by two kernel parameters:&lt;br /&gt;&lt;code&gt; /proc/sys/kernel/shmmax&lt;br /&gt;/proc/sys/kernel/shmall &lt;/code&gt; &lt;/p&gt; &lt;p&gt; These values can be changed at run time, but it is better to set them at boot using the /etc/sysctl.conf file. This increases shared memory to 1GB:&lt;br /&gt;&lt;code&gt; # increase shared buffers for postgres at boot&lt;br /&gt;kernel.shmmax=1073741824&lt;br /&gt;kernel.shmall=2097152&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; Then, tell PostgreSQL to use 768MB of the 1GB available in the /var/lib/pgsql/data/postgresql.conf file:&lt;br /&gt;&lt;code&gt;shared_buffers = 98304  # min 16, at least max_connections*2, 8KB each&lt;/code&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; Restart PostgreSQL for the change to take effect. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-5190293543759486005?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5190293543759486005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/5190293543759486005'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/postgresql.html' title='PostgreSQL'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1530683371923508314</id><published>2008-12-13T08:56:00.001-08:00</published><updated>2008-12-13T08:56:59.572-08:00</updated><title type='text'>MySQL</title><content type='html'>&lt;p&gt; MySQL communicates through either local unix sockets or over TCP/IP port 3306 (default). Database names, tables, field names, and passwords are case sensitive. SQL Commands are not case sensitive. &lt;/p&gt; &lt;p&gt; The main configuration file is &lt;code&gt;/etc/my.cnf&lt;/code&gt;.  Usually doesn't need tweaking, except when using the InnoDB storage engine, or if you have high performance requirements. &lt;/p&gt; &lt;p&gt;The main command line utilities are mysql, mysqldump, and mysqladmin. Many people like the phpMyAdmin package to manage MySQL through a web browser. &lt;/p&gt; &lt;p&gt; MySQL is not part of the default install in OS X. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Server Administration&lt;/b&gt;&lt;br /&gt;&lt;hr /&gt; &lt;b&gt;Show all running MySQL processes&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqladmin --user=root --password=xxx processlist&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Show detailed status report&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqladmin --user=root --password=xxx extended-status&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reload grant tables (after making security table changes)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqladmin --user=root --password=xxx reload&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Show running configuration settings&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqladmin --user=root --password=xxx variables&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Kill a slow or locked process&lt;/b&gt;&lt;br /&gt;First, get the process id using processlist, then&lt;br /&gt;&lt;code&gt;mysqladmin --user=root --password=xxx kill id&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reset the value of an autoincrement field in a table&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;mysql --user=root database&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;alter table tablename autoincrement=100;&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt; &lt;i&gt;Note: the above resets the autoincrement field to 100.  Use caution!&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Alter a table so it can grow beyond 4 GB in size&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Even if your OS supports file sizes greater than 4 GB, and even though MySQL supports tables larger than 4 GB, it will still give you a "table full" error message if you try to insert records into a table that has reached 4 GB unless you tell it to allow tables to grow larger. You can set a global option in my.cnf or you can tell MySQL on a table by table basis. This command will allow a table to grow to roughly 300 GB:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ALTER TABLE tbl_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=300;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Security&lt;/b&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;b&gt;Change/set the root password&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;mysql --user=root mysql&lt;/code&gt; (initially no password)&lt;/li&gt;&lt;li&gt;&lt;code&gt;     update user set Password=password('new_password') where user='root';     &lt;/code&gt;   &lt;/li&gt;&lt;li&gt;&lt;code&gt;flush privileges;&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt; &lt;b&gt;Create a user with remote update authority&lt;/b&gt;&lt;br /&gt;  &lt;ol&gt;&lt;li&gt;&lt;code&gt;mysql --user=root --password=xxx mysql&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;insert into user (Host, User, Password, Select_priv, Insert_priv,       Update_priv, Delete_priv) values ('%', 'remote', password('xxx'),              'Y', 'Y', 'Y', 'Y');&lt;/code&gt;     &lt;/li&gt;&lt;li&gt;&lt;code&gt;flush privileges;&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt; &lt;h4&gt;Create a user with access to just the db1 database&lt;/h4&gt; &lt;ol&gt;&lt;li&gt;&lt;code&gt;mysql --user=root --password=xxx mysql&lt;/code&gt;&lt;/li&gt;&lt;li&gt;      &lt;code&gt;      insert into user (Host, User, Password)&lt;br /&gt;     values ('localhost', 'foo', password('xxx'));&lt;br /&gt;     &lt;/code&gt;   &lt;/li&gt;&lt;li&gt;      &lt;code&gt;      insert into db (Host, Db, User, Select_priv, Insert_priv,&lt;br /&gt;     Update_priv, Delete_priv) values ('localhost', 'db1', 'foo',&lt;br /&gt;     'Y', 'Y', 'Y', 'Y');&lt;br /&gt;     &lt;/code&gt;   &lt;/li&gt;&lt;li&gt;&lt;code&gt;flush privileges;&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Backup and Restore&lt;/b&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;b&gt;Dump all databases (schema and data)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqldump --user=root --password=xxx --all-databases &gt; databases.sql&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a single database (schema and data)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqldump --user=root --password=xxx --databases db1 &gt; db1.sql&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dump a single database (schema only)&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysqldump --all --no-data --user=root --password=xxx --databases db1 &gt; db1.sql        &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Restore a database from a dump file&lt;/b&gt;&lt;br /&gt;&lt;code&gt;mysql --user=root --password=xxx &lt;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Load data from a text file&lt;/b&gt;&lt;br /&gt;&lt;hr /&gt; &lt;p&gt; The &lt;code&gt;LOAD DATA INFILE&lt;/code&gt; statement reads rows from a text file into a table at a very high speed. &lt;/p&gt; &lt;p&gt; For security reasons, when reading text files located on the server, the files must either reside in the database directory or be readable by all. Also, to use LOAD DATA INFILE on server files, you must have the FILE privilege on the server host. You can also load datafiles by using the &lt;code&gt;mysqlimport&lt;/code&gt; utility; it operates by sending a LOAD DATA INFILE command to the server. &lt;/p&gt; &lt;p&gt; The defaults cause LOAD DATA INFILE to act as follows when reading input: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Look for line boundaries at newlines.&lt;/li&gt;&lt;li&gt;Do not skip over any line prefix.&lt;/li&gt;&lt;li&gt;Break lines into fields at tabs.&lt;/li&gt;&lt;li&gt;Do not expect fields to be enclosed within any quoting characters.&lt;/li&gt;&lt;li&gt;Interpret occurrences of tab, newline, or .. preceded by .. as literal characters that are part of field values.&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;Example using the defaults (tab delimited):&lt;/b&gt;&lt;br /&gt;&lt;code&gt;LOAD DATA INFILE "data.txt" INTO TABLE &lt;em&gt;table&lt;/em&gt;;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Example using an unquoted CSV file:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;LOAD DATA INFILE "data.txt" INTO TABLE &lt;em&gt;table&lt;/em&gt; FIELDS TERMINATED BY ',';&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tuning&lt;/b&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;b&gt;Log slow queries&lt;/b&gt;&lt;br /&gt;&lt;p&gt; MySQL can log queries that take a long time to complete by adding this option to /etc/my.cnf in the [mysqld] section:&lt;br /&gt;&lt;code&gt;log-slow-queries=/var/log/mysqld.slowquery.log&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The file should be created first with an owner of mysql:mysql. By default, a slow query is one that takes more than 10 seconds. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1530683371923508314?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1530683371923508314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1530683371923508314'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/mysql.html' title='MySQL'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1239852631170568291</id><published>2008-12-11T17:05:00.001-08:00</published><updated>2008-12-11T17:05:35.170-08:00</updated><title type='text'>Gnu Privacy Guard (GPG)</title><content type='html'>The &lt;a href="http://www.gnupg.org/"&gt;Gnu Privacy Guard (GPG)&lt;/a&gt; is a command line application that can use public key encryption to safeguard text and data and prepare it for transport through the email system.&lt;br /&gt;&lt;br /&gt;It is not part of the default install of OS X and must be installed manually.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To generate a new key pair:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --gen-key&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To list keys on your public keyring:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --list-keys&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To list keys on your secret keyring:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --list-secret-keys&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To encrypt a text file "message.txt" for recipient "foo" with ASCII armor (Base64):&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg -e -a -r foo message.txt&lt;/code&gt;&lt;br /&gt;The encrypted message is saved as file "message.txt.asc".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To encrypt a text file "message.txt" for recipient "foo" with ASCII armor and sign it with your secret key:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg -s -e -a -r foo message.txt&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To import a public key:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --import keyfile&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To sign a newly imported key with your secret key:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --sign-key keyname&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To delete a public key from the keyring:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --delete-key keyname&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To verify a file with a detached signature:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --verify signature data-file&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To import a public key:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;gpg --import keyfile&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Set up a trusted public key (no passphrase required):&lt;/b&gt;&lt;br /&gt;&lt;p&gt; If you want to encrypt files in a script and not be prompted for your passphrase, you need to sign all public keys you want to use. Follow this procedure (GPG 1.2.5+) to sign a public key. &lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;gpg --edit-key keyname&lt;/code&gt;&lt;/li&gt;&lt;li&gt;at the prompt, enter "trust"&lt;/li&gt;&lt;li&gt;select "4" for trust fully&lt;/li&gt;&lt;li&gt;enter "lsign" to locally sign it&lt;/li&gt;&lt;li&gt;at the prompt, enter 3 for very careful checking&lt;/li&gt;&lt;li&gt;answer "yes" to the the "Really Sign?" prompt&lt;/li&gt;&lt;li&gt;enter secret key passphrase when requested&lt;/li&gt;&lt;li&gt;enter "save"&lt;/li&gt;&lt;/ol&gt; The key is now signed and can be used in a script without passphrase requirements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1239852631170568291?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1239852631170568291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1239852631170568291'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/gnu-privacy-guard-gpg.html' title='Gnu Privacy Guard (GPG)'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4509960987878843284</id><published>2008-12-11T16:58:00.000-08:00</published><updated>2008-12-11T17:04:47.947-08:00</updated><title type='text'>A Bourne Again Daemon</title><content type='html'>In Unix-like systems, a daemon is a process that runs in the background, usually providing some kind of service. Most daemons can be identified in the process list because their names end in &lt;i&gt;d&lt;/i&gt;. Examples are the Apache web server (httpd) and the OpenSSH server (sshd). Another thing daemons usually have in common is that they are written in the C programming language. To create a daemon quickly, you can throw one together using the Bourne Again Shell (Bash) scripting language.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note: originally published April 20, 2006 on linuxboxadmin.com&lt;/i&gt;&lt;br /&gt;&lt;i&gt;updated for OS X on August 15, 2007&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;More about daemons&lt;/b&gt;&lt;br /&gt;&lt;p&gt; There are a couple of other common daemon characteristics. They often have a configuration file with a name ending in ".conf". You can tell a daemon to read its configuration file again by sending it signal HUP (1). Lastly, daemons usually listen on a particular TCP or UDP port for incoming network connections. The network functionality is the only feature we won't duplicate using BASH. It is possible to add a network aware program to a BASH daemon, but that is left as an exercise for the reader. &lt;/p&gt; &lt;b&gt;Please allow me to introduce myself&lt;/b&gt;&lt;br /&gt;&lt;p&gt; Here is the basic structure of a BASH daemon: &lt;/p&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;# This is a simple daemon shell script.&lt;br /&gt;#&lt;br /&gt;# Traps:&lt;br /&gt;# signal HUP (1) read config file again&lt;br /&gt;# signal QUIT (3) delete temp files&lt;br /&gt;# signal TERM (15) delete temp files&lt;br /&gt;&lt;br /&gt;conf=/tmp/bashdaemon.conf&lt;br /&gt;source $conf&lt;br /&gt;tempfile=/tmp/BASHDAEMON_$$&lt;br /&gt;touch $tempfile&lt;br /&gt;&lt;br /&gt;# set traps&lt;br /&gt;trap 'source $conf' 1&lt;br /&gt;trap 'rm -f $tempfile; exit' 0&lt;br /&gt;trap 'rm -f $tempfile; exit' 3&lt;br /&gt;trap 'rm -f $tempfile; exit' 15&lt;br /&gt;&lt;br /&gt;# loop forever&lt;br /&gt;while :&lt;br /&gt;do&lt;br /&gt;   echo $foo&lt;br /&gt;   echo $bar&lt;br /&gt;   sleep 30&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt; If you want to play along at home, save the script as &lt;i&gt;bashdaemon.sh&lt;/i&gt; and make it executable with:&lt;br /&gt;&lt;code&gt;chmod a+x bashdaemon.sh&lt;/code&gt;&lt;br /&gt; &lt;p&gt; The bashdaemon.conf file contains variable assignments for two variables, &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;.  It starts out like this:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;foo=famine&lt;br /&gt;bar=death&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt; Let's walk through the script line by line. &lt;/p&gt; &lt;p&gt; &lt;code&gt;conf=/tmp/bashdaemon.conf&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This line defines the configuration file, called /tmp/bashdaemon.conf. In the example, all files are in the /tmp directory, but if you want to follow daemon convention, you could put it in /etc. &lt;/p&gt; &lt;p&gt; &lt;code&gt;source $conf&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The source command is a BASH built-in that reads and executes the configuration file, activating the variable assignments. &lt;/p&gt; &lt;p&gt; &lt;code&gt;tempfile=/tmp/BASHDAEMON_$$&lt;br /&gt;touch $tempfile&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The tempfile serves two purposes. It can be used as work area and it stores the process ID of the daemon in the file name. For example, if the process ID was 1234, the tempfile name would be /tmp/BASHDAEMON_1234. As long as the daemon is running, the tempfile will exist. It gets automatically deleted when the daemon ends (unless it is killed with signal KILL (9)). &lt;/p&gt; &lt;p&gt; &lt;code&gt;trap 'source $conf' 1&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This trap allows the daemon to capture signal HUP (1) and tells it to source the configuration file again and continue running. If the variable assignments have been changed, the new values take effect. &lt;/p&gt; &lt;p&gt; &lt;code&gt; trap 'rm -f $tempfile; exit' 0&lt;br /&gt;trap 'rm -f $tempfile; exit' 3&lt;br /&gt;trap 'rm -f $tempfile; exit' 15&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;These lines trap signals 0, 3, and 15 to delete the tempfile, then exit. See below for more about traps. &lt;/p&gt; &lt;pre&gt;while :&lt;br /&gt;do&lt;br /&gt;   echo $foo&lt;br /&gt;   echo $bar&lt;br /&gt;   sleep 30&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt; &lt;p&gt; The loop uses a never ending &lt;code&gt;while&lt;/code&gt; statement to run until it is ended with one of the signals that tell it to exit or signal 9, killing it unconditionally. Inside the loop, the daemon does its work. In the example, it just prints the contents of the &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; variables, then goes to sleep for 30 seconds. &lt;/p&gt; &lt;b&gt;Traps&lt;/b&gt;&lt;br /&gt;&lt;p&gt; For those not familiar with traps, a few more words are in order. If you already know about traps, skip ahead. Linux (and Unix) defines a set of messages called signals that can be sent to a program to tell it what to do. The "kill" program is used to send signals from the command line. To view the complete list of signals, try:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;kill -l&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That is an L, not the numeral one. For example, the hang up signal (HUP) is signal 1 and the QUIT signal is signal 3. When a program receives the QUIT signal, it exits immediately, unless the program is written to recognize that signal and take other action. Intercepting a signal is called a trap. Most languages have a trap function and in BASH, it is the &lt;i&gt;trap&lt;/i&gt; built-in function. The one signal that can't be trapped is KILL -- signal 9. The man page has more details. &lt;/p&gt;  &lt;b&gt;Firing it up&lt;/b&gt;&lt;br /&gt;&lt;p&gt; There are many ways to run a Bash daemon, depending on how formal you want to get. The least formal way is to start it from a terminal session with the background operator:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;./bashdaemon.sh &amp;amp;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This starts the daemon in the background and works, but requires the terminal session to remain open. Another option is to start it from a screen session. &lt;a href="ftp://ftp.uni-erlangen.de/pub/utilities/screen/"&gt;Screen&lt;/a&gt; is a program that lets you detach a process from the terminal and reattach to it later, even from a different computer. If you haven't tried screen before, it is a powerful tool worth learning. After launching the daemon from screen, you can simply detach, close the terminal, and check on it later as needed. &lt;/p&gt; &lt;p&gt; The most formal option in OS X is to set up a property list file like the big daemons use and have &lt;code&gt;launchd&lt;/code&gt; manage it. Linux users could set up a run control script in /etc/rc.d/init.d/. On the other hand, if you need to go to these lengths, you probably need to write it in a more appropriate language. BASH daemons excel at quick and dirty solutions. &lt;/p&gt;  &lt;b&gt;Killing it softly&lt;/b&gt;&lt;br /&gt;&lt;p&gt;To test the signal HUP trap, I started the BASH daemon in the background, then changed the variable assignments in the bashdaemon.conf file. After my edits, the bashdaemon.conf file looked like this:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;foo=pestilence&lt;br /&gt;bar=war&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt; Next, I found the process ID of the daemon (1927) by looking at the tempfile name in /tmp.  Then, I sent signal 1 to it using:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;kill -s HUP 1927&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After it received the signal, it started printing the new values from bashdaemon.conf. To kill it for good, I pulled the daemon back into the foreground with code&gt;fg and used Ctrl-C to end it. Afterward, the tempfile was gone as expected. &lt;/p&gt;  &lt;b&gt;Daemons for work and play&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Some interesting near real-time stuff can be done with BASH daemons. You could monitor a database, be notified when a certain user logs in, take action when a file is accessed, when a program is run, or anything you dream up. Summon your own daemons to do your bidding. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4509960987878843284?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4509960987878843284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4509960987878843284'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/bourne-again-daemon.html' title='A Bourne Again Daemon'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1668948381253600898</id><published>2008-12-11T16:56:00.000-08:00</published><updated>2008-12-11T16:58:01.160-08:00</updated><title type='text'>Perl</title><content type='html'>&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;Perl is a popular text processing language that has been extended into nearly every corner of computing. It is not one of my favorite scripting languages, but there are some things it does very well. I sometimes run across Perl applications that I want to run or customize. These tips can be useful in managing Perl.&lt;br /&gt;&lt;br /&gt;Perl is part of the default install of OS X.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Set up CPAN&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;perl -MCPAN -e shell&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all Perl modules currently installed&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;find `perl -e 'print "@INC"'` -name '*.pm' -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Taint mode&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;For untrusted scripts, add -T flag to perl at the start of the script:&lt;br /&gt;&lt;i&gt;#!/usr/local/bin/perl -T&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;One liner to edit files in place&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This command edits a group of files in place.  In particular, it does a global search/replace.  The &lt;i&gt;-p&lt;/i&gt; switch tells perl to iterate over filename arguments, &lt;i&gt;-i&lt;/i&gt;  tells perl to edit files in place, and &lt;i&gt;-e&lt;/i&gt; indicates that a one line program follows.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;perl -p -i -e 's/248/949/g' *.txt&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;One liner to edit files in place and backup each one to *.old&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;perl -p -i.old -e 's/248/949/g' *.txt&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1668948381253600898?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1668948381253600898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1668948381253600898'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/perl.html' title='Perl'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4319062633102208339</id><published>2008-12-11T16:52:00.001-08:00</published><updated>2008-12-11T16:52:58.654-08:00</updated><title type='text'>Rsync</title><content type='html'>Rsync is a file and directory syncronization tool. It can be used to keep local and/or remote files syncronized. What makes rsync powerful is that it can detect changes within large files and only transfer the parts that are different. This is much more efficient than transfering entire files, especially as the file sizes get bigger.&lt;br /&gt;&lt;br /&gt;The rsync utility is part of the default installation in OS X.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Note: examples that use a shell use ssh with public key authentication&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a local directory with a remote one (pull), use:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -r -a -v -e "ssh -l username" --delete hostname:/remote/dir/ /local/dir/&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a remote directory with a local one (push), use:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -r -a -v -e "ssh -l username" --delete /local/dir/  hostname:/remote/dir/&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a local file with a remote one, use:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -a -v -e "ssh -l username" hostname:/filename  /local/filename&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a remote file with a local one, use:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -a -v -e "ssh -l username" /local/filename hostname:/filename&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a local directory with a remote rsync server:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -r -a -v --delete rsync://rsync-server.com/stage/ /home/stage/&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To synchronize a local directory with a local directory (make a backup), use:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rsync -r -a -v --delete /local/dir/ /backup/dir/&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4319062633102208339?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4319062633102208339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4319062633102208339'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/rsync.html' title='Rsync'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7882493976823609024</id><published>2008-12-11T16:51:00.000-08:00</published><updated>2008-12-11T16:52:15.907-08:00</updated><title type='text'>BASH job control: fg, bg, jobs, and Ctrl-Z</title><content type='html'>The BASH shell has a feature called &lt;b&gt;job control&lt;/b&gt; that allows you to run and manage multiple processes from a single interactive prompt. In the age of serial connected dumb terminals, this was a killer feature. In the age of multi-homed multi-core Macs, not so killer, but there are certain situations where it can still be useful.&lt;br /&gt;&lt;br /&gt;The commands I want to focus on are &lt;i&gt;bg&lt;/i&gt; (background), &lt;i&gt;fg&lt;/i&gt; (foreground), and &lt;i&gt;jobs&lt;/i&gt;. These are all &lt;b&gt;shell builtins&lt;/b&gt;, meaning they are commands built into and handled by BASH itself instead of being external programs, like the &lt;i&gt;top&lt;/i&gt; program. Examples in this article were run on Mac OS 10.4.10.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Since the advent of the GUI, one solution to running multiple shell commands at a time is to open more than one terminal window. The beauty of this solution is that you can see both display windows at the same time and monitor what is happening. You can also copy and paste information between them. &lt;/p&gt; &lt;p&gt;What about times when you are connected to remote Mac (or Linux or Unix) computer with secure shell? Now, you are back to the single interactive shell and the job control commands can be of assistance. Yes, you can always open another terminal on your computer and establish a second secure shell connection, but that may be more trouble than it's worth. &lt;/p&gt; &lt;p&gt;Here is a scenario where job control can help get your work done a little faster. Again, say you have logged into a remote computer using secure shell and you start a long running job, such as compiling a large program from source, or updating the locate database. As an aside, the locate database came to the Mac from the BSD world where there was no spotlight. It lets you quickly find files based on a partial file name. It doesn't search inside files like spotlight, it only looks at file names. The Mac command for updating the locate database is a C shell script named &lt;i&gt;/usr/libexec/locate.updatedb&lt;/i&gt;. It can be run directly:&lt;br /&gt;&lt;br /&gt;keithw$ &lt;i&gt;/usr/libexec/locate.updatedb&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;note: if run as a regular user, it won't be able to scan all directories, so it should really be run as root. &lt;/p&gt; &lt;p&gt; Since it takes a long time to run, you will be unable to run any other commands until it finishes. The script is running in the foreground of the interactive shell. You can force it into the background by using Ctrl-Z. The Ctrl-Z sequence pushes the foreground job into the background, pauses it, and gives control back to you. When I use Ctrl-Z, I see this output:&lt;br /&gt;&lt;br /&gt;[1]+  Stopped      /usr/libexec/locate.updatedb&lt;br /&gt;&lt;br /&gt;This means job number 1 has been stopped and shows the associated command. To check the status of the all background jobs, use the &lt;i&gt;jobs&lt;/i&gt; command with the -l (list) switch:&lt;br /&gt;&lt;br /&gt;keithw$ &lt;i&gt;jobs -l&lt;/i&gt;&lt;br /&gt;[1]+  4836 Suspended               /usr/libexec/locate.updatedb&lt;br /&gt;&lt;/p&gt; &lt;p&gt; Now we have control of the terminal back, but the script we started is currently not running.  That can be fixed by using the &lt;i&gt;bg&lt;/i&gt; command. The &lt;i&gt;bg&lt;/i&gt; command tells BASH to run the specified job number in the background. You don't need to give it a job number if there is only one background job. This gets the script running again:&lt;br /&gt;&lt;br /&gt;keithw$ &lt;i&gt;bg&lt;/i&gt;&lt;br /&gt;[1]+ /usr/libexec/locate.updatedb &amp;amp;&lt;br /&gt;keithw$ &lt;i&gt;jobs -l&lt;/i&gt;&lt;br /&gt;[1]+  4836 Running                      /usr/libexec/locate.updatedb &amp;amp; &lt;/p&gt; &lt;p&gt; At this point, we have interactive control, the script is running in the background, and we can do something else while it finishes. When it is done, the shell will send us a notice. If you want to bring it back to the foreground, use the &lt;code&gt;fg&lt;/code&gt; command. Then, you are back where you started, waiting for it to finish. Generally, you would only use the fg command, if you have multiple background jobs running, and want to interact with one of them. You could theoretically have a text editor, a compile, and a long running script all running as jobs and swap them in and out as needed. &lt;/p&gt; &lt;p&gt;Take a closer look at the output from the jobs command above. Notice the &amp;amp; at the end of the command? You can start a job running in the background by appending an &amp;amp; to the end of the command. Had we done that originally, it would have started in the background and returned interactive control immediately. But for those times when you forget, the job control commands are your friends. &lt;/p&gt; &lt;b&gt;The difference between job number and process ID&lt;/b&gt; &lt;p&gt;I want to make a distinction between jobs and processes. Each running program in the operating system has a process ID (pid). From the shell's point of view, each background process is a job and jobs get assigned numbers starting at 1. The second background process would be job 2. To reference a background process when using the &lt;i&gt;fg&lt;/i&gt; or &lt;i&gt;bg&lt;/i&gt; commands, use the job number instead of the process ID. For sending operating system signals to a background process, you use the process ID. Going back to the last &lt;i&gt;jobs&lt;/i&gt; command, the process ID is printed after the job number, in this case 4836. To kill the background process unconditionally, you would send it the KILL signal using the process ID instead of job number:&lt;br /&gt;&lt;br /&gt;keithw$ &lt;i&gt;kill -9 4836&lt;/i&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7882493976823609024?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7882493976823609024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7882493976823609024'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/bash-job-control-fg-bg-jobs-and-ctrl-z.html' title='BASH job control: fg, bg, jobs, and Ctrl-Z'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2914008931475617486</id><published>2008-12-11T16:50:00.000-08:00</published><updated>2008-12-11T16:51:02.735-08:00</updated><title type='text'>Tar</title><content type='html'>Tar, (short for tape archiver), is a versital tool that can be used for archiving files to disk or any other device as easily as tape. In fact, if you don't work in a data center, you will probably never use tar with a tape drive.&lt;br /&gt;&lt;br /&gt;Often, Unix/BSD/Linux files and source code are distributed in a zipped tar file, sometimes called a tarball. Extensions for tarballs are usually .tgz or .tar.gz (gz because it was compressed using gzip, the free GNU zip program). Rarely, you may run across a tar file that is not compressed and has an extension of simply .tar.&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Here are some common uses for tar. If you pass a directory or a wildcard to tar, it will include all subdirectories in the tar file by default. &lt;/p&gt;  &lt;b&gt;Create a gzipped tar archive&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar czvf backup.tgz files-to-backup&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Create a gzipped tar archive, preserving file permissions&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar czvpf backup.tgz files-to-backup&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Extract a gzipped tar archive&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar xzvf backup.tgz files-to-backup&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Create a bzipped tar archive (using bzip compression instead of gzip)&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar cjvf backup.bz2 files-to-backup&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Extract a bzipped tar archive&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar xjvf backup.bz2 files-to-backup&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List files in a tar archive without extracing&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar tf backup.tgz&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List files in a zipped tar archive without extracing&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tar tzf backup.tgz&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2914008931475617486?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2914008931475617486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2914008931475617486'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/tar.html' title='Tar'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8362274236696435590</id><published>2008-12-11T16:48:00.002-08:00</published><updated>2008-12-11T16:50:34.857-08:00</updated><title type='text'>SSH</title><content type='html'>The following are tips for both the Secure Shell daemon (server) and the SSH command line client inlcuded with Mac OS X.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;SSH daemon (server)&lt;/b&gt;&lt;br /&gt;&lt;p&gt; The first time sshd runs, it generates three cryptographic key pairs and stores the keys in the /private/etc/ directory. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;ssh_host_key and ssh_host_key.pub (v1)&lt;/li&gt;&lt;li&gt;ssh_host_dsa_key and ssh_host_dsa_key.pub (v2 DSA)&lt;/li&gt;&lt;li&gt;ssh_host_rsa_key and ssh_host_rsa_key.pub (v2 RSA)&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt; SSH communicates over TCP port 22 by default. The global server configuration file is:&lt;br /&gt;&lt;i&gt;/private/etc/sshd_config&lt;/i&gt; &lt;/p&gt; To deny all remote SSH root logins (generally a good idea), set this value in the sshd_config file:&lt;br /&gt;&lt;i&gt;PermitRootLogin no&lt;/i&gt;  &lt;p&gt; To disable the less secure v1 SSH protocol, set this value in the sshd_config file:&lt;br /&gt;&lt;i&gt;Protocol 2&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To disable X forwading, set this value in the sshd_config file:&lt;br /&gt;&lt;i&gt;X11Forwarding no&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To disable keyboard password logins (force public/private key authentication), set this value in the sshd_config file:&lt;br /&gt;&lt;i&gt;PasswordAuthentication no&lt;/i&gt; &lt;/p&gt;  &lt;b&gt;SSH client&lt;/b&gt;&lt;br /&gt;&lt;p&gt; Note: because of its sensitive nature, the &lt;b&gt;$HOME/.ssh/&lt;/b&gt; directory and most of the files in it MUST be read/write for the user and not accessible to group or other. For example, the file permissions should look like this:&lt;br /&gt;-rw-------&lt;br /&gt;Otherwise, SSH will ignore them.  If you copy personal SSH files to a new system and they don't work, check the permissions. &lt;/p&gt; &lt;p&gt; The default client configuration file is:&lt;br /&gt;&lt;i&gt;/private/etc/ssh_config&lt;/i&gt;&lt;br /&gt;The user configuration file, &lt;i&gt;$HOME/.ssh/config&lt;/i&gt; takes precedence over the default configuration. &lt;/p&gt; &lt;p&gt; To connect to an SSH server using a different user ID:&lt;br /&gt;&lt;i&gt;ssh userid@server-name-or-IP&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To securely copy a local file(s) to a remote server, use scp:&lt;br /&gt;&lt;i&gt;scp localfile userid@server-name-or-IP:remotefile&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To securely copy remote file(s) to the local machine, use scp:&lt;br /&gt;&lt;i&gt;scp userid@server-name-or-IP:remotefile localfile&lt;/i&gt; &lt;/p&gt;  &lt;b&gt;Using public/private key encryption for authentication&lt;/b&gt;&lt;br /&gt;&lt;p&gt; First, generate a keypair for logins without passwords:&lt;br /&gt;&lt;i&gt;ssh-keygen -t dsa&lt;/i&gt;&lt;br /&gt;The system will prompt you for a secret key passphrase, then create the key pair in two files:&lt;br /&gt;&lt;i&gt; id_dsa (v2 private key)&lt;br /&gt;id_dsa.pub (v2 public key)&lt;br /&gt;&lt;/i&gt; Next, append the v2 public key to your &lt;i&gt;$HOME/.ssh/authorized_keys2&lt;/i&gt; file on the &lt;b&gt;server(s)&lt;/b&gt; where you want to login. &lt;/p&gt; &lt;p&gt; To bypass the passphrase that unlocks your secret key every time it is needed, load the key into ssh-agent. &lt;/p&gt;  &lt;b&gt;SSH-Agent&lt;/b&gt;&lt;br /&gt;&lt;p&gt; To load secret keys in the ssh-agent manually, execute: &lt;/p&gt;&lt;ol&gt;&lt;li&gt;ssh-agent&lt;/li&gt;&lt;li&gt;ssh-add keyfile (once for each key)&lt;/li&gt;&lt;/ol&gt;  &lt;p&gt; It is usually more convenient to run ssh-agent and load keys in a BASH login.  Linux users can use the &lt;a href="http://www.gentoo.org/proj/en/keychain/"&gt;keychain script&lt;/a&gt;. &lt;/p&gt;  &lt;b&gt;Port Forwarding&lt;/b&gt;&lt;br /&gt;&lt;p&gt; SSH can port forward local and remote connections securely. Only root can forward privileged ports (&lt;=1024) &lt;/p&gt;&lt;p&gt; To redirect a local port to a remote host port:&lt;br /&gt;&lt;i&gt;ssh userid@remotehost -L localport:remotehost:remoteport&lt;/i&gt; &lt;/p&gt; &lt;p&gt; To redirect a remote port to a local or remote host port:&lt;br /&gt;&lt;i&gt;ssh userid@remotehost -R remoteport:host:localport&lt;/i&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8362274236696435590?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8362274236696435590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8362274236696435590'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/ssh.html' title='SSH'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7929108844259481152</id><published>2008-12-11T16:48:00.001-08:00</published><updated>2008-12-11T16:48:47.386-08:00</updated><title type='text'>Fix a broken terminal</title><content type='html'>&lt;b&gt;To fix a broken terminal, try one of these commands:&lt;/b&gt;&lt;br /&gt;&lt;i&gt; tput init&lt;br /&gt;tput reset&lt;br /&gt;reset&lt;br /&gt;[ENTER] reset [ENTER] &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;If binary characters are sent to a terminal, it will often leave the screen in an abnormal state because it interprets them as control characters. A random stream of control characters can make the terminal unreadable. You may not be able to see the commands as you type them until the terminal is reset, or you may see junk characters as you type. Often, though, one of the above commands will clear up the problem.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To see the device of the current terminal:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;tty&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Pseudo-terminals under OS X Aqua are usually /dev/ttyp?.  For example, /dev/ttyp1, /dev/ttyp2, etc.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To see all current terminal settings:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;stty -a&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7929108844259481152?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7929108844259481152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7929108844259481152'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/fix-broken-terminal.html' title='Fix a broken terminal'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-340790035235598100</id><published>2008-12-11T16:46:00.000-08:00</published><updated>2008-12-11T16:48:16.401-08:00</updated><title type='text'>Daily aliases</title><content type='html'>If you spend any time working with the shell, you probably use many GNU or BSD utilities. One thing that distinguishes the newer free software versions from the classic Unix versions is that the free software programs are rife with additional options. Some of these options are so useful you may want to create an alias so you can use them all the time.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note: originally published December 12, 2005 on newsforge.com&lt;/i&gt;&lt;br /&gt;&lt;i&gt;updated for Mac OS X on July 27, 2007&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; A shell alias is a simple way to create your own custom command. To make your aliases available every time you open a BASH shell, add them to your $HOME/.bash_login file. For other shells, place them in the associated run control file. In OS X, the default BASH configuration doesn't include very much, really just a slightly customized prompt. When I start working on a new system, I immediately install my favorite aliases. &lt;/p&gt; &lt;p&gt; An alias is created using the following syntax:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;alias name='value'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;where name is the name of the new command and value is the command string that is executed. Note, if you create an alias with the same name as an existing executable program in your path, the shell will run the alias instead of the program. &lt;/p&gt; &lt;p&gt; To remove an alias from your current shell session, use:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;unalias name&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;where name is an existing alias. &lt;/p&gt; &lt;p&gt; To see all the current aliases known to your shell, type &lt;i&gt;alias&lt;/i&gt; with no parameters. &lt;/p&gt; &lt;p&gt; All of the following aliases were created and tested on OS 10.4.10 using the standard BASH shell. &lt;/p&gt;  &lt;b&gt;List the most recently modified files and directories&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias lt='ls -alt | head -20'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Once this alias is loaded, typing &lt;i&gt;lt&lt;/i&gt; lists the most recently modified contents of the current directory. The a and l options show all files including hidden files in a long listing format. Since I am usually interested in a file I have just changed, I limit the output to 20 lines with the &lt;i&gt;head&lt;/i&gt; command. &lt;/p&gt;  &lt;b&gt;List only subdirectories&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias lsd='ls -al -d * | egrep "^d"'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This shows only subdirectories of the current directory by using egrep to limit the listing to entries with the 'd' directory attribute. &lt;/p&gt;  &lt;b&gt;Show the inode number for files in the current directory&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias li='ls -ai1 | sort'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This prints the inode number (file system block identifier) for each file, sorted in ascending order. The last option to ls in this alias is the numeral one, not the letter L. You might need the inode number for file system repair or to recover data from a damaged file. &lt;/p&gt;  &lt;b&gt;Scramble a file using the ROT13 algorithm&lt;/b&gt; &lt;p&gt; &lt;i&gt;alias rot13='tr A-Za-z N-ZA-Mn-za-m'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This shifts all letters in a file 13 characters up the alphabet, creating scrambled, but not encrypted text. Running ROT13 on the scrambled text restores it. ROT13 was used back in the day on newsgroups to politely hide potentially offensive text. I almost never run across ROT13 text these days which may be a sign of lost Net innocence. To use the alias, redirect a file to standard input:&lt;br /&gt;&lt;br /&gt;keithw$ rot13 &lt; /etc/motd&lt;br /&gt;Jrypbzr gb Qnejva! &lt;/p&gt;  &lt;b&gt;Fast directory navigation with pushd and popd&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias +='pushd .'&lt;br /&gt;alias _='popd'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I tend to move around a lot on the command line. If I am working on code in a deeply nested directory, but need to go check some log files, I'll use the shell built-in pushd command to save my current directory location and popd to get back to the directory later. These aliases simplify the process by entering &lt;i&gt;'+'&lt;/i&gt; before changing directories, and &lt;i&gt;'_'&lt;/i&gt; to return to the directory later. You can push more than one directory on to the stack and pop them back off in reverse order. I used the underscore instead of the minus sign for popd because the minus sign is a reserved symbol. &lt;/p&gt;  &lt;b&gt;Find disk space abusers&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias dusk='du -s -k -c * | sort -rn'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Shows disk usage of files and subdirectories in the current directory, sorted with the ones using the most disk space first. The report shows disk usage in 1K increments and the total for the directory at the top. Beware, if you start this command from the root directory or at the top of a deeply nested directory, it could run a long time. Here is a sample report:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt; keithw$ dusk&lt;br /&gt;1756    total&lt;br /&gt;528     micro&lt;br /&gt;444     articles&lt;br /&gt;408     images&lt;br /&gt;152     move&lt;br /&gt;48      cgi-bin&lt;br /&gt;36      inc&lt;br /&gt;28      src&lt;br /&gt;24      index.html&lt;br /&gt;20      index.html.new&lt;br /&gt;12      xref&lt;br /&gt;8       send.php&lt;br /&gt;8       feed.xml&lt;br /&gt;8       css&lt;br /&gt;&lt;/pre&gt;   &lt;b&gt;Show all programs connected or listening on a network port&lt;/b&gt;&lt;br /&gt;&lt;p&gt; &lt;i&gt;alias nsl='netstat -alnp ip | grep -v CLOSE_WAIT | cut -c-6,21-94 | tail +2'&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Since netstat is used to look at all system info, you need to run this as root. It shows the process ID and program name of everything either connected or listening on a network port, including the sockets of the sending and receiving hosts. This is a great way to make sure no unexpected services are running in the background. Here is a sample report:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;Proto  Local Address          Foreign Address        (state)&lt;br /&gt;tcp4   192.168.1.137.63819    209.85.139.83.443      ESTABLISHED&lt;br /&gt;tcp4   192.168.1.137.63817    209.85.139.83.443      ESTABLISHED&lt;br /&gt;tcp4   192.168.1.137.22       199.199.199.199.4570   ESTABLISHED&lt;br /&gt;tcp4   *.*                    *.*                    CLOSED&lt;br /&gt;tcp4   127.0.0.1.1033         127.0.0.1.990          ESTABLISHED&lt;br /&gt;tcp4   127.0.0.1.990          127.0.0.1.1033         ESTABLISHED&lt;br /&gt;tcp4   127.0.0.1.631          *.*                    LISTEN&lt;br /&gt;tcp4   *.5432                 *.*                    LISTEN&lt;br /&gt;tcp6   *.5432                                        *.*&lt;br /&gt;&lt;/pre&gt;   &lt;b&gt;Combinations and Permutations&lt;/b&gt;&lt;br /&gt;&lt;p&gt; If you want to dig deeper into any of the options used in these aliases, check out the man/info page for the command. There are so many permutations of options and commands that you can sometimes stumble across a cool solution by studying the more obscure options in the man/info pages. What are your favorite aliases? &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-340790035235598100?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/340790035235598100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/340790035235598100'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/daily-aliases.html' title='Daily aliases'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4435923523063970045</id><published>2008-12-11T16:41:00.000-08:00</published><updated>2008-12-11T16:42:34.842-08:00</updated><title type='text'>Unix permissions on OS X</title><content type='html'>There are nine standard permissions in Unix-like operating systems on each file (and directory). There is a set for the owner of the file, a set for the group owner of the file, and set for everyone else. Each set has a Read (r), a Write (w), and an eXecute (x) permission. You can view the permissions on a file by using the ls (list) command with the long format option (-l). The permissions are listed in rwx order. For example:&lt;br /&gt;&lt;br /&gt;keithw$ ls -l&lt;br /&gt;-rw-r--r--   1 keithw  keithw   6677 Apr  5  2006 ab.php&lt;br /&gt;&lt;br /&gt;The permissions are read+write for the owner, read for the group, and read for everyone else.&lt;br /&gt;&lt;br /&gt;In addition to the standard permissions (rwx), there are three special permissions that can be set for a file or directory: suid, sgid, and sticky bit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;suid&lt;/b&gt;&lt;br /&gt;&lt;p&gt;this special permission allows the file to be executed with the security permissions of the file owner instead of the permission of the user who ran the program. This can be a source of security problems. Some daemons run as suid root. The suid permission is seen as an "S" in the user executable position a long directory listing (ls -l). Has no effect if the file is not executable.&lt;br /&gt;&lt;br /&gt;To set the suid permission:&lt;br /&gt;&lt;i&gt;chmod u+s filename&lt;/i&gt; &lt;/p&gt;  &lt;b&gt;sgid&lt;/b&gt;&lt;br /&gt;&lt;p&gt;this special permission allows the file to be run with the security permissions of the group instead of the permission of the user who ran the program. This can be a source of security problems. The sgid permission is seen as an "S" in the group executable position in a long directory listing (ls -l). Has no effect if the file is not executable.&lt;br /&gt;&lt;br /&gt;To set the sgid permission:&lt;br /&gt;&lt;i&gt;chmod g+s filename&lt;/i&gt; &lt;/p&gt; &lt;p&gt; &lt;i&gt;note:&lt;/i&gt; If sgid is set on a directory, any file created within that directory will have the same group owner assigned as the directory. Useful when a group of users is sharing the same directory. &lt;/p&gt;  &lt;b&gt;sticky bit on a directory&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Prevents any files in a directory from being deleted by anyone but the owner of that file. Often used on the /tmp directory. Good to prevent accidental deletions by rm * commands. The sticky bit is seen as a t in the other executable position in a long directory listing (ls -l). Setting the sticky bit on a file is ignored.&lt;br /&gt;&lt;br /&gt;To set the sticky bit:&lt;br /&gt;&lt;i&gt;chmod u+t dirname&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note:&lt;/i&gt; in Linux, the option is set using the "other" permissions instead of "user":&lt;br /&gt;&lt;i&gt;chmod o+t dirname&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;In both cases, the "t" appears in the other executable position:&lt;br /&gt;drwxr-xr-t    2 keithw  keithw     68 Jul 26 09:02 test&lt;br /&gt;&lt;/p&gt; &lt;p&gt; Finally, Unix permissions are not the end of the story. The OS X file system can also use Access Control Lists stored in extended attributes to give you more fine grained access control. You can view extended attributes using the -e option of the &lt;i&gt;ls&lt;/i&gt; command.  See the &lt;i&gt;chmod&lt;/i&gt; and &lt;i&gt;ls&lt;/i&gt; man pages for more details. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4435923523063970045?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4435923523063970045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4435923523063970045'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/unix-permissions-on-os-x.html' title='Unix permissions on OS X'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-3503414976855530264</id><published>2008-12-11T16:40:00.002-08:00</published><updated>2008-12-11T16:41:23.956-08:00</updated><title type='text'>SMTP testing from the command line</title><content type='html'>&lt;b&gt;To test SMTP from the command line:&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;telnet &lt;i&gt;host-to-test&lt;/i&gt; 25 (connect to port 25 on mail server)&lt;/li&gt;&lt;li&gt;HELO &lt;i&gt;sending-host&lt;/i&gt;&lt;/li&gt;&lt;li&gt;MAIL FROM: foo@foo.com&lt;/li&gt;&lt;li&gt;RCPT TO: bar@bar.com&lt;/li&gt;&lt;li&gt;DATA&lt;br /&gt;&lt;/li&gt;&lt;li&gt;(enter one blank line after DATA)&lt;/li&gt;&lt;li&gt;   Subject: test&lt;br /&gt;  To: to-user&lt;br /&gt;  From: from-user&lt;br /&gt;  (enter one blank line after From:)&lt;br /&gt;  test text for email&lt;br /&gt;  . (enter a single period by itself on the last line)   &lt;/li&gt;&lt;li&gt;QUIT&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Read on for testing servers that use SMTP AUTH...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To test SMTP with SMTP AUTH (no TLS/SSL) from the command line:&lt;/b&gt;&lt;br /&gt;&lt;p&gt; First, use a Perl one liner to compute the Base64 encoded user ID and password needed to authenticate to the mail server. This requires the Perl MIME::Base64 module.&lt;br /&gt;&lt;br /&gt;perl -MMIME::Base64 -e 'print encode_base64("00userid00password")'&lt;br /&gt;&lt;br /&gt;The output looks something like this:&lt;br /&gt;AHVzZXJpZABwYXNzd29yZA==&lt;br /&gt;Copy the output string so it can be pasted into the AUTH step below. &lt;/p&gt; &lt;ol&gt;&lt;li&gt;telnet &lt;i&gt;host-to-test&lt;/i&gt; 25 (connect to port 25 on mail server)&lt;/li&gt;&lt;li&gt;HELO &lt;i&gt;sending-host&lt;/i&gt;&lt;/li&gt;&lt;li&gt;AUTH PLAIN &lt;i&gt;Base64-encoded ID/password&lt;/i&gt;&lt;/li&gt;&lt;li&gt;MAIL FROM: foo@foo.com&lt;/li&gt;&lt;li&gt;RCPT TO: bar@bar.com&lt;/li&gt;&lt;li&gt;DATA&lt;br /&gt;&lt;/li&gt;&lt;li&gt;(enter one blank line after DATA)&lt;/li&gt;&lt;li&gt;    Subject: test&lt;br /&gt;   To: to-user&lt;br /&gt;   From: from-user&lt;br /&gt;   (enter one blank line after From:)&lt;br /&gt;   test text for email&lt;br /&gt;   . (enter a single period by itself on the last line)   &lt;/li&gt;&lt;li&gt;QUIT&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-3503414976855530264?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3503414976855530264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/3503414976855530264'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/smtp-testing-from-command-line.html' title='SMTP testing from the command line'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8805529937707158088</id><published>2008-12-11T16:40:00.001-08:00</published><updated>2008-12-11T16:40:26.887-08:00</updated><title type='text'>List Open Files (lsof)</title><content type='html'>The &lt;i&gt;lsof&lt;/i&gt; program is a great tool to find open files. One case you might need this is to find a process that has an open file on a device you are trying to unmount. Another is if you want to determine what files a certain process is opening.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List your own open files (includes sockets and pipes):&lt;/b&gt;&lt;br /&gt;&lt;i&gt;lsof&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List all open files on the system (includes sockets and pipes), must be root:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;lsof&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List open files for certain processes, must be root:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;lsof -c pattern&lt;/i&gt;&lt;br /&gt;where &lt;i&gt;pattern&lt;/i&gt; is the first few letters of the process name or a regular expression between forward slashes /regexp/.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;List all open network sockets, must be root:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;lsof -i&lt;/i&gt;&lt;br /&gt;Useful to make sure something unexpected isn't listening to the network.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8805529937707158088?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8805529937707158088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8805529937707158088'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/list-open-files-lsof.html' title='List Open Files (lsof)'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1357454981809249456</id><published>2008-12-11T16:38:00.000-08:00</published><updated>2011-07-22T19:18:35.071-07:00</updated><title type='text'>Vi[m]</title><content type='html'>Vi is an one of two powerhouse text editors in the Unix world, the other being EMACS. While obtuse, vi is extremely powerful and efficient. There may be times when vi is the only text editor available, so it helps to at least know the basics.&lt;br /&gt;&lt;br /&gt;On Mac OS X (and Linux), vi is symlinked to vim (vi improved), a more modern free software version. Vim It is the default editor when changing a crontab.&lt;br /&gt;&lt;br /&gt;If you gave vi a whirl and don't see the beauty of it, give the &lt;a href="http://nano-editor.org/overview.php"&gt;nano editor&lt;/a&gt; a try. It also ships with Mac OS X.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note: a chunk of this small guide came from a web page I found long ago, but I don't remember where so I can't give proper credit. I've added and changed things from the original text.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Vi has two modes, command and insert (really, three if you count replace mode). Command mode is used to navigate, search, and issue other commands. Insert mode is used to enter text. &lt;/p&gt; &lt;p&gt; Vi starts in command mode. &lt;/p&gt; &lt;p&gt;You can precede most commands with a number indicating how many times to perform a command. For example, entering 99 followed by the down arrow will move the cursor down 99 lines. "99x" will delete 99 characters. &lt;/p&gt; &lt;b&gt;While in command mode (case sensitive)&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;move the cursor with arrow keys; if there aren't any arrow keys, use j,k,h,l&lt;/li&gt;&lt;li&gt;i - change to insert mode (before cursor)&lt;/li&gt;&lt;li&gt;a - change to insert mode (after cursor)&lt;/li&gt;&lt;li&gt;A - change to insert mode (at end of line)&lt;/li&gt;&lt;li&gt;r - replace one character&lt;/li&gt;&lt;li&gt;R - overwrite text&lt;/li&gt;&lt;li&gt;x - delete one character&lt;/li&gt;&lt;li&gt;dd - delete one line&lt;/li&gt;&lt;li&gt;yy - yank line (copy)&lt;/li&gt;&lt;li&gt;p - paste deleted or yanked text after cursor&lt;/li&gt;&lt;li&gt;P - paste deleted or yanked text before cursor&lt;/li&gt;&lt;li&gt;G - go to end of the file&lt;/li&gt;&lt;li&gt;1G - go to top of the file&lt;/li&gt;&lt;li&gt;J - merge next line with this one&lt;/li&gt;&lt;li&gt;/ - search, follow / with text to find&lt;/li&gt;&lt;li&gt;:wq - write file and quit&lt;/li&gt;&lt;li&gt;:q! - quit without saving&lt;/li&gt;&lt;li&gt;%s/old/new/g - substitute; replace "old" with "new" on all lines&lt;/li&gt;&lt;li&gt;:g/pattern/d - delete all lines that match the pattern&lt;/li&gt;&lt;/ul&gt;  &lt;b&gt;While in insert mode&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ESC - change to command mode&lt;/li&gt;&lt;li&gt;any text typed is entered at the cursor&lt;/li&gt;&lt;/ul&gt;  &lt;b&gt;Typical vi session&lt;/b&gt; &lt;ol&gt;&lt;li&gt;Type "vi file.txt" at command prompt&lt;/li&gt;&lt;li&gt;Move cursor to where new text will be added&lt;/li&gt;&lt;li&gt;Type "i" to change to insert mode&lt;/li&gt;&lt;li&gt;Type new text&lt;/li&gt;&lt;li&gt;Type ESC to go back to command mode&lt;/li&gt;&lt;li&gt;type ":wq" and ENTER to write the file and quit&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1357454981809249456?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1357454981809249456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1357454981809249456'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/vim.html' title='Vi[m]'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7705654125759845876</id><published>2008-12-11T10:02:00.000-08:00</published><updated>2008-12-11T10:04:25.234-08:00</updated><title type='text'>Sudo vs. Root: The Real Story</title><content type='html'>In Mac OS X, the root account is disabled by default. The first user account created is added to the admin group and that user can use the &lt;i&gt;sudo&lt;/i&gt; command to execute other commands as root. The conventional wisdom is that sudo is the most secure way to run root commands, but a closer look reveals a picture that is not so clear.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;note: originally published March 21, 2006 on my old site, linuxboxadmin.com&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;b&gt;What you get with sudo&lt;/b&gt;&lt;br /&gt;&lt;p&gt; What are you really gaining by using sudo in the default Mac OS X configuration? First, you gain some comfort that nobody can login as root, either locally or remotely via SSH or FTP and tamper with your machine. Second, you get a log entry in /var/log/system.log every time sudo is used showing you who used it and what command was executed. These appear good enough reasons to endure the slight inconvenience of using sudo. &lt;/p&gt; &lt;p&gt;However, the way sudo is configured out of the box, you only need to enter your own password for authentication. This means that if someone guesses your password or steals it (and has access to it locally or via SSH), they can take over your box just as if you had root enabled. &lt;/p&gt;  &lt;p&gt; Worse, if you execute &lt;i&gt;sudo -s&lt;/i&gt; to start a root shell, the only thing that shows up in your system.log is this:&lt;br /&gt;&lt;br /&gt;Mar 20 07:49:12 my-mac-mini sudo:   username : TTY=ttyp3 ; PWD=/Users/&lt;br /&gt;username ; USER=root ; COMMAND=/bin/bash&lt;br /&gt;&lt;br /&gt;Every other command after starting a root shell does NOT get logged at all. All you can tell from this is when someone started the root shell. Whatever happened after that is a mystery. The same problem exists if a command is executed that permits shell escapes like many text editors, telnet programs, etc. So, in fact, using sudo has gained us absolutely nothing over enabling and using root. &lt;/p&gt;  &lt;p&gt; These deficiencies can be mitigated, and we'll get to that later. &lt;/p&gt;  &lt;b&gt;Securing the root account&lt;/b&gt;&lt;br /&gt;&lt;p&gt;If you enable the root account, there are a couple of precautions you should take. First, give root a different password than your user account. &lt;/p&gt; &lt;p&gt; You can prevent root logins to SSH by changing this line in the sshd configuration file, /private/etc/sshd_config:&lt;br /&gt;&lt;br /&gt;#PermitRootLogin yes&lt;br /&gt;&lt;br /&gt;to this:&lt;br /&gt;&lt;br /&gt;PermitRootLogin no &lt;/p&gt;  &lt;p&gt;To go one step further, disable all password logins to SSH and allow only public key authentication. This is how I configure my Linux servers. There are many fine &lt;a href="http://sial.org/howto/openssh/publickey-auth/"&gt;resources on the web&lt;/a&gt; that describe the gory details of using SSH public key authentication. &lt;/p&gt; &lt;p&gt; FTP logins by root are disabled by default since the root account is listed in the /etc/ftpusers file. Users listed in that file are not allowed to login using FTP. &lt;/p&gt; &lt;p&gt; Finally, disable user access to sudo by commenting out the %admin line in /private/etc/sudoers:&lt;br /&gt;&lt;br /&gt;#%admin  ALL=(ALL) ALL&lt;br /&gt;&lt;/p&gt; &lt;p&gt;With two minor configuration changes, we have a system that is arguably more secure than the default system using sudo. Why? Because if someone guesses or steals your user password, they can't use sudo to take over the machine. They still have to guess the root password. Of course, if they have a local account, they may be able to use a privilege escalation vulnerability to gain root access, but that is an issue for Apple. &lt;/p&gt;  &lt;b&gt;Back to sudo&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Is there a way to make the sudo configuration more secure? There are many things that can be done to improve the default settings. Here are a couple. &lt;/p&gt; &lt;p&gt;The most obvious change is to require a different password than your user password to authenticate. This can be done while keeping root logins disabled with a little trickery. First, enable the root account, change the root password, then use Netinfo Manager to change the root shell to /usr/bin/false. Any attempt to login as root will immediately end. Then, you can force sudo to require the root password by adding this line to /private/etc/sudoers:&lt;br /&gt;&lt;br /&gt;Defaults:ALL rootpw&lt;br /&gt;&lt;/p&gt; &lt;p&gt; Another security enhancement is to set up restrictions by user, and listing specific commands that are allowed to be run using sudo. By limiting the commands that can be run, you can limit the damage that can be done by a user account. This means changing the line in /private/etc/sudoers that grants all commands to users in the admin group. Check the sudoers man page for the details. &lt;/p&gt; &lt;p&gt;With these changes in place, sudo becomes much more secure, and is probably safer than using root directly. You should still change the SSH configuration to deny root logins and use public key authentication. &lt;/p&gt;  &lt;b&gt;The real story&lt;/b&gt;&lt;br /&gt;&lt;p&gt;I've made arguments and suggestions for using the root account and for using sudo. But consideration should be given to the role of the computer and primary user(s) before making a decision on which may work best for you. &lt;/p&gt; &lt;p&gt;The main goal of sudo is to allow users limited access to root commands for the purpose of distributing the sysadmin load. On a single user box, you are only distributing the load to yourself. If you take a few precautions, enabling the root user is perfectly acceptable and can be more secure than the default configuration using sudo. On a multi-user box, sudo adds value and may be the best way to go. Given its limitations, the notion that sudo is always the best choice is dubious. The real story is it depends on the configuration. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7705654125759845876?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7705654125759845876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7705654125759845876'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/sudo-vs-root-real-story.html' title='Sudo vs. Root: The Real Story'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-4913779995800387518</id><published>2008-12-11T09:57:00.000-08:00</published><updated>2008-12-11T09:59:03.427-08:00</updated><title type='text'>Find suid/sgid files</title><content type='html'>There are special permission that files in Unix-like systems can have called "set user id" (suid) and "set group id" (sgid). When set, these permissions alter how the programs are run. When suid is set, the program runs as the user who owns the file. When sgid is set, it runs as the group that owns the file. While these permissions are very useful, they can also be dangerous. You especially want to limit the number of programs that run as user root since they can write to any part of the system. This tip shows how to use the &lt;i&gt;find&lt;/i&gt; program to locate all suid/sgid files. You need to run these commands as root in order to search the entire system.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all SUID root files:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -user root -perm -4000 -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all SGID root files:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -group root -perm -2000 -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all SUID and SGID files owned by anyone:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -perm -4000 -o -perm -2000 -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all files that are not owned by any user:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -nouser -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all files that are not owned by any group:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -nogroup -print&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Find all symlinks and what they point to:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;find / -type l -ls&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-4913779995800387518?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4913779995800387518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/4913779995800387518'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/find-suidsgid-files.html' title='Find suid/sgid files'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-2741778921446527985</id><published>2008-12-11T09:55:00.000-08:00</published><updated>2008-12-11T09:56:08.712-08:00</updated><title type='text'>File Timestamps</title><content type='html'>Each file has three timestamps associated with it (stored as the number of seconds since the Epoch, Jan 1, 1970). The three timestamps are: &lt;ul&gt;&lt;li&gt;Access time (atime) - the last time the file was read&lt;/li&gt;&lt;li&gt;Modify time (mtime) - the last time the file contents were changed&lt;/li&gt;&lt;li&gt;Change time (ctime) - the last time the file permissions were changed&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;br /&gt;&lt;p&gt; In a long directory listing, the timestamp shown is the Modify time (mtime). To see all timestamps and a lot of other useful information, use the &lt;i&gt;stat&lt;/i&gt; program with the verbose option (-x):&lt;br /&gt;&lt;br /&gt;  &lt;i&gt;stat -x filename&lt;/i&gt; &lt;/p&gt;  Here is sample output from &lt;i&gt;stat&lt;/i&gt;:&lt;br /&gt;&lt;br /&gt;keithw$ stat -x "Mona Lisa Overdrive.mp3"&lt;br /&gt;  File: "Mona Lisa Overdrive.mp3"&lt;br /&gt;  Size: 6853358      FileType: Regular File&lt;br /&gt;  Mode: (0644/-rw-r--r--)         Uid: (  501/  keithw)  Gid: (  501/  keithw)&lt;br /&gt;Device: 14,9   Inode: 10208    Links: 1&lt;br /&gt;Access: Fri May 25 11:46:30 2007&lt;br /&gt;Modify: Fri Dec  8 16:38:54 2006&lt;br /&gt;Change: Fri Dec  8 16:38:54 2006&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-2741778921446527985?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2741778921446527985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/2741778921446527985'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/file-timestamps.html' title='File Timestamps'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8970471739981746646</id><published>2008-12-11T09:54:00.001-08:00</published><updated>2008-12-11T09:54:41.744-08:00</updated><title type='text'>BASH Basics</title><content type='html'>Following are some basics on how BASH gets initialized and core programming constructs.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;BASH initialization&lt;/b&gt; &lt;p&gt;When you first login, bash reads these initialization files in order (if they exist):&lt;/p&gt; &lt;p&gt;/etc/profile -- systemwide profile applies to all users&lt;/p&gt; &lt;p&gt; Then, it looks for these files and executes the FIRST one it  finds (note that the file names start with a period):&lt;br /&gt;$HOME/.bash_profile&lt;br /&gt;$HOME/.bash_login&lt;br /&gt;$HOME/.profile&lt;br /&gt;&lt;/p&gt; &lt;p&gt;For interactive non-login shells, it executes:&lt;br /&gt;$HOME/.bashrc &lt;/p&gt; &lt;p&gt;At logout, it executes:&lt;br /&gt;$HOME/.bash_logout &lt;/p&gt;  &lt;b&gt;Built-in shell variables:&lt;/b&gt; &lt;p&gt; These can be referenced interactively, but usually they are used in a shell script. A shell script is a plain text file that contains BASH commands executed in the order they appear. It is a program executed by BASH.&lt;br /&gt;&lt;/p&gt;&lt;table width="300"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td valign="top" align="left"&gt;$#&lt;/td&gt;     &lt;td&gt;number of command line arguments&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$?&lt;/td&gt;     &lt;td&gt;exit value of last command&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$$&lt;/td&gt;     &lt;td&gt;process ID of current process&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$!&lt;/td&gt;     &lt;td&gt;process ID of last background process&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$0&lt;/td&gt;     &lt;td&gt;command name of the current process&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$n&lt;/td&gt;     &lt;td&gt;(n=1-9) the 1st thru 9th command line arguments&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$*&lt;/td&gt;     &lt;td&gt;all command line arguments&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td valign="top" align="left"&gt;$@&lt;/td&gt;     &lt;td&gt;all command line arguments, individually quoted ($1 $2 ...)&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;br /&gt;&lt;b&gt;If statement&lt;/b&gt; &lt;p&gt; if condition ; then&lt;br /&gt;  commands&lt;br /&gt;elif condition ; then&lt;br /&gt;  commands&lt;br /&gt;else&lt;br /&gt;  commands&lt;br /&gt;fi &lt;/p&gt;  &lt;b&gt;Test the return status of the previous command:&lt;/b&gt; &lt;p&gt; if [ $? == 0 ] ; then&lt;br /&gt;  commands&lt;br /&gt;fi &lt;/p&gt;  &lt;b&gt;Loops&lt;/b&gt; &lt;p&gt; while condition; do&lt;br /&gt;  commands&lt;br /&gt;done &lt;/p&gt; &lt;p&gt; for var in list; do&lt;br /&gt;  commands&lt;br /&gt;done &lt;/p&gt; &lt;p&gt; for (( expr1; expr2; expr3 )); do&lt;br /&gt;  commands&lt;br /&gt;done &lt;/p&gt;  &lt;b&gt;Case statements&lt;/b&gt; &lt;p&gt;The case statement can be used in place of a complex if statement.&lt;br /&gt;&lt;br /&gt;case expression in&lt;br /&gt;pattern)&lt;br /&gt;  commands&lt;br /&gt;   ;;&lt;br /&gt;pattern)&lt;br /&gt;  commands&lt;br /&gt;   ;;&lt;br /&gt;*&lt;br /&gt;  commands&lt;br /&gt;esac &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8970471739981746646?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8970471739981746646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8970471739981746646'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/bash-basics.html' title='BASH Basics'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-7766616080686286206</id><published>2008-12-11T09:50:00.000-08:00</published><updated>2008-12-11T09:51:52.080-08:00</updated><title type='text'>Deleting files with bad names</title><content type='html'>If a file with a bad name gets accidentally created, such as a name that begins with a hyphen "-", it can't be deleted with a normal remove command (rm). Use the "--" option to tell rm that no more options follow, then it can delete the file.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;To delete a file whose file name begins with "-":&lt;/b&gt; &lt;p&gt; &lt;i&gt;rm -- -bad-file-name&lt;/i&gt;&lt;br /&gt;Or&lt;br /&gt;&lt;i&gt;rm ./-bad-file-name&lt;/i&gt; &lt;/p&gt; &lt;b&gt;To delete a file with non-printable characters in the name:&lt;/b&gt; &lt;p&gt; Use shell wildcards, "?" for one character and "*" for zero or more characters. For example, if the file name "bad file name" can't be deleted, one of the spaces may in fact contain a hexademical value. Try:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;rm bad?file?name&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;caution:&lt;/i&gt; use &lt;i&gt;ls bad?file?name&lt;/i&gt; first to make sure you are not matching more files than you think with wildcards before deleting them. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-7766616080686286206?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7766616080686286206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/7766616080686286206'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/deleting-files-with-bad-names.html' title='Deleting files with bad names'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-1235740751921427227</id><published>2008-12-11T09:43:00.000-08:00</published><updated>2008-12-11T10:05:30.507-08:00</updated><title type='text'>Mac/Linux/Windows file name friction</title><content type='html'>In 1993, Microsoft added long file name support to Windows NT 3.1, allowing more descriptive names than the limited 8.3 DOS format. Mac users scoffed, having had long file names for nearly a decade, and because Windows still stored a DOS file name in the background. Linux was born with long file name a couple of years before it showed up in Windows. Today, long file names are well supported by all three operating systems though key differences remain.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Linux is the most sensitive&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;One of first culture shocks for people moving from Windows to Linux is the case sensitivity of file names. These files: "filename", "Filename", and "FileName" are the same file in Windows but three unique files in Linux.&lt;br /&gt;&lt;br /&gt;The Mac OS X HFS+ and Windows NTFS file systems are case preserving, but not case sensitive. This means they will store and keep track of the case in a file name, but will ignore case when comparing file names. So, you can't have "filename" and "Filename" in the same directory. (note: an &lt;a href="http://developer.apple.com/technotes/tn/tn1150.html#HFSX"&gt;optional file system called HFSX&lt;/a&gt;, available in OS X 10.3+, is case sensitive.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Linux and OS X files have more character(s)&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Linux file names can be up to 255 characters long and can be made up of any characters except forward slash (/) and NUL. Using special characters like those recognized by the shell takes extra effort. You can trick the shell by either enclosing the name in single quotes ('icky?filename') or escaping it with a backslash (icky?filename). You can also use non-printable characters in a file name, but I can't think of a good reason to do so. To avoid confusion, most people stick to alphanumerics, periods, spaces, underscores, and hyphens.&lt;br /&gt;&lt;br /&gt;OS X supports up to 255 characters and can use the same characters as Linux, except for a colon (:). However, the Finder may have trouble with bizarre file names that can be created in the shell.&lt;br /&gt;&lt;br /&gt;Windows file names can be up to 255 characters, but that includes the full path. A lot characters are wasted if the default storage location is used: "C:\Documents and Settings\USER\My Documents". Windows does not allow names to contain any of these characters: &lt;pre&gt;* |  / :  ?&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;table width="300" border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" align="center"&gt;&lt;b&gt;Avoid using these characaters&lt;br /&gt;  for maximum portability&lt;/b&gt;     &lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Asterisk&lt;/td&gt;     &lt;td align="left"&gt;*&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Colon&lt;/td&gt;     &lt;td align="left"&gt;:&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Back slash&lt;br /&gt;&lt;/td&gt;     &lt;td align="left"&gt;\&lt;br /&gt;&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Forward slash&lt;/td&gt;     &lt;td align="left"&gt;/&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Less Than&lt;/td&gt;     &lt;td align="left"&gt;&lt;&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Greater Than&lt;/td&gt;     &lt;td align="left"&gt;&gt;&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Pipe&lt;/td&gt;     &lt;td align="left"&gt;|&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Quote&lt;/td&gt;     &lt;td align="left"&gt;"&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td align="center"&gt;Question mark&lt;/td&gt;     &lt;td align="left"&gt;?&lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td colspan="2" align="center"&gt;all non-printable characters&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Portability&lt;/b&gt; &lt;/p&gt;&lt;p&gt;Even though you can use odd characters in a Linux or OS X file name, it's not a great idea. Using sensible names allows a smooth exchange of files with other operating systems where an odd character may be invalid. For maximum portability, avoid using characters that are illegal in any of the operating systems. &lt;/p&gt; &lt;b&gt;The lowercase-hyphen rule&lt;/b&gt; &lt;p&gt;My preference is to always use lowercase letters and hyphens to replace spaces. For example, "this-is-a-long-filename.txt", instead of "This is a long filename.txt". &lt;/p&gt; &lt;p&gt;I'm not sure where or when I picked up the lowercase habit but it has been with me for some time. Since I spend a lot of quality time with web files, it relieves me of thinking about the case of file names. I like hyphens over underscores because underscores don't always show up clearly in anchor tag hyperlinks. Another web bias. Even though it is not required in Linux or OS X, I add a file type extension (three or four characters) mostly for my own benefit. I use the same naming convention regardless of operating system. &lt;/p&gt; &lt;p&gt;There are two exceptions I make to the lowercase-hyphen rule. The first is audio files, since ripping software tends to default file names to the track title with mixed case and spaces. The other exception is when I exchange documents with someone who has already named a file. The tab completion feature of BASH takes the edge off working with whatever is thrown at me. &lt;/p&gt; &lt;b&gt;Taming file names&lt;/b&gt; &lt;p&gt;Modern operating systems provide a lot of flexibility in naming files. I probably expend too many brain cycles thinking about file names, but I suspect most people have a preference.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-1235740751921427227?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1235740751921427227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/1235740751921427227'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/maclinuxwindows-file-name-friction.html' title='Mac/Linux/Windows file name friction'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-2971257711362934224.post-8604763525424773045</id><published>2008-12-11T08:57:00.000-08:00</published><updated>2008-12-11T08:58:13.277-08:00</updated><title type='text'>Boot key sequences</title><content type='html'>Following are some of the most commonly used boot key sequences for recent Macs (with Open Firmware or Extended Firmware Interface).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;c = boot from CD&lt;/li&gt;&lt;li&gt;n = attempt to boot from network server (using BOOTP or TFTP)&lt;/li&gt;&lt;li&gt;t = boot into FireWire Target Disk mode&lt;/li&gt;&lt;li&gt;shift = safe mode, disable login items and non-essential kernel extensions (OS X, 10.1.3 and later)&lt;/li&gt;&lt;li&gt;hold down mouse = eject CD/DVD from drive&lt;/li&gt;&lt;li&gt;cmd-v = verbose mode, show console messages during boot&lt;/li&gt;&lt;li&gt;cmd-s = boot into single user mode&lt;/li&gt;&lt;li&gt;cmd-opt-shift-delete = boot from external disk drive (or CD)&lt;/li&gt;&lt;li&gt;opt = show Open Firmware system picker (PowerPC only)&lt;/li&gt;&lt;li&gt;cmd-opt-o-f = boot into Open Firmware (PowerPC only)&lt;/li&gt;&lt;li&gt;cmd-opt-p-r = reset parameter RAM (PRAM)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2971257711362934224-8604763525424773045?l=commandlinemac.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8604763525424773045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2971257711362934224/posts/default/8604763525424773045'/><link rel='alternate' type='text/html' href='http://commandlinemac.blogspot.com/2008/12/boot-key-sequences.html' title='Boot key sequences'/><author><name>tekewin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
