PSU MacAdmins 2014 talk (updated)

I attended the 2014 Penn State University Mac Admins Conference this year as a speaker and gave a talk today titled Shell Building Blocks. Here’s a link to my talk’s companion github repo, as well as the slides in PDF and original Keynote format.


Slides: PDF | Keynote

Video: YouTube



Introducing: Assetter, a simple little asset app

Last week, MacEnterprise mailing list subscriber Eric Thomas Gadsby posted the following question:

Dear Friends,

Where I work the PC’s we use have a little visual basic app the give abbreviated system information along with the asset tag number (not the serial but something generated my the inventory people) when opened. Has anybody written or found such an app for Mac OS X? Ideas? Thanks!

I knew I could quickly create such an app for him using AppleScript Objective C (ASOC), so after a few back-and-forth emails to the list, I had all the information I needed and got right to work on it. After a handful of hours spread over two days, I had the app ready and shared it with the list. I present it to you here:

assetter-iconAssetter, version 1.2 build 2

Here’s a quick run-down of its features:

  • On first launch, Assetter prompts you for the computer’s asset tag if it has not yet been set.
  • The asset tag is stored in the computer’s NVRAM so the information is not lost when the disk is replaced or re-imaged.
  • Assetter displays the following information:
    • hostname
    • model
    • serial number
    • asset tag
    • memory
    • size and number of drives
    • ip address and hardware address of network interfaces
  • The data displayed can be exported to a text file on the desktop with the push of a button.


Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
Please contact your system administrator.
Add correct host key in /home/username/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/username/.ssh/known_hosts:42
RSA host key for has changed and you have requested strict checking.
Host key verification failed.

If you use ssh — if you’re reading this blog, you likely count yourself as a member of that group — you’ve seen this warning. If you bring up and take down vms regularly, or replace servers regularly, or use dhcp on your network with short lease times, you might see this warning more than others. Regardless of how or when you’ve seen the warning, you probably find it annoying. “No, computer, I’m not being hacked. A different host has this IP now. Just let me in already, ok?” At this point, you open the known_hosts file in your editor of choice, find the offending line, delete the line, save the file, and try your ssh command again. Tedious, right?

We can all agree that simply turning off this warning is not the best idea, so how can we deal with it efficiently? (HINT: check this posts categories.) That’s right, we script it. We don’t need any more than a simple one-liner, and the best place to keep your one-liner scripts is in your .bashrc file (or the shell of your choice’s rc file).

Do you see how the error kindly tells you which line of the known_hosts file is the offender? This makes our job extremely easy. Both sed and perl can easily delete a given line from a file. (NOTE: Mac users will need to use perl, since BSD version of sed does not include the functionality shown here.) Both of the following commands will delete line 42 from the file.

sed -i '42 d' ~/.ssh/known_hosts
perl -i -ne 'print unless 42 .. 42" ~/.ssh/known_hosts

These are nice, but we need to wrap the command in a function that takes the line number as an argument. Let’s call the function rmhost.

rmhost () { sed -i "$1 d" ~/.ssh/known_hosts; }
rmhost () { perl -i -ne "print unless $1 .. $1" ~/.ssh/known_hosts; } # for Macs

And there we have it. Put your command in your .bashrc, source it (i.e. load the changes by running ‘source ~/.bashrc’), and the next time you see the above warning (and you know the reason you’re getting it), just type rmhost [line #] and you’re good to go.

Recursively Find/Replace Inside Files Within a Directory

We recently had to change a handful of usernames in LDAP due to a merging of resources. This was a relatively painless process, but since some services use static authorization files to grant access, some manual post-processing was necessary. The script at the end of this post is something I came up with to deal with updating the subversion auth_files. It’s a bash script that uses a couple useful tricks:

tree -ifF --noreport /path/to/dir/ | grep -v '/$'
  • The tree command normally prints out an ascii-graphical representation of the file structure rooted in the given path, recursively. The ‘-i’ option tells it not to display the graphics. The ‘-f’ option prints out the full path to each item. The ‘-F’ adds file-type indicators to the end of file names, which I’m using here so I can filter out directories from the list using an inverse grep.
  • The output of the tree command is piped to grep. The ‘-v’ option activates inverse grep, and the ‘/$’ regex will match trailing slashes. This grep will match all lines not ending in ‘/’.
  • The tree command is not standard on all flavors/versions of *nix. It’s missing on OS X, for example.
perl -p -i -e 's|before|after|[ig]' file
  • This perl command will edit a file in-place, replacing occurrences of “before” with “after”.
  • Adding an i to the end of the substitution string makes it a case insensitive substitution.
  • Adding a g makes the command replace all instances, a.k.a. global, instead of just the first instance.

Why perl instead of sed for in-place edits?

Not all versions of sed allow in-place edits, especially older ones, so perl is the more universal option. If you know your sed can do in-place edits (check the man page for the ‘-i’ option), then you can replace the perl line in the script below with this:

sed -i'' -e "s|$1|$2|g" $afile

Whether you choose to use perl or sed, you must remember to double-quote the substitution string so bash expands the variables and hands the values off to sed/perl. Using single quotes here would result in sed/perl looking for a literal ‘$1’ to replace with a literal ‘$2’.

The Script

This code can easily be repurposed for other tasks, but I present it here as I wrote it for the subversion auth_files purpose. (I named it “auth_find”.)


UPDATE (8/31/09): Added “why perl instead of sed” section in response to comment.

Print PDFs as Postscript to an lpr Queue

I wrote a simple script recently for a user who was having trouble getting certain PDFs to print properly from his linux box (Fedora 10). I first suggested that he try converting the pdfs to ps and printing the resulting file. That worked but he found the process a bit tedious. Here’s the script I wrote to take care of the tediousness. It relies on the standard (in Fedora, at least) pdf2ps package. It should be pretty self-explanatory.

Save the script to a location in your path (/usr/local/bin works) and you’re off.

Test for 64-bit Capability

UPDATE (10/8/08): The following one-liner will work on ppc or intel boxes and will return 1 if the computer is 64-bit capable or 0 if it is not. UPDATE 2 (12/11/08):  Reader Ted suggested suppressing stderr for cleaner output. I amended the code below to include his suggestion.

sysctl hw.optional 2> /dev/null | awk -F': ' '/64/ {print $2}'

The arch tool is an easy way to test whether a Mac’s processor is intel or ppc, but it does not draw a distinction between the different types of intel processors. It will return i386 whether it’s a Core Duo, Core 2 Duo, or Xeon. We can use the fact that the Core Duo is only intel processor found in Macs incapable of running 64-bit code to write a script that extend arch to test for 64-bit capability.


    proc=$(/usr/sbin/system_profiler SPHardwareDataType | \
    /usr/bin/awk -F': ' '/Processor Name:/ {print $2}')

    if [ "$(/usr/bin/arch)" == "i386" ]; then
        if [ "$proc" != "Intel Core Duo" ]; then
            /bin/echo $(/usr/bin/arch)-64
            /bin/echo $(/usr/bin/arch)-32
        /bin/echo $(/usr/bin/arch)

This script will return i386-32 for intel processors limited to 32 bits, i386-64 for 64-bit capable intel processors, and ppc for non-intel processors.

I’ve called this script archbits and made it downloadable here.

networksetup – Change Network Settings from the Command Line

UPDATE (8/12/08): I simplified the awk portion of the command.

Mac OS X comes with a very convenient tool called networksetup that makes it relatively easy to view or change network settings from the command line. In Leopard, the command is readily available at /usr/sbin/networksetup. Since /usr/sbin exists in the default path, you can access the command directly. In Tiger, Panther, and Jaguar, the command is not anywhere in the default path, but lives buried within the bundled ARD Agent at /System/Library/CoreServices/RemoteManagement/ (If you’re not using Leopard, be sure to include the full path to the executable in all of your commands.) Apple’s man page for networksetup covers all the available options but it’s short on real examples of its use.

Continue reading

Easily Change Your Server’s Default NetBoot Image from the Command Line

I have five different NetInstall/NetRestore images living on an Xserve that I use for deployment purposes. I find myself using Server Admin pretty often to change the default NetBoot image so I can boot computers to that image while holding down option-N. I was starting to find it pretty tedious to do this via the GUI. After launching the application, it takes seven clicks to change a default image in Server Admin (Tiger and Leopard). The times that I wasn’t at my computer and wanted to change the default image were starting to pile up, too.

So, what does any intrepid admin do at a time like this? That’s right. We take it to the command line and find a way to script it. My goal now was to create a script that I could run (from any computer) after ssh’ing into the server.

Continue reading

shotshadows – Quick Script to Enable or Disable Screenshot Shadows

If you’ve taken screenshots of windows in Tiger and Leopard using the command-shift-4+space trick, you’ll have noticed that Leopard will include the window’s (rather large) drop shadows in the resulting image. Depending on your point of view this can be good, bad, or a mixed blessing. I’m in the latter camp. They can be nice for blog posts, but if you’re creating documentation, for example, they can take up precious space on the page.

Using this hint as a starting point, I wrote the following bash script to make the process of disabling and enabling those shadows quick and painless:

Save this script as shotshadows — or download it here — make it executable, and drop it somewhere in your path. (I use /usr/local/bin.) Now you can turn screenshot shadows on and off with the simple terminal commands shotshadows on and shotshadows off. The change takes effect instantly.