<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>T’N’T Luoma &#187; Shell Scripts</title>
	<atom:link href="http://tntluoma.com/category/shell-scripts/feed/" rel="self" type="application/rss+xml" />
	<link>http://tntluoma.com</link>
	<description>Stuff I've Written Down</description>
	<lastBuildDate>Sun, 23 Aug 2009 06:12:49 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SuperDuper Bash Script to Automatically Mount or Unmount a Hard Drive</title>
		<link>http://tntluoma.com/shell-scripts/superduper-script-automatic-mount-unmount/</link>
		<comments>http://tntluoma.com/shell-scripts/superduper-script-automatic-mount-unmount/#comments</comments>
		<pubDate>Fri, 06 Mar 2009 17:20:41 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tntluoma.com/?p=1307</guid>
		<description><![CDATA[SuperDuper! is a superb backup program for the Mac.

It does one (major) thing: It duplicates your hard drive to another hard drive.

mount-or-unmount-for-superduper.sh is a shell script which automates the process of mounting and un-mounting a hard drive to use with SuperDuper.

&#8220;What? Why? I don&#8217;t get it.&#8221;

Imagine this: you have a desktop Mac (or a laptop [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html">SuperDuper!</a> is a superb backup program for the Mac.</p>

<p>It does one (major) thing: It duplicates your hard drive to another hard drive.</p>

<p><a href="http://tntluoma.com/files/mount-or-unmount-for-superduper.sh">mount-or-unmount-for-superduper.sh</a> is a shell script which automates the process of mounting and un-mounting a hard drive to use with SuperDuper.</p>

<h1>&#8220;What? Why? I don&#8217;t get it.&#8221;</h1>

<p><span id="more-1307"></span>Imagine this: you have a desktop Mac (or a laptop Mac that you keep the external drive plugged into all the time, I suppose).</p>

<p>You want to automate your backups because you know that you won&#8217;t really run them if they aren&#8217;t automated, because you&#8217;re lazy.</p>

<p>Nothing personal, everyone is lazy when it comes to backups. That&#8217;s why almost no one has them, even if they know they should.</p>

<p>SuperDuper is super easy (I promise I&#8217;ll stop with the super super bit) and works great, and even has a scheduler so you can set it to backup your machine at 3 a.m. or whenever you won&#8217;t be using it.</p>

<p>The only problem is that the drive has to be mounted (obviously) to do that, and having it mounted all the time can be annoying:</p>

<ol>
<li><p>Spotlight finds 2x the number of actual results: once for your main hard drive, once for your backup. [This is enough of an annoyance that there really needs to be no #2, but…]</p></li>
<li><p>Having the drive mounted means that it will spin up and down all day long as it goes to &#8216;sleep&#8217; and then thinks that it may be needed.  If you&#8217;re only using it for SuperDuper, why not only have it spin up once per day?</p></li>
<li><p>Installers will often check to see if maybe you want to install on a different hard drive than the main one. Having unmounted the drive means that you don&#8217;t have to worry about the Installer checking it.</p></li>
<li><p>Imagine something horribly unexpected happens and you delete a bunch of files by accident. Do you want that list of &#8220;Files I May Have Accidentally Deleted&#8221; to include your backups? If not, having the backup drive unmounted prevents accidental deletions too.</p></li>
</ol>

<h1>How does it work?</h1>

<p>The script is very simple. All you have to do is edit <strong><em>one</em></strong> line.</p>

<pre><code># Where Finder shows the drive when it is mounted
DRIVE_NAME_SHORT="iMac_Backup"
</code></pre>

<p>(Note that this must not include the /Volumes/ part of the path, but JUST the part which appears when the drive appears on the desktop or in Finder.)</p>

<p>I would encourage you <strong><em>not</em></strong> to get &#8216;creative&#8217; with the name: Use letters only, no spaces or other punctuation except _ or - if you must</p>

<h1>Names are important</h1>

<p>Make sure to save the file with a name that begins with either &#8216;mount-&#8217; or &#8216;unmount-&#8216;</p>

<p>I recommend this that you:</p>

<ol>
<li><p>Download <a href="http://tntluoma.com/files/mount-or-unmount-for-superduper.sh">mount-or-unmount-for-superduper.sh</a></p></li>
<li><p>Save it to ~/bin/ or somewhere else in your $PATH.</p></li>
<li><p>Rename it:</p>

<p>mv mount-or-unmount-for-superduper.sh mount-drive-for-superduper.sh</p></li>
<li><p>Link it (so that any changes in one will be reflected in the other)</p>

<p>ln mount-drive-for-superduper.sh unmount-drive-for-superduper.sh</p></li>
<li><p>Launch SuperDuper, click the &#8216;Options&#8217; button and then the &#8216;Advanced&#8217;</p></li>
</ol>

<ul>
<li><p>Add the &#8216;mount-drive-for-superduper.sh&#8217; to &#8216;Before Copy: Run shell script before copy starts&#8217;</p></li>
<li><p>Add the &#8216;unmount-drive-for-superduper.sh&#8217; to &#8216;After Copy: Run shell script after copy completes&#8217;</p></li>
</ul>

<p>You ought to have a window that looks something like this:</p>

<div style="text-align:center;"><img src="http://tntluoma.com/files/superduperscriptswindow.png" alt="SuperDuperScriptsWindow.png" border="0" width="618" height="637" /></div>

<p>Click &#8216;OK&#8217; and it should look like this:</p>

<div style="text-align:center;"><img src="http://tntluoma.com/files/superduper-confirmation-window.png" alt="SuperDuper Confirmation Window.png" border="0" width="618" height="494" /></div>

<p>And then click &#8216;Schedule&#8217; to tell SuperDuper when to run.</p>

<h1>Feedback?</h1>

<p>I welcome feedback on the script, especially if anything is unclear or you can see an easier way to do something.</p>

<p>Please leave a valid email address in comments. No one else but me will ever see it.</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/superduper-script-automatic-mount-unmount/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>~/Dropbox/bin/</title>
		<link>http://tntluoma.com/shell-scripts/dropbox-bin/</link>
		<comments>http://tntluoma.com/shell-scripts/dropbox-bin/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 04:34:28 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>
		<category><![CDATA[dropbox]]></category>
		<category><![CDATA[geeky]]></category>
		<category><![CDATA[zsh]]></category>

		<guid isPermaLink="false">http://tntluoma.com/?p=1005</guid>
		<description><![CDATA[Summary: I geek out by putting all my shell scripts in ~/Dropbox/bin/ and a few other tweaks and tricks.


Like most computer-savvy folks I know, I ♥ Dropbox.

If you don&#8217;t know what Dropbox is, here&#8217;s a simple summary:


It&#8217;s a folder on your local computer which is also sync&#8217;d with Amazon.com&#8217;s super cool S3 service
You can sync [...]]]></description>
			<content:encoded><![CDATA[<p>Summary: I geek out by putting all my shell scripts in ~/Dropbox/bin/ and a few other tweaks and tricks.</p>

<p><span id="more-1005"></span>
Like most computer-savvy folks I know, I ♥ <a href="http://getdropbox.com/">Dropbox</a>.</p>

<p>If you don&#8217;t know what Dropbox is, here&#8217;s a simple summary:</p>

<ul>
<li>It&#8217;s a folder on your local computer which is also sync&#8217;d with Amazon.com&#8217;s super cool S3 service</li>
<li>You can sync that folder with all your computers, so all your files are on all your computers</li>
<li>It&#8217;s free (up to 2GB, which is plenty for documents)</li>
<li>It works for Mac, Windows, and Linux</li>
<li>You can access your files via a web browser (ever been away from home without your computer and wished you could get a file off your computer? Now you can, if the file is on your Dropbox.</li>
</ul>

<p>The same files, everywhere.</p>

<p>If you have more than one computer, you realize how this can be valuable.</p>

<p>Also, it works in the background, flawlessly (for me, thus far) and you never know that anything is happening.</p>

<h2>&#8220;Ok, I knew all that, what&#8217;s new?&#8221;</h2>

<p>Like most geeks I know, I&#8217;ve got a small collection of shell scripts that I&#8217;ve written over the years.</p>

<p>I would like those scripts to be accessible on all my computers as well.</p>

<p>I also have a bunch of shell customizations in my .zshenv file which I would also like sync&#8217;d on all my computers.</p>

<p>As I was getting ready to write some complicated syncing script to do that, it occurred to me: &#8220;Why don&#8217;t I just use Dropbox?&#8221;</p>

<p>Scripts are small and self-contained, and I can put them in <em>any</em> folder as long as I add that folder to my $PATH.</p>

<p>So I changed this:</p>

<pre><code>PATH=$HOME/bin:/usr/local/bin:/usr/local/sbin:/opt/local/bin:
</code></pre>

<p>to this</p>

<pre><code>PATH=$HOME/Dropbox/bin:/usr/local/bin:/usr/local/sbin:/opt/loc
</code></pre>

<p>then I simply moved my ~/bin/ folder to ~/Dropbox/</p>

<p>Then I renamed ~/.zshenv to ~/Dropbox/zshenv.txt (so it would be visible and have a known file extension to open in a text editor) and finally I did this</p>

<pre><code>cd ~ &amp;&amp; ln -s Dropbox/zshenv.txt .zshenv
</code></pre>

<p>so now I have the same <a href="http://www.zsh.org/">Zsh</a> setup everywhere.</p>

<p>Wow! That was easy.</p>

<h2>Not So Fast</h2>

<p>I should have known this because <a href="http://forums.getdropbox.com/topic.php?id=1748">I raised the issue on the Dropbox forums</a> about 4 months ago.</p>

<blockquote>
  <p>I am developing a shell script. Since I want to use the same version on all my Macs, I have saved it in ~/Dropbox/ and issued chmod 755.  However, the &#8216;execute&#8217; bit keeps getting dropped off when it syncs.</p>
</blockquote>

<p>to which I was told:</p>

<blockquote>
  <p>Dropbox doesn&#8217;t actually track most extended attributes for any operating system, the file comes down as a standard read/writeable file. The problem here is that the &#8220;file system&#8221; on the cloud isn&#8217;t ntfs, or ext3, or zfs, or hfs +, so there is no analogous part to the execute bit. or file permissions or any of that extra stuff, but all your bits are there. But OS X supports ACLs that you can set on a directory so that all files created there inherit the same permissions, so drop your script into a folder, and set an ACL for it.</p>
</blockquote>

<p>Now I&#8217;ve <em>heard</em> of <a href="http://en.wikipedia.org/wiki/Access_control_list">ACLs</a>, but since I&#8217;m the only user on my computer, I&#8217;ve never actually <em>used them</em> before.</p>

<p>Like most geeks I know, I only really learn about something when I have some practical <em>reason</em> to know it.  When people ask me how I know so much about computers, I always tell them &#8220;practice&#8221; and it&#8217;s true.</p>

<p>I don&#8217;t sit around <em>reading</em> about something, and if there&#8217;s something I just have a casual interest in learning (&#42;cough&#42;perl, emacs, vi&#42;cough&#42;) I probably won&#8217;t learn about it even if I do read about it.</p>

<p>Now I had a reason, so I set off to learn something about ACLs.</p>

<p>And here is what I learned about ACLs: they&#8217;re fairly complicated for what I&#8217;m trying to do.</p>

<p>Here&#8217;s another thing about me and (I believe) most geeks: we&#8217;re lazy. By which I mean, we&#8217;ll accept any acceptable solution, and tend to prefer the first one that &#8220;just works&#8221;.</p>

<p>(Look at the GUI for most large free software packages, and you&#8217;ll understand what I mean. Most geeks don&#8217;t care so much about making things <em>pretty</em> as making things <em>work</em>. When things work, they go on to making something else work.)</p>

<p>So, since I didn&#8217;t wake up today and say &#8220;Hey, I want to learn about ACLs today!&#8221; and I don&#8217;t know that I&#8217;ll have much use to know about them in the future, I went for the easiest solution I could think of, which is this:</p>

<pre><code>chmod -R 755 ~/Dropbox/bin/
</code></pre>

<p>which says &#8220;Make everything inside the ~/Dropbox/bin/ folder executable.&#8221;</p>

<p>And I put that line in my ~/.zshenv, so that whenever I open a new shell, the command gets run. Sure if I had thousands and thousands of files in there, it might be slow, but there 205, and it takes almost no &#8216;time&#8217; at all:</p>

<pre><code>$ time chmod -R 755 ~/Dropbox/bin 
chmod -R 755 ~/Dropbox/bin  0.00s user 0.00s system 16% cpu 0.019 total
</code></pre>

<p>Or, to put it another way:</p>

<pre><code>$ date;chmod -R 755 ~/Dropbox/bin;date
Wed Dec  3 23:20:24 EST 2008
Wed Dec  3 23:20:25 EST 2008
</code></pre>

<p>It takes less than a second.</p>

<p>Note: because I am a hardcore, comment-happy geek, this is actually what I put in my .zshenv:</p>

<pre><code># if the folder is found
# make everything inside it executable
# since Dropbox doesn't save execute bit

if [[ -d $HOME/Dropbox/bin ]]
then

    chmod -R 755 $HOME/Dropbox/bin

fi
</code></pre>

<p>which means that the command only gets run if the folder is located.</p>

<p>All in all, a pretty dang slick.</p>

<h2>Just One More Thing</h2>

<p>Did I mention that Dropbox saves revisions?</p>

<p>Yeah, so now if I make a change to a script and decide I want to undo that, I can go back and get a previous version.</p>

<h2>Oh, and about those ACLs</h2>

<ol>
<li><p>15 Geek Cred points to anyone who can tell me the proper &#8216;chmod&#8217; command to set ~/Dropbox/bin/ so that all the files inside of it are automatically set to be executable.</p></li>
<li><p>25 Geek Cred points to anyone who can point me to an online &#8220;ACLs in Plain English&#8221; explanation (and no, &#8216;man acl&#8217; doesn&#8217;t count :-)</p></li>
<li><p>If you want to deal with ACLs in Mac OS X and would like a GUI tool, checkout <a href="http://www.bresink.de/osx/TinkerToolSys.html">TinkerTool System</a> (not to be confused with <a href="http://www.bresink.de/osx/TinkerTool.html">TinkerTool</a> by the same company) which <a href="http://www.bresink.de/osx/193281/screenshots.html">handles ACLs</a>.  It sells for € 7.00 (as of 2008-12-03).</p></li>
</ol>

<p>If you take nothing else away from this, remember one thing: <a href="https://www.getdropbox.com/">Dropbox? More like ROCK BOX!</a></p>

<p>(No, no, I don&#8217;t mean it&#8217;s like a box of rocks, I mean it <em>rocks</em>. Nevermind.)</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/dropbox-bin/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>TwitReport</title>
		<link>http://tntluoma.com/shell-scripts/twitreport/</link>
		<comments>http://tntluoma.com/shell-scripts/twitreport/#comments</comments>
		<pubDate>Mon, 15 Sep 2008 02:42:10 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=937</guid>
		<description><![CDATA[What is TwitReport?

TwitReport takes the email that Twitter sends you when someone follows you and turns it into something more useful.

What does TwitReport tell me?

This is what TwitReport tells you about the new follower:


Full name (if given)
Twittername
Bio, Location, URL (if given)
How many people they follow
How many people they are followed by
Total # of Favorites
When they [...]]]></description>
			<content:encoded><![CDATA[<h1>What is TwitReport?</h1>

<p>TwitReport takes the email that Twitter sends you when someone follows you and turns it into something more useful.</p>

<h1>What does TwitReport tell me?</h1>

<p>This is what TwitReport tells you about the new follower:</p>

<ul>
<li>Full name (if given)</li>
<li>Twittername</li>
<li>Bio, Location, URL (if given)</li>
<li>How many people they follow</li>
<li>How many people they are followed by</li>
<li>Total # of Favorites</li>
<li>When they joined Twitter</li>
<li>Total # of posts</li>
<li>Percentage of @Replies</li>
<li>Average posts per day</li>
<li>20 most recent posts (and a link to more if they have more than 20)</li>
</ul>

<p>What sets TwitReport apart are the &#8220;Relationship Reports&#8221;:</p>

<ol>
<li>Who do <em>I</em> follow who follows this new person?</li>
<li>Who do <em>I</em> follow who this person also follows?</li>
<li>Who follows both me <em>and</em> this new person?</li>
</ol>

<p>You also get links to:<br />
* Follow them
* Send them a DM
* Block them
* See a larger version of their picture</p>

<p>You can also, if you choose, get a DM with basic stats information when someone follows you. (You control whether these DMs are sent or not. See below.)</p>

<h1>Compared to TwiMailer</h1>

<p><a href="http://twimailer.com/">TwiMailer</a> recently launched with a much better PR campaign than TwitReport.</p>

<p>It actually does less than TwitReport does, as far as I can tell, with one exception: TwiMailer gives you a link to follow someone right in the email. TwitReports give you a link to the the new follower&#8217;s Twitter page and you have to click that, and then click follow.</p>

<p>TwiMailer does not give the &#8220;Relationships&#8221; information, nor does it make it easy to use with multiple Twitter accounts. It also does not offer &#8220;Block&#8221; links (something I assume will change soon).</p>

<p>Oh, and you don&#8217;t have to change your email address in Twitter.</p>

<h1>TwitMailer and TwitReports are not competitors</h1>

<p>I have no financial stake in TwitReport, just hours spent.</p>

<p>If TwiMailer would include all the TwitReport information, I would happily suspend development.</p>

<p>Ideally, though, this ought to be what Twitter is providing.</p>

<h2>So How Do I Use It?</h2>

<p>Couple of options:</p>

<ol>
<li><p>When you get a &#8220;New Follower&#8221; email (like the one shown above), simply forward it to <nobr><strong>twitreport AT tntluoma DOT com</strong></nobr>. The only important thing is that you <strong>Do Not Change The Subject Line</strong> (adding a FWD: or FW: at the beginning is not a problem). [Update 2009-02-15: See note below under &#8216;Auto DMs of New Followers&#8217;]</p></li>
<li><p>Send a blank email to the above address with the Subject: <strong>twitreport foobar</strong> (where &#8220;foobar&#8221; is the Twittername you want to get a report for). This is helpful if you just want to check someone&#8217;s information even if they don&#8217;t follow you.</p></li>
<li><p>Setup an automatic forwarding rule in your mail program.</p></li>
</ol>

<p>That last option is by far the slickest, and it&#8217;s what I do.</p>

<p>If you use GMail, all you need to do is setup a filter with the following criteria:</p>

<ul>
<li>From: &#8220;@postmaster.twitter.com&#8221;</li>
<li>Subject: is now following you on twitter!</li>
</ul>

<p>which should look like this:</p>

<p><img src="/files/TwitReport-Filter-508x200.png" alt="GMail Filter" border="0" width="508" height="200"  /></p>

<p>and then click <strong>Next Step</strong></p>

<ul>
<li>Check &#8220;Skip the Inbox (Archive it) <em>[Note: this is <strong>recommended</strong> but not strictly <strong>required</strong>. IMO it just makes sense to ignore the official email because the new one should arrive in a minute or two]</em></li>
<li>Forward it to (the above address, shown in the image)</li>
</ul>

<p><img src="/files/twit-filter-2a.png" alt="Twit Filter 2a.png" border="0" width="525" height="217"  /></p>

<ul>
<li>Click &#8220;Update Filter&#8221;</li>
</ul>

<p><strong>Note:</strong> Gmail will <em>not</em> forward email that you have already received, so don&#8217;t ask.</p>

<h1>A Note About Forwarding</h1>

<p>Apple&#8217;s Mail program (and others) will let you create a &#8220;rule&#8221; to forward automatically, but it does not maintain the original Twitter headers, so you will not get the Relationship Reports.</p>

<h2>Auto DMs of New Followers</h2>

<p><a href="http://twitter.com/brookr">@brookr</a> on Twitter came up with a very cool idea.  He asked if it would be possible to get a Direct Message (DM) whenever someone new starts following you.</p>

<p>Turns out this is possible, but there are <strong><em>very specific criteria</em></strong>:</p>

<ol>
<li><p>You must be following <a href="http://twitter.com/twitreport">@twitreport</a>. The DMs will come from that account.  It is a very low volume account which generally only gets very sporadic posts when I am tinkering with the scripts. Which I don&#8217;t expect to do very often.</p></li>
<li><p>You must be forwarding the New Follower Emails automatically. The way Gmail does it works, I don&#8217;t know about other methods. They must keep the &#8216;X-Twitterrecipientscreenname&#8217; header intact.</p></li>
</ol>

<p>What info is included in the DM? Currently it includes their Full Name (if given), Followers/Following/# of Posts, how many days since they joined twitter, and their Bio.  Oh, and if their updates are &#8216;Protected&#8217; it will tell you that.  (Subject to change. Have a suggestion? Leave a comment below.)</p>

<p><strong>Q: What if I want to follow <a href="http://twitter.com/twitreport">@twitreport</a> but don&#8217;t want the DMs?</strong></p>

<p>Simple: change your email filter which sends the New Follower Emails so that it forwards to &#8216;twitreport+nodm@tntluoma.com&#8217; instead of &#8216;twitreport@tntluoma.com&#8217;</p>

<h2>One More Thing&#8230;..</h2>

<p>Make sure that you go to <a href="http://twitter.com/account/notifications">http://twitter.com/account/notifications</a> and verify that there is a checkbox next to &#8220;New Follower Emails&#8221;:</p>

<p><img src="/files/new-follower-twitter.png" alt="New follower Twitter.png" border="0" width="404" height="31"  /></p>

<p>otherwise the rest of this is pretty much useless!</p>

<p>There is an <a href="http://twitter.com/twitreport">@twitreport</a> account too, but you can leave comments, ideas, etc here too.</p>

<h2>Change Log</h2>

<p><strong>Version 1: Nov 2008</strong><br />
Based entirely on web scraping using &#8216;lynx&#8217; and several commandline Unix tools</p>

<p><strong>Version 2: Early Feb 2009</strong><br />
Begun to use API calls for most information. More information now available and less error-prone.</p>

<p><strong>Version 3: 2009-02-15</strong><br />
* Notification emails now include the new follower&#8217;s Twitter Icon. If you&#8217;re anything like me, you may recognize people more by their icon than their name.
* Direct Messages now supported for new followers</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/twitreport/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Fastest Way to Get Pictures from your Camera Card to your Mac</title>
		<link>http://tntluoma.com/shell-scripts/pics2hd/</link>
		<comments>http://tntluoma.com/shell-scripts/pics2hd/#comments</comments>
		<pubDate>Sun, 24 Aug 2008 05:54:52 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=926</guid>
		<description><![CDATA[Joe Maller asks on Twitter:


what is iPhoto doing that manages grind every other app to a standstill while importing?! Copying JPEGs over USB shouldn&#8217;t be this hard


I have no idea, but it&#8217;s bad enough that I don&#8217;t bother trying to make it work anymore.

I did what any self-respecting geek would do:

I wrote a shell script, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://twitter.com/joemaller/">Joe Maller</a> asks on <a href="http://twitter.com/joemaller/statuses/897002754">Twitter</a>:</p>

<blockquote cite="http://twitter.com/joemaller/statuses/897002754">
what is iPhoto doing that manages grind every other app to a standstill while importing?! Copying JPEGs over USB shouldn&#8217;t be this hard
</blockquote>

<p>I have no idea, but it&#8217;s bad enough that I don&#8217;t bother trying to make it work anymore.</p>

<p>I did what any self-respecting geek would do:</p>

<p>I wrote a shell script, and took out most of the vowels when naming it: <a href="/files/pics2hd.sh.zip">pics2hd.sh</a></p>

<p>Long story short:</p>

<p>1) It moves .jpg and .avi files from your SD card (or whatever) to a folder</p>

<p>2) It renames them to the date and time when the picture was taken (handy in case the EXIF data ever gets lost)</p>

<p>3) It ejects the card</p>

<p>4) You have to be comfortable with some basic Terminal.app usage (i.e. you have to know what it means when I say &#8220;Download this script, unzip it, chmod 755 it, and put it somewhere in your $PATH)</p>

<p>5) Read the script in BBEdit/TextWrangler whatever for some other important notes and usage instructions</p>

<p>6) No warrantee or guarantee expressed or implied. If it breaks, you get to keep both pieces and all of the responsibility. Welcome to adulthood.</p>

<p>7) I welcome improvements, corrections, or questions, but don&#8217;t expect much by the way of tech support for this.</p>

<p>8) Free of charge, free to modify, free to whatever you want to do with it.</p>

<p>Download here: <a href="/files/pics2hd.sh.zip">pics2hd.sh</a></p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/pics2hd/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Vonage and AT&amp;T Home Voicemail on an iPhone</title>
		<link>http://tntluoma.com/shell-scripts/att-home-voicemail-on-an-iphone/</link>
		<comments>http://tntluoma.com/shell-scripts/att-home-voicemail-on-an-iphone/#comments</comments>
		<pubDate>Wed, 16 Jul 2008 04:25:53 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=917</guid>
		<description><![CDATA[AT&#038;T home voicemail sends me a WAV email attachment that iPhone can&#8217;t play.

Synergy (n): Still Meaningless Bullshit After All These Years. (Source: Me on May 29th, 2008)

The Problem

Part 1) We have AT&#38;T for our home voicemail. When someone leaves a voicemail message there, I can get an email or text message. However, then I have [...]]]></description>
			<content:encoded><![CDATA[<blockquote cite="http://twitter.com/tj/statuses/822530868">AT&#038;T home voicemail sends me a WAV email attachment that iPhone can&#8217;t play.

Synergy (n): Still Meaningless Bullshit After All These Years. (Source: Me on <a href="http://twitter.com/tj/statuses/822530868">May 29th, 2008</a>)</blockquote>

<h3>The Problem</h3>

<p><strong>Part 1)</strong> We have AT&amp;T for our home voicemail. When someone leaves a voicemail message there, I can get an email or text message. However, then I have to dial a 10 digit number, enter our home phone number, then a 6 digit PIN, then press 1, then press 1 again.</p>

<p>Which is annoying.</p>

<p><strong>Part 2)</strong> AT&amp;T can send me a copy of the voicemail as a .wav file  &#8212;  but (and you&#8217;ll love this part!) the .wav file can&#8217;t be played on an iPhone.</p>

<p>(Yes, this is the same AT&amp;T with the exclusive contract with Apple to sell the iPhone in the USA.)</p>

<p><strong>Part 3)</strong> There are lots of areas with poor/weak cell reception. The process described in Part 1 can take a couple of minutes just to get to the message.</p>

<p><strong>Part 4)</strong> There&#8217;s no easy way to go back and search through old messages, unless you know the number. I can download the .wav on my desktop but it ends up with the name &#8220;message-x.wav&#8221; where X is a number. Not helpful..</p>

<h3>The Solution</h3>

<p>The easiest solution seemed to be to convert the file to MP3 and then send <em>that</em> file.</p>

<p>But, while I was at it, I might as well throw in a few extras such as doing a reverse lookup on the phone number to see who the call is from.</p>

<p>I used to scrape content from reverse lookup websites until I found <a href="http://www.whitepages.com">Whitepages.com</a> had released an API earlier this year.</p>

<p>I spent several days figuring out how to parse the information.</p>

<p>Then they changed it so you were getting a lot <em>more</em> information, which meant that I had to re-do everything that I had done.</p>

<h3>Geeky Part #1: The Procmail Part</h3>

<p>Procmail geeks will understand this next part</p>

<p><pre>
:0
* ^X-DCL-Caller-Number: \/[^ ]+
{
    # The phone number is sent as a Header to the email
    PHONE="$MATCH"</p>

<pre><code># find a unique datestamp ready
TIMESTAMP=`date '+%s'`

# set AND EXPORT (I forgot that part at first) a unique variable
export METAMAIL_TMPDIR=$HOME/voicemail/temp/$TIMESTAMP

# This will do nothing except dump the
# file into the METAMAIL_TMPDIR above
:0 fb w
| (mkdir -p "$METAMAIL_TMPDIR" &amp;&amp; metamail -q -x 2&gt;&amp;1&gt;/dev/null)

# this external program does all of the heavy lifting
:0 fb i
| process-new-voicemail-wav.sh "$PHONE" "$METAMAIL_TMPDIR"
</code></pre>

<p>}
</pre></p>

<h3>Geeky Part #2: The </h3>

<p>This is the &#8216;process-new-voicemail-wav.sh&#8217; script</p>

<p><pre></p>

<h1>!/bin/sh</h1>

<p>PHONE="$1"</p>

<p>METAMAIL_TMPDIR="$2"</p>

<h1>Get the Reverse Lookup Information for the phone number</h1>

<p>reverse.sh $PHONE >/dev/null</p>

<h1>I am in Eastern Time, server is on California time, so we adjust +3 hours</h1>

<p>TIME=<code>date --date '+3 hours' '+%Y-%m-%d-at-%H.%M'</code></p>

<h1>Make sure that the folder we were given is valid</h1>

<p>if [ ! -d &#8220;$METAMAIL_TMPDIR&#8221; ]
then</p>

<pre><code>echo "$NAME: FAILED could not find a directory $DIR at $TIME" |\
Mail -s "$NAME Fatal error" $MAILTO
exit 1
</code></pre>

<p>fi</p>

<h1>make sure we can get into the dir</h1>

<p>cd &#8220;$METAMAIL_TMPDIR&#8221; || exit 2</p>

<p>for INPUT_FILE in <code>find $METAMAIL_TMPDIR/ -type f -print</code>
do</p>

<pre><code># get JUST THE NAME of the person who called
VM_NAME=`reverse.sh --just name $PHONE`

# make sure we don't hit the API again too quickly
sleep 1

# get the just the ADDRESS of the person who called
VM_ADDRESS=`reverse.sh --just address $PHONE`

# Save the filename in a variable, since we use it
# several times
OUTPUT_MP3="$PHONE.$MESSAGE_FOR.$TIME.mp3"

# This is the core of the whole operation
# ffmpeg will conver the WAV to MP3 and tag it
# Unfortunately the tagging is limited to 30 characters per field, so we couldn't do a whole lot with it
# so we use several fields. This means that I have to adjust my 'reverse.sh' script
# so that it will give just the name and/or address if so requested
#
# Note the "MESSAGE_FOR" part below was never fully implemented. My wife and I
# both have voicemail systems so I want to be able to tell those apart
# most folks wouldn't need that part anyway.
ffmpeg  \
    -i "$INPUT_FILE" \
    -author "$VM_NAME" \
    -timestamp "`date --date '+3 hours' '+%H:%M on %Y-%m-%d'`" \
    -album "Voicemail for $MESSAGE_FOR" \
    -comment "$VM_ADDRESS" \
    "$OUTPUT_MP3"

if [ -f "$OUTPUT_MP3" ]
then

    # mpack keeps chocking on "No such file or directory"
    # without an explicit TMPDIR
    #
    # YEAH THAT TOOK A LONG TIME TO FIGURE OUT
    #
    TMPDIR=.

    export TMPDIR

    mpack -s "Voicemail Test $TIME" \
        "$OUTPUT_MP3" myemailaddresswhichisntthis@gmail.com

fi
</code></pre>

<p>done</p>

<p>exit 0</p>

<h1>EOF</h1>

<p></pre></p>

<h3>Geek Part #3: The Reverse Lookup Script</h3>

<p>This was where I spent the majority of my time.  After I had gotten it worked out the first time, Whitepages changed things so that you got <em>much more data</em> back, and all my underlying assumptions no longer held.  This is a good thing, I guess, but it made things much more complex.</p>

<p>Plus, then I realized that I needed to take <em>mobile phones</em> into consideration, which was a whole other rathole to deal with.</p>

<p>I won&#8217;t post the whole script, since it is currently 362 lines long, but suffice it to say, it is huge and complex.</p>

<h3>Bumps In the Road</h3>

<p>Actually there were a bunch of snags in the road.</p>

<p>1) Metamail wasn&#8217;t using the folder I told it to use. Without that, we didn&#8217;t know where to look for the voicemail file.</p>

<p>2) ffmpeg wasn&#8217;t the first program I tried.</p>

<p>First I tried &#8216;sox&#8217; and then &#8216;lame&#8217;.</p>

<p>Both said that they could not deal with this specific kind of WAV (Thank you AT&amp;T for using an odd kind of .wav file!) which is described by &#8216;file&#8217; as &#8220;RIFF (little-endian) data, WAVE audio, ITU G.711 mu-law, mono 8000 Hz&#8221;</p>

<p>Lame died with an error &#8220;Unsupported data format: 0x0007&#8221;</p>

<p>It was only then that I did even more research and found that ffmpeg could do it, <em>and</em> it was already installed! YAY!</p>

<p>3) &#8216;mpack&#8217; is a program to email files from the commandline. I had to download, compile, install it.  All of which worked fine.</p>

<p>It just refused to work once it was installed.</p>

<p>It kept telling me the file wasn&#8217;t there when it was.</p>

<p>I finally tracked that down to needing to be explicit when dealing with a Temp directory for mpack as well.</p>

<p>4) After many, many frustrating hours over many days trying to get this all to work, my wife came in and said &#8220;You do realize that the amount of time you are hoping to save will never match the amount of time you&#8217;ve spent on this, right?&#8221;</p>

<p>So, you know&#8230; ouch.</p>

<p>On the other hand, she was also looking for a voicemail message from a friend of ours we haven&#8217;t spoken to in years. She had deleted off her voicemail, and I knew I must have a copy of it somewhere, but was it called &#8216;message.wav&#8217; or &#8216;message-5.wav&#8217; or &#8216;message-10.wav&#8217; or what?  I know she&#8217;s in California but none of the files are marked in any way to tell what the phone number was.</p>

<p>We ended up having to look for her number a totally different way which wouldn&#8217;t work 99% of the time.</p>

<h3>I Finally Solved All of the Problems (*)</h3>

<p>(*) Except for one.</p>

<p>Remember how excited I was that &#8216;ffmpeg&#8217; was already installed on the server?</p>

<p>Well it is.</p>

<p>Sorta.</p>

<p>It is installed on the <em>webserver</em>.  It is installed on the machine I ssh into to make sure that everything was running (vs testing on my Mac and then having new problems on the actual machine).</p>

<p>However, mail is not delivered to the same machine as the webserver/ssh machine.</p>

<p>Mail is delivered to a different machine.</p>

<p>That machine does not have ffmpeg installed.</p>

<h3>Sometimes the Answer is: &#8220;Go To Bed&#8221;</h3>

<p>I finally quit around 2 a.m. last night and decided to go to bed.  Of course, as soon as I got into bed I realized what I could do:</p>

<p>Solution: Have procmail run &#8216;wget&#8217; or &#8216;lynx&#8217; on a specific URL (web page) which would run PHP which would execute the shell script <em>on the webserver</em> not the mailserver.</p>

<p>Since I was tired, I went to sleep.</p>

<p>Today I tried working on the PHP page, using what is no doubt an <em>entirely unsafe</em> method of calling a shell script and feeding the $QUERY_STRING directly to it.</p>

<p>It seemed to work, so I tried to add some security to it&#8230;</p>

<p>…at which point I broke it so badly I couldn&#8217;t even figure out how to make the un-safe method work again (I haven&#8217;t done that much PHP work and haven&#8217;t written raw PHP in 5+ years).</p>

<p>So I gave up.</p>

<h3>Sometimes the Answer is: Give Up</h3>

<p>It might not make a great after-school special, but the truth of the matter is that sometimes you just need to give up.</p>

<p>At least for a little while.</p>

<p>You need to take a break, step back, and re-evaluate <em>everything.</em></p>

<p>For example, I realized that I had gotten really far afield from my original goal: make an MP3 (I haven&#8217;t even mentioned some of the other grandiosity that I had in mind, such as a web-accessible, searchable archive).</p>

<h3>Sometimes the Answer is: Doest Thou Shitteth Me?</h3>

<p>So have you guessed what I missed?</p>

<p>I&#8217;ll give you a hint: something happened last Friday.</p>

<p>With Apple.</p>

<p>And the iPhone.</p>

<p>iPhone OS 2.0 was released.</p>

<p>Here&#8217;s a bug-fix for iPhone 2.0 that you won&#8217;t see listed in the reviews my Macworld, or Ars Technica, or Engadget, or anywhere else except here:</p>

<p>iPhone 2.0 brings compatibility with the kind of .wav file used by AT&amp;T for their home voicemail.</p>

<p>Now I&#8217;ve already mentioned that this was an odd kind of .wav file, so I cannot believe this was an accident.  Apple fixed their mobile media player to work with AT&amp;T&#8217;s home voicemail.</p>

<h3>Quote The Wife</h3>

<p>Relaying this information to my wife she said &#8220;So this is one of those times when I should <em>NOT</em> say &#8216;I told you so&#8217; right?&#8221;</p>

<p>Well, the fact of the matter is that I&#8217;d still like to get the reverse lookup information in there, but with the free <a title="iTunes Link for People" href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284942546&#038;mt=8">People application for iPhone</a> which uses the Whitepages.com data, it is easy enough to do a manual reverse lookup.</p>

<p>All things being equal, this is probably the best possible outcome. Ok, well, the best possible outcome would be that the reverse lookup information is included, but really, that&#8217;s not a huge issue.</p>

<p>This means that I don&#8217;t have to worry about any piece of the chain breaking down between a procmail receipe, a PHP page, and two shell scripts.</p>

<p>And it means that I have spent the evening relaxing with the family and writing this up&#8230; and now I can go to bed.</p>

<p>UPDATE: I am told that Vonage also uses &#8220;RIFF (little-endian) data, WAVE audio, ITU G.711 mu-law, mono 8000 Hz&#8221; files which also play on the updated iPod Touch.</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/att-home-voicemail-on-an-iphone/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Free Reverse Lookup from the Command Line</title>
		<link>http://tntluoma.com/shell-scripts/free-reverse-lookup-from-the-command-line/</link>
		<comments>http://tntluoma.com/shell-scripts/free-reverse-lookup-from-the-command-line/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 22:51:03 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=915</guid>
		<description><![CDATA[reverse.sh is a free Bash script that, like all good Unix utilities, does one thing

Purpose: Give it a phone number, it will do a reverse lookup on that number and give you the name and address of either the person or business it is associated with.

That&#8217;s it.

NOTE: the script won&#8217;t work without a free API [...]]]></description>
			<content:encoded><![CDATA[<p><a href="/files/reverse.sh">reverse.sh</a> is a free Bash script that, like all good Unix utilities, does one thing</p>

<p>Purpose: Give it a phone number, it will do a reverse lookup on that number and give you the name and address of either the person or business it is associated with.</p>

<p>That&#8217;s it.</p>

<p>NOTE: the script won&#8217;t work without a free API key that you need to get (see below).</p>

<p>Why this is important is that I&#8217;ve been trying to do this for years, and always ended up content scraping, which is a horribly ineffective, error-prone, and easy to break way of getting this information.</p>

<p>Have you ever tried to find a reverse lookup that isn&#8217;t loaded down with ads?  Good luck.</p>

<p>Well, I finally found the answer.</p>

<p><a href="http://www.whitepages.com/landing/api">Whitepages.com has a free API</a> which they just opened up a few months ago.  I went in, got an API key, and voilà!</p>

<p>I would really very much like to be able to make an iPhone-friendly web page that would do the same thing, but I&#8217;m not sure how to do that yet.  Other than an <a href="http://developer.whitepages.com/page/attribution">attribution to WhitePages.com</a> the page would be ad-free. I&#8217;m surprised such a thing apparently doesn&#8217;t exist over a year after the iPhone was introduced.</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/free-reverse-lookup-from-the-command-line/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Twitter API Count</title>
		<link>http://tntluoma.com/shell-scripts/twitter-api-count/</link>
		<comments>http://tntluoma.com/shell-scripts/twitter-api-count/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 17:55:46 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=914</guid>
		<description><![CDATA[Here, Mac OS X (*) Twitter Users, I made you this:

Download: twitterapicount.sh

Download it, put it somewhere like $HOME/bin/twitterapicount.sh and do this in Terminal:

chmod 755 ~/bin/twitterapicount.sh

then open a new Terminal.app window and type

twitterapicount.sh YourTwitterName YourTwitterPassword

and it will tell you

A) How many API hits Twitter is currently giving out

B) How many API hits you have used this [...]]]></description>
			<content:encoded><![CDATA[<p>Here, Mac OS X (*) Twitter Users, I made you this:</p>

<p><strong>Download: <a href="/files/twitterapicount.sh">twitterapicount.sh</a></strong></p>

<p>Download it, put it somewhere like $HOME/bin/twitterapicount.sh and do this in Terminal:</p>

<p><tt>chmod 755 ~/bin/twitterapicount.sh</tt></p>

<p>then open a new Terminal.app window and type</p>

<p><tt>twitterapicount.sh YourTwitterName YourTwitterPassword</tt></p>

<p>and it will tell you</p>

<p>A) How many API hits Twitter is currently giving out</p>

<p>B) How many API hits you have used this hour</p>

<p>C) How long you have to wait for a new batch of API hits</p>

<p>For example, the current information for my <a href="http://twitter.com/tj">TJ</a> account is shown here (note the $ is used just to represent the Terminal.app prompt):</p>

<p><pre>
$ twitterapicount.sh tj REDACTED</p>

<p>Twitter API totals for account:     tj</p>

<p>Number of API Hits Allowed Per Hour:    70
Number of Hits You Have Remaining:  65</p>

<p>Time remaining until API count reset:   52 minutes
</pre></p>

<h3>Background</h3>

<p><a href="http://furbo.org/">Craig Hockenberry</a> (aka <a href="http://twitter.com/chockenberry">chockenberry</a>), the man behind <a title="Twitterific" href="http://iconfactory.com/software/twitterrific">The Bird</a> helped out some Twittees by letting us know that we could find out this limit by fetching an XML file like this:</p>

<p>curl -u TWITTERNAME:TWITTERPASSWORD http://twitter.com/account/rate_limit_status.xml</p>

<p>which gives you results like this:</p>

<p><pre>
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;hash>
  &lt;reset-time type="datetime">2008-07-09T18:42:21+00:00&lt;/reset-time>
  &lt;remaining-hits type="integer">65&lt;/remaining-hits>
  &lt;hourly-limit type="integer">70&lt;/hourly-limit>
  &lt;reset-time-in-seconds type="integer">1215628941&lt;/reset-time-in-seconds>
&lt;/hash>
</pre></p>

<p>which is totally awesome if you&#8217;re a computer, but not so good if you&#8217;re a human.</p>

<p>That information can be easily parsed into human-readable format, which is all this script does.  You can open it in TextEdit or BBedit or whatever if you&#8217;d like to see what it does. I get a little OCD when writing comments in code, and it&#8217;s not elegant (Ruby/Perl/etc coders look away! I&#8217;m hideous!) but it works.</p>

<h3>Warnings and Options</h3>

<p>If there is someone else logged into your computer (via ssh, for example) and they happen to run &#8216;ps&#8217; at just the right time when this script is running, they might see your Twitter password.  For most people this is as unlikely as getting pregnant while riding a pogo stick wearing ski pants, but in the interest of full-disclosure, I thought I&#8217;d mention it.</p>

<p>If you are worried about this, you have two options:</p>

<h1>1) Open the file, read the source and follow the instructions to hard-code your username and password into it. Then you will only have to call the file &#8220;twitterapicount.sh&#8221; and it will give you the info. NOTE: if you do this, run</h1>

<p><tt>chmod 700 ~/bin/twitterapicount.sh</tt></p>

<p>afterwards to make sure that no one else can read it.</p>

<h1>2) If you don&#8217;t want your password showing up in &#8216;ps&#8217; and you don&#8217;t want to muck with the source code, just run the program and tell it your username and leave off the password, and it will prompt you for it, like so:</h1>

<p><pre>
$ twitterapicount.sh tj
twitterapicount.sh: You gave me the Twitter username "tj".
Now I need the password (this is not stored anywhere)</p>

<p>Password for tj ?
</pre></p>

<p>(Obviously you want to use <em>your</em> Twitter name, not &#8216;tj&#8217;)</p>

<p>Once you type in your password, it will proceed as normal.</p>

<p>I think that&#8217;s it.</p>

<p>Questions / comments / feedback: luomat at gmail com</p>

<p>(<em>) Oh, this will probably work for those of you who use other variants of Un</em>x too.</p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/twitter-api-count/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>RickRolling Protection for April Fools&#8217; Day and Beyond</title>
		<link>http://tntluoma.com/shell-scripts/showurls/</link>
		<comments>http://tntluoma.com/shell-scripts/showurls/#comments</comments>
		<pubDate>Tue, 01 Apr 2008 13:01:12 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/?p=897</guid>
		<description><![CDATA[TinyURL and XRL.us are great URL shortening services.  Unfortunately, while they were intended for good, they have been used for evil, namely: Rick Rolling.

TinyURL will let you turn on previews (which keep you from being redirected before you see the destination URL) here: http://tinyurl.com/preview.php

If you are enough of a Terminal geek, you might like [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://tinyurl.com/create.php">TinyURL</a> and <a href="http://metamark.net/add">XRL.us</a> are great URL shortening services.  Unfortunately, while they were intended for good, they have been used for evil, namely: <a href="www.youtube.com/watch?v=eBGIQ7ZuuiU">Rick Rolling</a>.</p>

<p>TinyURL will let you turn on previews (which keep you from being redirected before you see the destination URL) here: <a href="http://tinyurl.com/preview.php">http://tinyurl.com/preview.php</a></p>

<p>If you are enough of a Terminal geek, you might like <a href="http://tj.tntluoma.com/files/showurls.sh">showurls.sh</a> which is a script I wrote.</p>

<p>Usage is simple, after installing (see script for details) simply use &#8220;showurls.sh http://some/short/url/here&#8221; such as</p>

<blockquote>
showurls.sh http://xrl.us/bip6p
</blockquote>

<p>which should give you output like:</p>

<p><a href="">http://xrl.us/bip6p</a>
points to <a href="http://www.comics2film.com/index.php?a=story&amp;b=32203&amp;c=22">http://www.comics2film.com/index.php?a=story&amp;b=32203&amp;c=22</a>
Title: The Elevator: &#8216;Panthea Obscura&#8217; - Story @ Comics2Film.com</p>

<p>(NOTE: if you see &#8220;tr: Illegal byte sequence&#8221; just ignore it)</p>

<p>Tested 99.99% effective against being <a href="www.youtube.com/watch?v=eBGIQ7ZuuiU">Rick Rolled</a>.  The &#8220;Title&#8221; part is hacky and might not work, but the &#8220;points to&#8221; should work with TinyURL, XRL.us, and any other service which redirects using the Location: header.</p>

<p>Other note: if you clicked on either one of two links explicitly marked as RickRolls, I might not be able to help you.</p>

<p>Download <a href="http://tj.tntluoma.com/files/showurls.sh">showurls.sh</a></p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/showurls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Get Current Weather Conditions for any Zip or Location</title>
		<link>http://tntluoma.com/shell-scripts/get-current-weather-conditions-for-any-zip-or-location/</link>
		<comments>http://tntluoma.com/shell-scripts/get-current-weather-conditions-for-any-zip-or-location/#comments</comments>
		<pubDate>Thu, 14 Jun 2007 04:24:16 +0000</pubDate>
		<dc:creator>@luomat</dc:creator>
				<category><![CDATA[Shell Scripts]]></category>

		<guid isPermaLink="false">http://tj.tntluoma.com/scripts/get-current-weather-conditions-for-any-zip-or-location</guid>
		<description><![CDATA[lynx -width=100000 \
-dump &#8216;http://mobile.wunderground.com/cgi-bin/findweather/getForecast?brand=mobile&#38;query=32605&#8217; &#124;\
sed &#8216;1,/Forecast as of/d; s#^   ##g&#8217; &#124;\
head -5 &#124;\
egrep &#8220;&#46;$&#8221; &#124;\
head -1

Note: the only line breaks in the above are where you see \ or &#124;\

What it does:

1) lynx dumps the output of the web page.  Change &#8216;32605&#8217; to the zip code you want.  Note the &#8216;-width&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p>lynx -width=100000 \
-dump &#8216;http://mobile.wunderground.com/cgi-bin/findweather/getForecast?brand=mobile&amp;query=32605&#8217; |\
sed &#8216;1,/Forecast as of/d; s#^   ##g&#8217; |\
head -5 |\
egrep &#8220;&#46;$&#8221; |\
head -1</p>

<p>Note: the only line breaks in the above are where you see \ or |\</p>

<p>What it does:</p>

<p>1) lynx dumps the output of the web page.  Change &#8216;32605&#8217; to the zip code you want.  Note the &#8216;-width&#8217; flag which is crucial to making this work.  It is meant to ensure that no line breaks will be added unless the HTML code calls for it.</p>

<p>2) sed deletes from the first line down to where it finds &#8216;Forecast as of&#8217; <em>and</em> deletes the leading spaces.</p>

<p>3) head takes the first 5 lines</p>

<p>4) egrep grabs the lines which end with a period</p>

<p>5) head takes the first result, which is the current weather conditions</p>

<p>So I can check out the current weather at any time with a simple command.  Turning it into a shell script that takes a variable is simple enough, I&#8217;d probably make it something like this:</p>

<p><pre></p>

<h1>!/bin/sh</h1>

<p>if [ "$#" -lt 1 ]
then
    # set a default zip code
    ZIP=45631
else
    # you can use either a zip code or words such as
    # gainesville florida
    # but you need to replace any spaces with +
    ZIP=<code>echo "$@" | tr -s ' ' '+'</code>
fi</p>

<p>URL=&#8221;http://mobile.wunderground.com/cgi-bin/findweather/getForecast?brand=mobile&amp;query=$ZIP&#8221;</p>

<p>echo -n &#8220;Current weather for $ZIP: &#8220;</p>

<p>lynx -width=100000 -dump &#8220;$URL&#8221; |&#92;
sed &#8216;1,/Forecast as of/d; s#^   ##g&#8217; |&#92;
head -5 |&#92;
egrep &#8220;&#46;$&#8221; |&#92;
head -1</p>

<p>exit 0</p>

<h1>EOF</h1>

<p></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://tntluoma.com/shell-scripts/get-current-weather-conditions-for-any-zip-or-location/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
