Get a Twitter Account’s Registration Date via Snow Leopard Service

Creating services in Snow Leopard is all the rage lately. So is Twitter. This tutorial brings both of them together and should serve as a fine example of just how slick and useful services in Snow Leopard can be. Read the rest of this entry »

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”.)

#!/bin/bash

workpath=/opt/auth_files/
outfile=/root/auth_find-$1

# friendly usage funtion, called if no argument is supplied
usage ()
{
    echo ""
    echo "Usage: auth_find [username] [new-username]"
    echo ""
    echo "This script recursively searches subversion's /opt/auth_files/ directory for"
    echo "the supplied username and returns a list of files that contain it. If a second"
    echo "username is supplied all instances of the first will be replaced with the second."
    echo ""
    echo "Output is sent to both STDOUT and /root/auth_find-username."
    echo ""
    exit 1
}

if [ $# == 1 ]; then    # do this block if one argument is given
    echo "Results:"
    for afile in $(tree -ifF --noreport $workpath | grep -v '/$'); do
        if [ -n "$(grep "^$1 " $afile)" ]; then
            echo "$afile" | tee -a $outfile
        fi
    done
else
    if [ $# == 2 ]; then    # do this block if two arguments are given
        echo "Now replacing occurrences of '$1' with '$2' in the following files:"
        for afile in $(tree -ifF --noreport $workpath | grep -v '/$'); do
            if [ -n "$(grep "^$1 " $afile)" ]; then
                echo "$afile" | tee -a $outfile-CHANGED
                perl -p -i -e "s|$1|$2|g" $afile
            fi
        done
    else    # show usage if incorrect number of arguments given
        usage
    fi
fi
#!/bin/bash
outfile=/root/auth_find-$1

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.

#!/bin/bash

# grab first argument as pdf filename and generate ps filename
thePDF=$1
thePS=$(echo $thePDF.ps)
queueName=$2

usage()
{
    echo ""
    echo "Usage: psprint [your pdf] [lpr queue]*"
    echo ""
    echo "This command does three things:"
    echo "  1. Converts the specified pdf file to ps"
    echo "  2. Prints the ps file to your default lpr queue *(unless you specify another queue)"
    echo "  3. Deletes the ps file"
    echo ""
    exit 1
}

if [ $# == 0 ]; then usage; fi
if [ $# == 1 ]; then
    echo "Converting $thePDF ..."
    pdf2ps "$thePDF" "$thePS"
    echo "Sending to default printer ..."
    lpr "$thePS"
    echo "Cleaning up ..."
    rm "$thePS"
    exit 1
fi
if [ $# == 2 ]; then
    echo "Converting $thePDF ..."
    pdf2ps "$thePDF" "$thePS"
    echo "Sending to $2 ..."
    lpr -P "$queueName" "$thePS"
    echo "Cleaning up ..."
    rm "$thePS"
    exit 1
fi
if [ $# > 2 ]; then usage; fi

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.

    #!/bin/bash

    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
        else
            /bin/echo $(/usr/bin/arch)-32
        fi
    else
        /bin/echo $(/usr/bin/arch)
    fi

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.

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.

Read the rest of this entry »

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:

#!/bin/bash

usage ()
{
    /bin/echo "Usage: shotshadows [off|on]"
    exit 1
}

if [ $# == 1 ]; then
    if [ $1 == "off" ]; then
	    /bin/echo "Disabling drop shadows in screenshots and restarting SystemUIServer"
	    /usr/bin/defaults write com.apple.screencapture disable-shadow -bool true
	    /usr/bin/killall SystemUIServer
    elif [ $1 == "on" ]; then
        /bin/echo "Enabling drop shadows in screenshots and restarting SystemUIServer"
        /usr/bin/defaults delete com.apple.screencapture disable-shadow
        /usr/bin/killall SystemUIServer
    else
        usage
    fi
else
	usage
fi

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.