<?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>Brett Terpstraterminal page  - Brett Terpstra</title>
	<atom:link href="http://brettterpstra.com/tag/terminal/feed/" rel="self" type="application/rss+xml" />
	<link>http://brettterpstra.com</link>
	<description>Elegant solutions to complex problems.</description>
	<lastBuildDate>Tue, 22 May 2012 02:49:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>A simple but handy Bash function: console</title>
		<link>http://brettterpstra.com/a-simple-but-handy-bash-function-console/</link>
		<comments>http://brettterpstra.com/a-simple-but-handy-bash-function-console/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 09:30:39 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=3487</guid>
		<description><![CDATA[<p>Here’s a quick riff on an older bash alias I use which will allow you to easily scan system messages from Terminal. I’ve long had an alias in my ~/.bash_profile called console. It simply tailed the system log with ‘alias console=‘tail –f /var/log/system.log’. Bam I decided to amp it up a little for added convenience. The function below allows me&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/a-simple-but-handy-bash-function-console/">A simple but handy Bash function: console</a></p>]]></description>
			<content:encoded><![CDATA[<p>Here’s a quick riff on an older bash alias I use which will allow you to easily scan system messages from Terminal.</p>

<p>I’ve long had an alias in my <code>~/.bash_profile</code> called <code>console</code>. It simply tailed the system log with ‘alias console=‘tail –f /var/log/system.log’.</p>

<h3>Bam</h3>

<p>I decided to amp it up a little for added convenience. The function below allows me to add additional arguments which are translated into a regular expression for filtering the log output. Arguments, separated by spaces on the command line, are joined into a regular expression as OR matches. You can specify as many as you like to track each as a keyword. It’s case insensitive and you can use basic regular expression syntax in each parameter. Examples:</p>

<pre><code>$ console byword

$ console usbmuxd servermgrd

$ console mark(ed|y) multimarkdown composer
</code></pre>

<p><code>console</code> with no arguments will still just tail the log with no filter.</p>

<h3>The function</h3>

<p>Just stick this in your <code>~/.bash_profile</code> file, run <code>. ~/.bash_profile</code> and try it out.</p>

<pre><code>function console () {
  if [[ $# &gt; 0 ]]; then
    query=$(echo "$*"|tr -s ' ' '|')
    tail -f /var/log/system.log|grep -i --color=auto -E "$query"
  else
    tail -f /var/log/system.log
  fi
}
</code></pre>

<p>If you want to track more than just the <code>system.log</code> file, you can just add additional filenames, separated by a space, after system.log for each <code>tail</code> command in the function.</p>

<p>There, that was handy.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/fk-a-useful-bash-function/' rel='bookmark' title='fk: a useful bash function'>fk: a useful bash function</a></li>
<li><a href='http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/' rel='bookmark' title='oft: Bash function for opening a specific filetype'>oft: Bash function for opening a specific filetype</a></li>
<li><a href='http://brettterpstra.com/a-bash-function-for-markdown-bloggers/' rel='bookmark' title='A Bash function for Markdown bloggers'>A Bash function for Markdown bloggers</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/a-simple-but-handy-bash-function-console/">A simple but handy Bash function: console</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/a-simple-but-handy-bash-function-console/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>na: per-project todos in Terminal</title>
		<link>http://brettterpstra.com/na-per-project-todos-in-terminal/</link>
		<comments>http://brettterpstra.com/na-per-project-todos-in-terminal/#comments</comments>
		<pubDate>Sat, 24 Dec 2011 14:00:06 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[TaskPaper]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=3421</guid>
		<description><![CDATA[<p>As I’ve mentioned before, I keep todo.taskpaper files in my web and code project folders. These allow me to keep track of bugs, ideas, notes, etc., and the archive it creates helps me remember what I did, when I did it and how it worked. I like having them separated per project; it’s the way my one-track mind works. I&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/na-per-project-todos-in-terminal/">na: per-project todos in Terminal</a></p>]]></description>
			<content:encoded><![CDATA[<p>As I’ve mentioned before, I keep todo.taskpaper files in my web and code project folders. These allow me to keep track of bugs, ideas, notes, etc., and the archive it creates helps me remember what I did, when I did it and how it worked. I like having them separated per project; it’s the way my one-track mind works. I like the plain-text format because I can use any variety of methods (including <a href="http://www.hogbaysoftware.com/products/taskpaper">TaskPaper</a> itself) to manipulate and quickly update the files. This gave me the idea to have Terminal just notify me of current todos whenever I switched to a project. Thus, <code>na</code> was born. Whether or not it’s useful to anyone else remains to be seen, but I figured I’d share it anyway.</p>

<p>Yesterday at 5:30pm, this little project was working fine with about eight lines of code. Then I had an idea or two, and by morning it was 160 lines of code. It definitely got out of hand, but I rather like the final product. The bulk of the script is straight bash and UN*X commands, but I shelled a lot of the more complex string handling out to Ruby. I’m too lazy to deal with <code>awk</code> and <code>sed</code> past a certain point.</p>

<p>Feel free to skip to <a href="https://github.com/ttscoff/na">the <code>na</code> GitHub repo</a>, peek at the readme.md file and start playing. I welcome any revisions/iterations of this, so feel free to fork and let me know what you do with it!</p>

<p><span id="more-3421"></span></p>

<h3>Meet “na”</h3>

<p><code>na</code> is a bash function designed to make it easy to see what your next actions are for any project, right from the command line. It works with TaskPaper-format files (but any plain text format will do), looking for @na tags (or whatever you specify) in todo files in your current folder. It can also auto-display next actions when you enter a project directory, automatically locating any todo files and listing their next actions when you <code>cd</code> to the project (optionally recursive).</p>

<h3>Features</h3>

<p>You can list next actions in files in the current directory by typing <code>na</code>. By default, <code>na</code> looks for “.taskpaper” files and extracts items tagged “@na” and not “@done”. All of these can be changed in the configuration.</p>

<h4>Easy matching</h4>

<p><code>na</code> features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories names. If your project is in “~/Sites/dev/markedapp,” you could quickly list its next actions by typing <code>na dev mark</code>. It will always look for the shortest match.</p>

<h4>Recursion</h4>

<p><code>na</code> can also recurse subdirectories to find all todo files in child folders as well. Use the <code>-r</code> switch to do a recursive search on the current directory. <code>na -r</code> with no arguments will recurse from your current location, looking for todo files in all subdirectories. Maximum depth for recursion can be controlled in the config (default is 4). <code>na -r</code> can take a path or project title fragments as arguments as well, and will recurse from the matched directory. A configuration option allows you to have the auto-display recurse by default.</p>

<h4>Adding todos</h4>

<p>You can also quickly add todo items from the command line with the <code>-a</code> switch. The script will look for a file in the current directory called todo.taskpaper (or whatever extension you’ve set). If found, it will try to locate an “Inbox:” project, or create one if it doesn’t exist. Any arguments after <code>-a</code> will be combined to create a new task in TaskPaper format. They will automatically be assigned as next actions (tagged “@na”) and will show up when <code>na</code> lists the tasks for the project.</p>

<p>More details and usage examples (as well as the download) <a href="https://github.com/ttscoff/na">on the GitHub page</a>.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/totally-taskpaper/' rel='bookmark' title='Totally TaskPaper'>Totally TaskPaper</a></li>
<li><a href='http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/' rel='bookmark' title='Quick Tip: throttling parallel batch processes in Terminal'>Quick Tip: throttling parallel batch processes in Terminal</a></li>
<li><a href='http://brettterpstra.com/quick-link-terminal-navigation-utilities/' rel='bookmark' title='Quick Link: Terminal navigation utilities'>Quick Link: Terminal navigation utilities</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/na-per-project-todos-in-terminal/">na: per-project todos in Terminal</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/na-per-project-todos-in-terminal/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>GVoice command line SMS revisited</title>
		<link>http://brettterpstra.com/gvoice-command-line-sms-revisited/</link>
		<comments>http://brettterpstra.com/gvoice-command-line-sms-revisited/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 14:07:44 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[google voice]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/gvoice-command-line-sms-revisited/</guid>
		<description><![CDATA[<p>Thanks to a comment from Evaryont on the original SMS from the command line with Google Voice post, a problem that was causing Error 500s in the script has been solved. Check the original post for the script, and change the line (around line 90) rnrse = newres.match(/‘_rnr_se’: ‘([^’]+)’/)[1] to: rnrse = CGI.escape(newres.match(/‘_rnr_se’: ‘([^’]+)’/)[1]) The CGI escaping should help with&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/gvoice-command-line-sms-revisited/">GVoice command line SMS revisited</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/09/google_voice_128.png?9d7bd4" alt="Google Voice icon" height="128" width="128" class="alignright"></p>

<p>Thanks to a <a href="http://brettterpstra.com/sms-from-the-command-line-with-google-voice/#comment-20950">comment from Evaryont</a> on the original <a href="http://brettterpstra.com/sms-from-the-command-line-with-google-voice/">SMS from the command line with Google Voice</a> post, a problem that was causing Error 500s in the script has been solved.</p>

<p><span id="more-2733"></span></p>

<p>Check the original post for the script, and change the line (around line 90)</p>

<p>rnrse = newres.match(/‘_rnr_se’: ‘([^’]+)’/)[1]</p>

<p>to:</p>

<p>rnrse = CGI.escape(newres.match(/‘_rnr_se’: ‘([^’]+)’/)[1])</p>

<p>The CGI escaping should help with the Google’s changes to the <code>_rnr_se</code> variable. Evaryont also notes that the script works great in Arch Linux with Ruby 1.9.2. For 1.9 compatibility (thanks to David for clarification in the comments below), remove the <code>-rjcode</code> from the hashbang on the first line, and add <code>require 'jcode' if RUBY_VERSION &lt; '1.9'</code> below. Have fun!</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/sms-from-the-command-line-with-google-voice/' rel='bookmark' title='SMS from the command line with Google Voice'>SMS from the command line with Google Voice</a></li>
<li><a href='http://brettterpstra.com/a-system-service-for-to-url-shortening/' rel='bookmark' title='A System Service for to. url shortening'>A System Service for to. url shortening</a></li>
<li><a href='http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/' rel='bookmark' title='Address Book search and Skype from the command line'>Address Book search and Skype from the command line</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/gvoice-command-line-sms-revisited/">GVoice command line SMS revisited</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/gvoice-command-line-sms-revisited/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Quick Tip: This command line trick is tops</title>
		<link>http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/</link>
		<comments>http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 08:37:43 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[quicktip]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2710</guid>
		<description><![CDATA[<p>Quick tips are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize. I just (accidentally) discovered the command tops while working in Terminal. I’m not seeing many of mentions of it (any) on the web, but it could be too early in the&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/">Quick Tip: This command line trick is tops</a></p>]]></description>
			<content:encoded><![CDATA[<p><em><a href="http://brettterpstra.com/tag/quicktip/">Quick tips</a> are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize.</em></p>

<p>I just (accidentally) discovered the command <code>tops</code> while working in Terminal. I’m not seeing many of mentions of it (any) on the web, but it could be too early in the morning for me to form a coherent query. Regardless, I thought I’d give it a mention. The man page is quite complete, and has a succinct explanation of the command: <code>tops - perform in-place substitutions on code.</code></p>

<p>It’s not just useful for code, though, it makes a great tool for batch modifications to any text file(s). With an easy-to-grok syntax, it does in a few words what I usually do in three or more piped oneliners (grep, awk, sed, etc.).  There’s a <code>replacemethod</code> option specifically for replacing Objective-C-style method names, which leads me to believe that this is an OS X-only tool, possibly only part of the Developer Tools. If anyone more familiar with this command has insight, I’d be curious.</p>

<p>Tops can read a script file with rules for search and replace, or take commands as arguments to process changes in a text file instantly. Simple example:</p>

<pre><code>tops replace "Word" with "Markdown" writing.*
</code></pre>

<p>All instances of “Word” in all files with the name “writing” were just replaced with “Markdown.” Try it, it’s cool. The options go far beyond my simplistic example, but the more complex options are primarily specific to Objective-C. If this piques your curiosity anyway, spend some time with <code>man tops</code>.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/' rel='bookmark' title='Address Book search and Skype from the command line'>Address Book search and Skype from the command line</a></li>
<li><a href='http://brettterpstra.com/gvoice-command-line-sms-revisited/' rel='bookmark' title='GVoice command line SMS revisited'>GVoice command line SMS revisited</a></li>
<li><a href='http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/' rel='bookmark' title='Quick Tip: Extracting Mac App Store reviews as text'>Quick Tip: Extracting Mac App Store reviews as text</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/">Quick Tip: This command line trick is tops</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Extracting Mac App Store reviews as text</title>
		<link>http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/</link>
		<comments>http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/#comments</comments>
		<pubDate>Sat, 13 Aug 2011 03:06:02 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[mac app store]]></category>
		<category><![CDATA[markdown]]></category>
		<category><![CDATA[markdownifier]]></category>
		<category><![CDATA[marked]]></category>
		<category><![CDATA[quicktip]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2498</guid>
		<description><![CDATA[<p>Quick tips are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize. Apple has disabled the ability to copy and paste text (or even select it) in the Mac App Store. This is fine for descriptions, you can just view the web preview&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/">Quick Tip: Extracting Mac App Store reviews as text</a></p>]]></description>
			<content:encoded><![CDATA[<p><em><a href="http://brettterpstra.com/tag/quicktip/">Quick tips</a> are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize.</em></p>

<p>Apple has disabled the ability to copy and paste text (or even select it) in the Mac App Store. This is fine for descriptions, you can just view the web preview and get what you need (just right click the icon in the App Store app and choose Copy Link to paste into your browser). You can even get to the first few reviews that way. Marked users have left some insanely nice reviews, though, and I wanted to capture them all (both for marketing and for general warm fuzzies).</p>

<p>First, we need to enable WebKit’s Inspector in the App Store. In case you didn’t know it, the App Stores for both Mac and iOS (iTunes) are just HTML. With the Webkit Inspector loaded, you can dig right into the code.</p>

<p>Quit the App Store application. Run this line in Terminal:</p>

<pre><code>defaults write com.apple.appstore WebKitDeveloperExtras -bool true
</code></pre>

<p>Now, (after starting App Store back up) when you right click an element, you’ll get a contextual menu with “Inspect Element.” Go ahead and select it. If you’re not familiar with the Inspector, have a peek around. The main section you need for this, though, is the first one: Elements.</p>

<p><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2011/08/AppStoreInspector.jpg?9d7bd4"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/08/AppStoreInspector-300x253.jpg?9d7bd4" alt="App Store Webkit Inspector screenshot" title="App Store Webkit Inspector" width="300" height="253" class="alignright size-medium wp-image-2499" /></a>It shows an outline of the DOM (post JavaScript processing) and lets you select any element on the page. You can get to elements quickly by turning on the magnifying glass at the bottom and hovering over elements on the page to highlight them in the Inspector. Note that you can break the inspector out of the main window and into it’s own with the icon in the lower left corner.</p>

<p>For my purposes I wanted all of the html text in the reviews section, so I navigated to the containing element and selected it. Right clicking on the element in the inspector now offers me the ability to “Copy as HTML.” Doing that gives me that whole chunk of HMTL and makes writing up “testimonials” for the new <a href="http://markedapp.com">Marked</a> website much, much easier.</p>

<p>If you want to go the extra mile, and I <em>do</em>, you might want to convert all of this markup to something more readable. If you use the Blogsmith Blogging bundle in TextMate, you already have a command (Convert HTML to Markdown) that will turn the HTML chunk into nicely formatted Markdown. You can also use <a href="http://www.aaronsw.com/2002/html2text/">html2text.py</a>, <a href="http://milianw.de/projects/markdownify/">Markdownify for PHP</a> or Pandoc.</p>

<p>A couple of quick regular expression search and replace maneuvers later, I have a list of all of my reviews thus far, with attribution and title. Nice.</p>

<p>Marked 1.2 is looking great, by the way, and should be in your hands faster than you can terrace a backyard, assuming you’re in moderate shape and have some evening and weekend time available. Maybe faster than that. It would take you 2–3 weeks, right?</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/quick-tip-fixing-the-other-account-mac-app-store-issue/' rel='bookmark' title='Quick Tip: fixing the “other account” Mac App Store issue'>Quick Tip: fixing the “other account” Mac App Store issue</a></li>
<li><a href='http://brettterpstra.com/marked-is-on-the-mac-app-store/' rel='bookmark' title='Marked is on the Mac App Store'>Marked is on the Mac App Store</a></li>
<li><a href='http://brettterpstra.com/multimarkdown-composer-hits-the-app-store/' rel='bookmark' title='MultiMarkdown Composer hits the App Store'>MultiMarkdown Composer hits the App Store</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/">Quick Tip: Extracting Mac App Store reviews as text</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Option-arrow navigation in iTerm2</title>
		<link>http://brettterpstra.com/option-arrow-navigation-in-iterm2/</link>
		<comments>http://brettterpstra.com/option-arrow-navigation-in-iterm2/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 15:19:49 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[iterm2]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2489</guid>
		<description><![CDATA[<p>Update: See the comments for more (and possibly better) solutions from readers! I’ve been trying to get Option-arrow keys to move by word in iTerm2. I figured out a solution, but it’s weird. If anyone has an explanation or a better way to do this, let me know. First, I had to edit my ~/.inputrc file and add these lines:&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/option-arrow-navigation-in-iterm2/">Option-arrow navigation in iTerm2</a></p>]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> See the comments for more (and possibly better) solutions from readers!</p>

<p>I’ve been trying to get Option-arrow keys to move by word in iTerm2. I figured out a solution, but it’s weird. If anyone has an explanation or a better way to do this, let me know.</p>

<p>First, I had to edit my <code>~/.inputrc</code> file and add these lines:</p>

<pre><code>"\e[1;5C": forward-word
"\e[1;5D": backward-word
</code></pre>

<p><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2011/08/iTerm2SettingsPanel-2.jpg?9d7bd4"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/08/iTerm2SettingsPanel-2-300x224.jpg?9d7bd4" alt="iTerm2 Preference Panel screenshot" title="iTerm2 Settings Panel" width="300" height="224" class="alignright size-medium wp-image-2492 shadow" /></a>Then I had to set up in iTerm2 preferences–under Profiles-&gt;Keys–the options for both key combinations:</p>

<ul>
<li>Add a hotkey with the plus symbol at the bottom of the hotkey list</li>
<li>Set the keyboard shortcut by pressing Option-left or Option-right</li>
<li>Set the action to “Send Escape Sequence”</li>
<li>Set the Esc+ field to:

<ul>
<li>[1;5C (Option-Right)</li>
<li>[1;5D (Option-Left)   </li>
</ul></li>
</ul>

<p>With these in place both work swimmingly. I don’t know why I had to do both parts, though…</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/new-text-navigation-keybindings/' rel='bookmark' title='New text navigation KeyBindings'>New text navigation KeyBindings</a></li>
<li><a href='http://brettterpstra.com/keybinding-madness/' rel='bookmark' title='KeyBinding madness'>KeyBinding madness</a></li>
<li><a href='http://brettterpstra.com/filesystem-navigation-with-textexpander/' rel='bookmark' title='Filesystem navigation with TextExpander'>Filesystem navigation with TextExpander</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/option-arrow-navigation-in-iterm2/">Option-arrow navigation in iTerm2</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/option-arrow-navigation-in-iterm2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Quick Link: Terminal navigation utilities</title>
		<link>http://brettterpstra.com/quick-link-terminal-navigation-utilities/</link>
		<comments>http://brettterpstra.com/quick-link-terminal-navigation-utilities/#comments</comments>
		<pubDate>Tue, 24 May 2011 10:38:57 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[quicklink]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/quick-link-terminal-navigation-utilities/</guid>
		<description><![CDATA[<p>If you follow me on Twitter, you’ve probably seen me express my adoration for autojump, a command-line utility for navigating frequently-used folders. The only problem is that I deal with a lot of repetitive folder hierarchies; for example, the multiple site structures in my web development folder. j css almost certainly isn’t going to take me to the one I&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-link-terminal-navigation-utilities/">Quick Link: Terminal navigation utilities</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/05/ttscoffbashprompt.jpg?9d7bd4" alt="Bash prompt screenshot" title="Bash prompt" width="245" height="148" class="alignright size-full wp-image-2365 shadow" />If you follow me <a href="https://twitter.com/#!/ttscoff">on Twitter</a>, you’ve probably seen me express my adoration for <a href="https://github.com/joelthelion/autojump">autojump</a>, a command-line utility for navigating frequently-used folders. The only problem is that I deal with a lot of repetitive folder hierarchies; for example, the multiple site structures in my web development folder. <code>j css</code> almost certainly isn’t going to take me to the one I was thinking of.</p>

<p>I found a couple of solutions this morning. There’s a package called <code>cdargs</code> which lets you bookmark folders with short names, autocomplete bookmarks, use bookmarks in copy and move actions and list and visually select from all of your bookmarks. I had some conflicts on my system that prevented me from using it, though, so I went with a simpler solution: <a href="http://www.huyng.com/bashmarks-directory-bookmarks-for-the-shell/">bashmarks</a> by Huy Nguyen.</p>

<p>Bashmarks lets me do most of what cdargs can do, but with a few less frills (and no conflicts with my setup). I can bookmark the css folder in my blog development folder <code>btcss</code>, and one in a client folder as <code>clientcss</code> and be able to quickly jump to the right one. Bashmarks provides autocomplete, too, so typing <code>g bt[tab]</code> gets me to btcss in a jiffy.</p>

<p>On the way, I also discovered a package called <a href="https://github.com/rupa/z">z</a>, which bills itself as “the new j” (in reference to autojump). It takes multiple arguments and uses them to more specifically match the folder you want to jump to. So, if I have a css folder in /brettterpstra/ and in /myclientsite/, I could type <code>z brett css</code> or <code>z client css</code> to distinguish between them. I haven’t bothered with replacing autojump in my config files yet, but this looks promising.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/' rel='bookmark' title='Quick Tip: throttling parallel batch processes in Terminal'>Quick Tip: throttling parallel batch processes in Terminal</a></li>
<li><a href='http://brettterpstra.com/quick-link-historio-us/' rel='bookmark' title='Quick Link: historio.us'>Quick Link: historio.us</a></li>
<li><a href='http://brettterpstra.com/filesystem-navigation-with-textexpander/' rel='bookmark' title='Filesystem navigation with TextExpander'>Filesystem navigation with TextExpander</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-link-terminal-navigation-utilities/">Quick Link: Terminal navigation utilities</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-link-terminal-navigation-utilities/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quick Tip: throttling parallel batch processes in Terminal</title>
		<link>http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/</link>
		<comments>http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/#comments</comments>
		<pubDate>Fri, 20 May 2011 08:47:12 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[quicktip]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2334</guid>
		<description><![CDATA[<p>Quick tips are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize. It starts out with mdfind and all of the creative scripting you can do with it. You start finding batches of files with something in common and you do things with&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/">Quick Tip: throttling parallel batch processes in Terminal</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/05/parallel_clipart.jpg?9d7bd4" class="alignright shadow" alt="Parallel Planes ClipartIt" /><em><a href="http://brettterpstra.com/tag/quicktip/">Quick tips</a> are random posts regarding something I discovered on my way to something bigger. They usually get longer than “quick” would imply, for which I refuse to apologize.</em></p>

<p>It starts out with <a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/mdfind.1.html">mdfind</a> and all of the <a href="http://www.tuaw.com/2008/02/15/terminal-tips-creating-a-spotlight-based-gallery/">creative scripting</a> you can do with it. You start finding batches of files with something in common and you do things with them or to them. It sounds genocidal; it’s not. It’s very productive after the initial script setup.</p>

<p>Take, for example, a little script I run to add thumbnails to weblocs I have laying around. It looks something like this:</p>


<div class="wp_syntax"><div class="code"><pre class="bash">mdfind <span class="re5">-onlyin</span> ~<span class="sy0">/</span>Dropbox<span class="sy0">/</span>Sync<span class="sy0">/</span>Bookmark<span class="sy0">/</span> \
<span class="st_h">'(! ( ((kMDItemOMUserTags == &quot;*donotthumbnail*&quot;cd) \
|| (kOMUserTags == &quot;*donotthumbnail*&quot;cd) ) ) \
&amp;&amp; (kMDItemFSHasCustomIcon = &quot;0&quot;) \
&amp;&amp; (kMDItemContentType == &quot;*webloc*&quot;cd))'</span> <span class="sy0">|</span> <span class="kw1">while</span> <span class="kw2">read</span> <span class="kw2">file</span>; \
<span class="kw1">do</span> <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin<span class="sy0">/</span>setWeblocThumb <span class="st0">&quot;<span class="es2">$file</span>&quot;</span> ; <span class="kw1">done</span></pre></div></div>


<p>It’s a one-liner, you’d want to reassemble it to run it (remove the backslashes at the line ends and join them all together), but it uses mdfind to search my shared bookmarks folder for recent items which don’t already have a custom thumbnail, passes them to <a href="http://hasseg.org/setWeblocThumb/">setWeblocThumb</a> and processes them… one at a time. I know my machine and my bandwidth can handle more than that, but if the list is 50+ long, that’s a lot of processes doing some relatively intensive labor. It would grind my machine to a halt. Yes, I tried it just to be sure.</p>

<p>So I needed a way to throttle the number of simultaneous processes, and I know that someone out there must have long beat me to the solution. There it was: <a href="http://pebblesinthesand.wordpress.com/2008/05/22/a-srcipt-for-running-processes-in-parallel-in-bash/">parallel</a>. It’s a script you can download and make executable in your path, and then run it with a few parameters and a batch of files or arguments. It will keep your defined number of processes going until the job is done, but won’t let things get out of hand. You can add <code>nice</code> (<a href="http://man.cx/nice">man page</a>) in each process if you need more cpu control over the process.</p>

<p>My new command looks like:</p>


<div class="wp_syntax"><div class="code"><pre class="bash">mdfind <span class="re5">-onlyin</span> <span class="sy0">/</span>Users<span class="sy0">/</span>ttscoff<span class="sy0">/</span>Dropbox<span class="sy0">/</span>Sync<span class="sy0">/</span>Bookmark<span class="sy0">/</span> \
<span class="st_h">'(! ( ((kMDItemOMUserTags == &quot;*donotthumbnail*&quot;cd) \
|| (kOMUserTags == &quot;*donotthumbnail*&quot;cd) ) ) \
&amp;&amp; (kMDItemFSHasCustomIcon = &quot;0&quot;) \
&amp;&amp; (kMDItemContentType == &quot;*webloc*&quot;cd))'</span><span class="sy0">|</span> parallel <span class="re5">-j</span> <span class="nu0">8</span> <span class="re5">-r</span> <span class="st0">&quot;/usr/local/bin/setWeblocThumb&quot;</span></pre></div></div>


<p>Seriously, if you’re doing anything in batch you should <a href="http://pebblesinthesand.wordpress.com/2008/05/22/a-srcipt-for-running-processes-in-parallel-in-bash/">check Parallel out</a>, or show me an even better one. Parallel made my morning, and by keeping CPU from maxing I actually got through some batches even faster. I’m sure there are other elegant ways of handling this. Let ‘em rip.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/geeklet-top-ram-processes/' rel='bookmark' title='Geeklet: Top RAM Processes'>Geeklet: Top RAM Processes</a></li>
<li><a href='http://brettterpstra.com/geeklet-top-cpu-processes/' rel='bookmark' title='Geeklet: Top CPU processes'>Geeklet: Top CPU processes</a></li>
<li><a href='http://brettterpstra.com/a-bash-function-for-markdown-bloggers/' rel='bookmark' title='A Bash function for Markdown bloggers'>A Bash function for Markdown bloggers</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/">Quick Tip: throttling parallel batch processes in Terminal</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-throttling-parallel-batch-processes-in-terminal/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automated HTML5 video encoding revisited</title>
		<link>http://brettterpstra.com/automated-html5-video-encoding-revisited/</link>
		<comments>http://brettterpstra.com/automated-html5-video-encoding-revisited/#comments</comments>
		<pubDate>Sun, 01 May 2011 15:21:51 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2285</guid>
		<description><![CDATA[<p>A little while ago I approached the subject of scripting automated encoding for HTML5 video formats. I started using the process regularly as I built the Blogsmith Bundle video site. Pretty soon I got some help from friend and TUAW editor Mike Rose, and working together we refined the script and improved the speed tremendously. It was built for use&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/automated-html5-video-encoding-revisited/">Automated HTML5 video encoding revisited</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/05/html5automatorTV-small.jpg?9d7bd4" alt="HTML5 Automator" title="HTML5 Automator" width="328" height="257" class="alignright size-full wp-image-2296" />A little while ago I approached the subject of scripting <a href="http://brettterpstra.com/automating-html5-video-encodes/">automated encoding for HTML5 video formats</a>. I started using the process regularly as I built the <a href="http://bundle.weblogzinc.com/video/">Blogsmith Bundle video site</a>. Pretty soon I got some help from friend and TUAW editor <a href="http://www.tuaw.com/bloggers/michael-rose">Mike Rose</a>, and working together we refined the script and improved the speed tremendously. It was built for use on Mac OS X, but with just a few lines modified, it should work on any *NIX system.
<span id="more-2285"></span></p>

<h3>What it does</h3>

<p>The script is specifically designed to take an MPEG-4, H.264 file, move it to a new folder based on the filename, create WEBM and OGV versions of it in the new folder, and upload the whole folder to a server using <code>rsync</code>. SSH information and target directories are specified in the config at the top of the script. At the end, it takes what it knows about the files and filenames and creates a TextMate Markdown blog template, inserts the video shortcode for the <a href="http://wordpress.org/extend/plugins/videojs-html5-video-player-for-wordpress/">VideoJS WordPress plugin</a> (which is common syntax for other plugins as well) and opens it for editing in TextMate. The <code>rsync</code> command really needs <a href="http://www.rootsilver.com/2007/10/keyless-ssh-sshkeygen-setup-an">keyless SSH login</a> for this to be considered fully-automated.</p>

<p>If you run this script with <a href="http://www.noodlesoft.com/hazel.php">Hazel</a>, you can just render an <a href="http://en.wikipedia.org/wiki/H.264">H.264</a> video (<code>.mov</code> files that pass the H.264 test<sup id="fnref:fnh264"><a href="#fn:fnh264" rel="footnote">1</a></sup> will automatically be renamed to <code>.mp4</code>) to that folder from your screen-recording application of choice, sit back for a few minutes (or start writing the post) and wait for the pre-populated TextMate blog post to pop open. Then type or paste your text in, hit Control-Command-P (assuming you’re set up for TextMate-&gt;WordPress blogging) and your video is posted.</p>

<h3>Improvements</h3>

<p>The first thing that happened in this rewrite was a major simplification of the WEBM encoding process, which now only takes a third of the time it did before and the files are not significantly larger in most cases. They may even look better. The old command involved two passes, one of them turning out to be unnecessary; <code>ffmpeg</code> is smarter than I thought. The new command (using the variables from the script) is just <code>/usr/local/bin/ffmpeg -i "$FILENAME" -b 614400 -s $MAXSIZE -aspect 16:9 "$BASENAME".webm</code>.</p>

<p>I also added better logging, optional progress reports with <a href="http://growl.info/">Growl</a>, batch file handling and a few other refinements. The logging, if enabled in the config at the top, will output information including processing time for each file and total processing time to STDOUT (command line) and to the system log where you can watch it from Console. If you enable growl notifications, the messages at the beginning and end of each conversion will be “growled” on your screen.</p>

<h3>Using the script</h3>

<p>You’ll need a couple of additional utilities to do the conversions.</p>

<h4>Requirements</h4>

<p>To run the script and do the encoding, you’ll need <code>ffmpeg</code> and <code>ffmpeg2theora</code>. You can install <code>ffmpeg</code> from <a href="https://github.com/mxcl/homebrew">Homebrew</a> (<code>brew install ffmpeg</code>) quite easily, if you’re set up for that. You can also pull the binary out of <a href="http://www.ffmpegx.com/">ffmpegX</a> with a <a href="http://hints.macworld.com/article.php?story=20061220082125312">few simple steps</a>. You can, of course, <a href="http://troykelly.com/2007/01/18/building-ffmpeg-on-os-x/">build your own</a> if you have the developer tools installed.</p>

<p>ffmpeg2theora (needed for OGV conversion) no longer appears to be available from <code>brew</code>, but there are OS X binaries (and source) <a href="http://v2v.cc/~j/ffmpeg2theora/download.html">available for download</a>.</p>

<p>The <a href="#thescript">script is below</a>. You’ll want to modify the information in the configuration section at the top, and modify the template output at the bottom to suit your needs. Anything between <code>&lt;&lt;-POSTTEMPLATE</code> and <code>POSTTEMPLATE</code> is freeform text that you can edit in any way you like, including the use of $variables. If you’d rather do something such as copy a shortcode to your clipboard and show a Growl message, just use <code>pbcopy</code> and <code>growlnotify</code>. You could also just comment out the template part and let Hazel tell you when it’s done, if you want to handle things more manually. I’ll let you work out the details on that.</p>

<h4>Command line usage</h4>

<p>To use the script from the command line, save it as “html5encode.sh” somewhere in your path, change to its parent folder in Terminal and run <code>chmod a+x html5encode.sh</code>. The you can run it on any h.264 .mov or .mp4 file and it will handle the rest. It also handles batches, so you can specify multiple targets or use <code>*.mp4</code> to run it on all .mp4 files in a folder. It will process them one by one, creating new folders for each.</p>

<h4>Hazel</h4>

<p>If you want to run it with Hazel, you can follow the same procedure and set up a rule that runs a shell script when a .mov or .mp4 is detected in a watch folder. The script can then be run as a command or be pasted in its entirety into the Hazel script editor within the rule.</p>

<p>You should be able to pull off using this with OS X Folder Actions, as well, but I haven’t played with that yet.</p>

<p><strong>Bonus tip:</strong> <em>If you name your original .mov or .mp4 file with a CamelCased name, it will break apart the filename and create the title of your post based on it. Not an essential feature, but kind of nifty. Well, I think so anyway.</em></p>

<h3 id="thescript">The script</h3>

<p><a href="http://brettterpstra.com/share/html5encode.sh.txt">View Raw</a> | <a href="http://brettterpstra.com/share/html5encode.sh">Download</a></p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0">#!/bin/bash</span>
<span class="co0">#################################################################</span>
<span class="co0">### html5encode.sh by Brett Terpstra and Mike Rose</span>
<span class="co0">### Published 05/01/2011</span>
<span class="co0">### Freely distributed, modifications welcomed (with attribution)</span>
<span class="co0">#################################################################</span>
<span class="co0">### Configuration ###############################################</span>
<span class="co0">#################################################################</span>
<span class="re2">MAXSIZE</span>=<span class="st0">&quot;960x540&quot;</span>
<span class="re2">DISPLAYWIDTH</span>=<span class="st0">&quot;600&quot;</span>
<span class="re2">DISPLAYHEIGHT</span>=<span class="st0">&quot;338&quot;</span>
<span class="re2">SSHURL</span>=<span class="st0">&quot;username@ssh.host.name&quot;</span>
<span class="re2">SSHDIR</span>=<span class="st0">&quot;/server/folder/target/for/rsync/&quot;</span>
<span class="re2">WEBDIR</span>=<span class="st0">&quot;/front-end/url/path/video/&quot;</span> <span class="co0"># used for blog template</span>
<span class="re2">LOGGING</span>=<span class="kw2">true</span> <span class="co0"># send status messages and times to STDOUT and syslog</span>
<span class="re2">GROWLLOG</span>=<span class="kw2">false</span> <span class="co0"># duplicate messages to growl, if installed</span>
<span class="co0">##################################################################</span>
<span class="co0">### END Configuration ############################################</span>
<span class="co0">##################################################################</span>
&nbsp;
<span class="co0"># function to handle logging (if enabled) to STDOUT and STDERR </span>
<span class="co0"># as well as Growl (if enabled)</span>
<span class="kw1">function</span> logit<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="re1">$LOGGING</span> ; <span class="kw1">then</span>
    logger <span class="re5">-st</span> <span class="st0">&quot;HTML5 Encoder&quot;</span> <span class="st0">&quot;$1&quot;</span>
    <span class="kw1">if</span> <span class="re1">$GROWLLOG</span> ; <span class="kw1">then</span>
      <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin<span class="sy0">/</span>growlnotify <span class="re5">-t</span> <span class="st0">&quot;HTML5 Encoder&quot;</span> <span class="re5">-a</span> <span class="st0">&quot;Terminal&quot;</span> <span class="re5">-m</span> <span class="st0">&quot;$1&quot;</span>
    <span class="kw1">fi</span>
  <span class="kw1">fi</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co0"># Count the inputs for log message</span>
<span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re4">$#</span> <span class="re5">-gt</span> <span class="nu0">1</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
  logit <span class="st0">&quot;Starting batch conversion.&quot;</span>
  <span class="re2">maintimer1</span>=<span class="sy0">`</span><span class="kw2">date</span> <span class="st_h">'+%s'</span><span class="sy0">`</span>
<span class="kw1">else</span>
  logit <span class="st0">&quot;Starting HTML5 Encoder&quot;</span>
<span class="kw1">fi</span>
&nbsp;
<span class="co0"># Loop through each passed file</span>
<span class="kw1">for</span> <span class="kw2">file</span> <span class="kw1">in</span> <span class="st0">&quot;$@&quot;</span>; <span class="kw1">do</span>
  <span class="re2">timer1</span>=<span class="sy0">`</span><span class="kw2">date</span> <span class="st_h">'+%s'</span><span class="sy0">`</span>
  <span class="re2">INPUT</span>=<span class="re1">$file</span>
  <span class="co0"># Check that input file is H.264</span>
  <span class="re2">isH264</span>=<span class="sy0">`</span>mdls <span class="re5">-raw</span> <span class="re5">-name</span> kMDItemCodecs <span class="re1">$INPUT</span><span class="sy0">|</span><span class="kw2">grep</span> H.264<span class="sy0">`</span>
&nbsp;
  <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="sy0">!</span><span class="re1">$isH264</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span>
    logit <span class="st0">&quot;<span class="es2">$INPUT</span> is not h.264&quot;</span>
    <span class="kw3">continue</span>
  <span class="kw1">fi</span>
&nbsp;
  <span class="re2">DIRNAME</span>=<span class="sy0">`</span><span class="kw2">dirname</span> <span class="st0">&quot;<span class="es2">$INPUT</span>&quot;</span><span class="sy0">`</span>
  <span class="re2">FILENAME</span>=<span class="sy0">`</span><span class="kw2">basename</span> <span class="st0">&quot;<span class="es2">$INPUT</span>&quot;</span><span class="sy0">`</span>
  <span class="re2">BASENAME</span>=<span class="co1">${FILENAME%%.*}</span>
  logit <span class="st0">&quot;Conversion of <span class="es2">$FILENAME</span> started on <span class="es5">`date '+%D'`</span> at <span class="es5">`date '+%r'`</span>&quot;</span>
  <span class="re2">bytesize</span>=<span class="sy0">`</span><span class="kw2">stat</span> <span class="re5">-f</span> <span class="st_h">'%z'</span> <span class="re1">$FILENAME</span><span class="sy0">`</span>
  <span class="re2">filesize</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;scale = 2 ; <span class="es2">$bytesize</span>/1048576&quot;</span><span class="sy0">|</span><span class="kw2">bc</span> -lq<span class="sy0">`</span>
  <span class="kw3">cd</span> <span class="st0">&quot;<span class="es2">$DIRNAME</span>&quot;</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re5">-d</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
    logit <span class="st0">&quot;Found <span class="es2">$FILENAME</span>, but directory <span class="es2">$BASENAME</span> already exists. Aborting&quot;</span>
    <span class="kw3">continue</span>
  <span class="kw1">fi</span>
  <span class="kw2">mkdir</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span>
  <span class="kw2">mv</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>/&quot;</span>
  <span class="kw3">cd</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="co1">${FILENAME#*.}</span> <span class="re5">-eq</span> <span class="st0">&quot;mov&quot;</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span> <span class="kw2">mv</span> <span class="re1">$FILENAME</span> <span class="co1">${BASENAME}</span>.mp4; <span class="kw1">fi</span>  
  <span class="re2">FILENAME</span>=<span class="co1">${BASENAME}</span>.mp4
  <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin<span class="sy0">/</span><span class="kw2">ffmpeg</span> <span class="re5">-i</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-b</span> <span class="nu0">614400</span> <span class="re5">-s</span> <span class="re1">$MAXSIZE</span> <span class="re5">-aspect</span> <span class="nu0">16</span>:<span class="nu0">9</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span>.webm
  logit <span class="st0">&quot;Completed webm conversion&quot;</span>
  <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin<span class="sy0">/</span>ffmpeg2theora <span class="re5">--videoquality</span> <span class="nu0">5</span> <span class="re5">--audioquality</span> <span class="nu0">1</span> --max_size <span class="re1">$MAXSIZE</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-o</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>.ogv&quot;</span>
  logit <span class="st0">&quot;Completed ogv conversion&quot;</span>
  <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin<span class="sy0">/</span><span class="kw2">ffmpeg</span> <span class="re5">-i</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-ss</span> <span class="nu0">0</span> <span class="re5">-vframes</span> <span class="nu0">1</span> <span class="re5">-vcodec</span> mjpeg <span class="re5">-f</span> image2 <span class="st0">&quot;<span class="es3">${BASENAME}</span>Poster.jpg&quot;</span>
  logit <span class="st0">&quot;Created poster image&quot;</span>
&nbsp;
  <span class="co0"># Create a title from camelcased filename</span>
  <span class="re2">TITLE</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/\([A-Z][^A-Z]*\)/&amp; /g'</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/ $//'</span><span class="sy0">`</span>
  <span class="re2">SERVER</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;<span class="es2">$SSHURL</span>&quot;</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/^.*\@//'</span><span class="sy0">`</span>
  logit <span class="st0">&quot;Uploading to <span class="es2">$SERVER</span>...&quot;</span>
  <span class="kw3">cd</span> ..
  rsync <span class="re5">-v</span> <span class="re5">-r</span> <span class="re5">-e</span> <span class="kw2">ssh</span> <span class="st0">&quot;<span class="es5">`pwd`</span>/<span class="es2">$BASENAME</span>&quot;</span> <span class="re1">$SSHURL</span>:<span class="re1">$SSHDIR</span>
  logit <span class="st0">&quot;Finished Uploading&quot;</span>
  <span class="co0"># remove trailing slash from $WEBDIR</span>
  <span class="re2">WEBDIR</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;<span class="es2">$WEBDIR</span>&quot;</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/\/$//'</span><span class="sy0">`</span>
  <span class="kw2">cat</span> <span class="sy0">&gt;</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>/<span class="es2">$BASENAME</span>.blog.markdown&quot;</span> <span class="co2">&lt;&lt;-POSTTEMPLATE
Type: Blog Post (Markdown)
Blog: BlogsmithVideo
Title: $TITLE
Keywords: 
Status: draft
Pings: On
Comments: On
Category: Tutorial
&nbsp;
Synopsis
&nbsp;
[video mp4=&quot;$WEBDIR/$BASENAME/$BASENAME.mp4&quot; ogg=&quot;$WEBDIR/$BASENAME/$BASENAME.ogv&quot; webm=&quot;$WEBDIR/$BASENAME/$BASENAME.webm&quot; poster=&quot;$WEBDIR/$BASENAME/${BASENAME}Poster.jpg&quot; preload=&quot;true&quot; width=&quot;$DISPLAYWIDTH&quot; height=&quot;$DISPLAYHEIGHT&quot;]
&nbsp;
&lt;!--more--&gt;
Transcript
&nbsp;
POSTTEMPLATE</span>
&nbsp;
  open <span class="st0">&quot;<span class="es2">$BASENAME</span>/<span class="es2">$BASENAME</span>.blog.markdown&quot;</span> <span class="re5">-a</span> <span class="st0">&quot;TextMate.app&quot;</span>
  <span class="re2">timer2</span>=<span class="sy0">`</span><span class="kw2">date</span> <span class="st_h">'+%s'</span><span class="sy0">`</span>
  <span class="re2">time</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;scale=2 ; (<span class="es2">$timer2</span>-<span class="es2">$timer1</span>)/60&quot;</span><span class="sy0">|</span><span class="kw2">bc</span> -lq<span class="sy0">`</span>
  logit <span class="st0">&quot;Conversion of <span class="es2">$FILENAME</span> complete&quot;</span>
  logit <span class="st0">&quot;It took <span class="es2">$time</span> minutes to process a <span class="es3">${filesize}</span>M MP4 to webm and ogv and upload to <span class="es5">`echo &quot;$SSHURL&quot;|sed 's/^.*\@//'`</span>.&quot;</span>
<span class="kw1">done</span>
<span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re4">$#</span> <span class="re5">-gt</span> <span class="nu0">1</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
  <span class="re2">maintimer2</span>=<span class="sy0">`</span><span class="kw2">date</span> <span class="st_h">'+%s'</span><span class="sy0">`</span>
  <span class="re2">total</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="st0">&quot;scale=2 ; (<span class="es2">$maintimer2</span>-<span class="es2">$maintimer1</span>)/60&quot;</span><span class="sy0">|</span><span class="kw2">bc</span> -lq<span class="sy0">`</span>
  logit <span class="st0">&quot;Batch conversion complete, total time <span class="es2">$total</span> minutes.&quot;</span>
<span class="kw1">fi</span></pre></div></div>


<p>Hopefully this will make a few people’s lives easier. Mike and I have battle tested it and it seems to be a pretty great fit for our needs. If you modify it for your own needs, please share (with credit) so that it can become as well-rounded as possible!</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:fnh264">
<p>The script runs a quick check using <code>mdls</code> to look for the h.264 codec. It will skip the file if it doesn’t match the criteria. It doesn’t check for AAC, but assumes that you know what you’re doing to <em>some</em> extent. If you’re running Hazel, just check for the specific extension you’re rendering to (<code>.mov</code> or <code>.mp4</code>) to avoid any hassle from the start. <a href="#fnref:fnh264" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/automating-html5-video-encodes/' rel='bookmark' title='Automating HTML5 video encodes'>Automating HTML5 video encodes</a></li>
<li><a href='http://brettterpstra.com/seriously-easy-html5-video-encoding/' rel='bookmark' title='Seriously easy HTML5 video encoding'>Seriously easy HTML5 video encoding</a></li>
<li><a href='http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/' rel='bookmark' title='oft: Bash function for opening a specific filetype'>oft: Bash function for opening a specific filetype</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/automated-html5-video-encoding-revisited/">Automated HTML5 video encoding revisited</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/automated-html5-video-encoding-revisited/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Address Book search and Skype from the command line</title>
		<link>http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/</link>
		<comments>http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/#comments</comments>
		<pubDate>Wed, 13 Apr 2011 12:12:24 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[skype]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2195</guid>
		<description><![CDATA[<p>Here’s a neat little command-line utility for searching your address book: aboo. It’s not complex… it just takes a single word or phrase and searches your Address Book entries’ names for it. It can output vcards and YAML, too. I created a fork that adds a few things, most importantly I extended search to business names and notes. It also&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/">Address Book search and Skype from the command line</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/04/oldphone.jpg?9d7bd4" class="alignright" />Here’s a neat little command-line utility for searching your address book: <a href="https://github.com/chneeb/aboo">aboo</a>. It’s not complex… it just takes a single word or phrase and searches your Address Book entries’ names for it. It can output vcards and YAML, too. I created a <a href="https://github.com/ttscoff/aboo">fork</a> that adds a few things, most importantly I extended search to business names and notes. It also does a better job of realizing there’s no proper name and substituting the Company name in the output, if it exists. There’s a <a href="https://github.com/downloads/ttscoff/aboo/aboo-ttscoff-1.0.zip">compiled binary of my fork</a> on GitHub, too. Just put it in <code>/usr/local/bin</code> and run <code>aboo -h</code> to see the options.</p>

<p>So, I’m toying with that this morning and I get a sudden urge to be able to make a Skype phone call from the command line. I added a –p flag to <code>aboo</code> which only returns entries which have a phone number. A little <code>awk</code> on the output, and you can get a menu of people to send straight to a function that can call them with Skype. I’ll skip the middle part for now, but here’s a bash function for dialing a number. It accepts multiple formats of strings and tries to turn it into a standardized format for Skype (+15554321111). Usage: <code>skype 5555551111</code> or <code>skype "(555) 555 5124"</code> (it will strip the extra characters, makes it easier to paste and dial quickly).</p>


<div class="wp_syntax"><div class="code"><pre class="bash">skype <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re2">number</span>=<span class="sy0">`</span><span class="kw3">echo</span> <span class="re4">$1</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/[\(\)\+ \-]//g'</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/^1//'</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/^/+1/'</span><span class="sy0">`</span>
  osascript <span class="re5">-e</span> <span class="st0">&quot;tell application <span class="es1">\&quot;</span>Skype<span class="es1">\&quot;</span> to send command <span class="es1">\&quot;</span>CALL <span class="es2">$number</span><span class="es1">\&quot;</span> script name <span class="es1">\&quot;</span>CLIDIALER<span class="es1">\&quot;</span>&quot;</span>
<span class="br0">&#125;</span></pre></div></div>


<p>I normally make most of my Skype calls from LaunchBar, but this will come in handy every once in a while when I’m already working in Terminal. Thought it might be handy for someone else, too.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/answer-skype-with-a-hotkey/' rel='bookmark' title='Answer Skype with a hotkey'>Answer Skype with a hotkey</a></li>
<li><a href='http://brettterpstra.com/sms-from-the-command-line-with-google-voice/' rel='bookmark' title='SMS from the command line with Google Voice'>SMS from the command line with Google Voice</a></li>
<li><a href='http://brettterpstra.com/quick-tip-this-command-line-trick-is-tops/' rel='bookmark' title='Quick Tip: This command line trick is tops'>Quick Tip: This command line trick is tops</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/">Address Book search and Skype from the command line</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SMS from the command line with Google Voice</title>
		<link>http://brettterpstra.com/sms-from-the-command-line-with-google-voice/</link>
		<comments>http://brettterpstra.com/sms-from-the-command-line-with-google-voice/#comments</comments>
		<pubDate>Sat, 20 Nov 2010 05:54:41 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[google voice]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1344</guid>
		<description><![CDATA[<p>I needed a script send an SMS today, and I found a very handy post at sudocode to send one via Google Voice, using PHP. I wanted to make it a little more command-line-friendly, so I rewrote it (ham-handedly) in Ruby and added some options parsing to it. It’s designed for—and only tested on—OS X, but may work fine elsewhere.&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/sms-from-the-command-line-with-google-voice/">SMS from the command line with Google Voice</a></p>]]></description>
			<content:encoded><![CDATA[<p>I needed a script send an SMS today, and I found a very <a href="http://sudocode.net/article/66/sending-a-google-voice-sms-using-php/">handy post at sudocode</a> to send one via <a href="https://www.google.com/voice/">Google Voice</a>, using PHP. I wanted to make it a little more command-line-friendly, so I rewrote it (ham-handedly) in Ruby and added some options parsing to it. It’s designed for—and only tested on—OS X, but may work fine elsewhere.</p>

<p><span id="more-1344"></span></p>

<h3>The code</h3>

<p>To use it, copy the code below into a text file, save it as voicesms.rb (or download it directly using the link at the top of the code), and run <code>chmod a+x voicesms.rb</code> from the command line to make it executable.</p>

<div class="collapse">


<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="co1">#!/usr/bin/env ruby -rjcode -Ku</span>
&nbsp;
<span class="kw3">require</span> <span class="st0">'net/http'</span>
<span class="kw3">require</span> <span class="st0">'net/https'</span>
<span class="kw3">require</span> <span class="st0">'open-uri'</span>
<span class="kw3">require</span> <span class="st0">'cgi'</span>
<span class="kw3">require</span> <span class="st0">'optparse'</span>
&nbsp;
ACCOUNT = <span class="st0">''</span> <span class="co1"># Set to Google Voice account email for default account</span>
PASSWORD = <span class="st0">''</span> <span class="co1"># Set to Google Voice account password for default account</span>
NUMBERS = <span class="br0">&#91;</span><span class="st0">'+1555444333'</span>,<span class="st0">'+1555444222'</span><span class="br0">&#93;</span> <span class="co1"># Set one or more numbers for default destination(s)</span>
&nbsp;
options = <span class="br0">&#123;</span><span class="br0">&#125;</span>
optparse = OptionParser.<span class="me1">new</span> <span class="kw1">do</span><span class="sy0">|</span>opts<span class="sy0">|</span>
  opts.<span class="me1">banner</span> = <span class="st0">&quot;Usage: voicesms.rb -n +15554443333[,+15554442222] -m <span class="es0">\&quot;</span>Message to send<span class="es0">\&quot;</span> [-u Username:Password]&quot;</span>
&nbsp;
  options<span class="br0">&#91;</span><span class="re3">:numbers</span><span class="br0">&#93;</span> = NUMBERS
  opts.<span class="me1">on</span><span class="br0">&#40;</span> <span class="st0">'-n'</span>, <span class="st0">'--numbers NUM[,NUM]'</span>, <span class="st0">'Phone numbers to SMS (separate multiples with comma)'</span> <span class="br0">&#41;</span> <span class="kw1">do</span><span class="sy0">|</span>numbers<span class="sy0">|</span>
    options<span class="br0">&#91;</span><span class="re3">:numbers</span><span class="br0">&#93;</span> = numbers.<span class="kw3">split</span><span class="br0">&#40;</span><span class="st0">','</span><span class="br0">&#41;</span>
  <span class="kw1">end</span>
&nbsp;
  options<span class="br0">&#91;</span><span class="re3">:message</span><span class="br0">&#93;</span> = <span class="kw2">false</span>
  opts.<span class="me1">on</span><span class="br0">&#40;</span> <span class="st0">'-m'</span>, <span class="st0">'--message MESSAGE'</span>, <span class="st0">'Message to send'</span> <span class="br0">&#41;</span> <span class="kw1">do</span><span class="sy0">|</span>msg<span class="sy0">|</span>
    options<span class="br0">&#91;</span><span class="re3">:message</span><span class="br0">&#93;</span> = msg
  <span class="kw1">end</span>
&nbsp;
   options<span class="br0">&#91;</span><span class="re3">:username</span><span class="br0">&#93;</span> = ACCOUNT
   options<span class="br0">&#91;</span><span class="re3">:password</span><span class="br0">&#93;</span> = PASSWORD
   opts.<span class="me1">on</span><span class="br0">&#40;</span> <span class="st0">'-u'</span>, <span class="st0">'--user USERNAME:PASSWORD'</span>, <span class="st0">'Google Voice username and password'</span> <span class="br0">&#41;</span> <span class="kw1">do</span><span class="sy0">|</span>creds<span class="sy0">|</span>
     parts = creds.<span class="kw3">split</span><span class="br0">&#40;</span><span class="st0">':'</span><span class="br0">&#41;</span>
     options<span class="br0">&#91;</span><span class="re3">:username</span><span class="br0">&#93;</span> = parts<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>
     options<span class="br0">&#91;</span><span class="re3">:password</span><span class="br0">&#93;</span> = parts<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>
   <span class="kw1">end</span>
&nbsp;
  opts.<span class="me1">on</span><span class="br0">&#40;</span> <span class="st0">'-h'</span>, <span class="st0">'--help'</span>, <span class="st0">'Display this screen'</span> <span class="br0">&#41;</span> <span class="kw1">do</span>
    <span class="kw3">puts</span> opts
    <span class="kw3">exit</span>
  <span class="kw1">end</span>
<span class="kw1">end</span>
&nbsp;
optparse.<span class="me1">parse</span>!
&nbsp;
<span class="kw1">unless</span> options<span class="br0">&#91;</span><span class="re3">:message</span><span class="br0">&#93;</span>
  <span class="kw3">puts</span> <span class="st0">&quot;Message required. Use -m <span class="es0">\&quot;</span>MESSAGE<span class="es0">\&quot;</span>.&quot;</span>
  <span class="kw3">puts</span> <span class="st0">&quot;Enter `voicesms.rb -h` for help.&quot;</span>
  <span class="kw3">exit</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> postit<span class="br0">&#40;</span>uri_str, data, header = <span class="kw2">nil</span>, limit = <span class="nu0">3</span><span class="br0">&#41;</span>
    <span class="kw3">raise</span> <span class="kw4">ArgumentError</span>, <span class="st0">'HTTP redirect too deep'</span> <span class="kw1">if</span> limit == <span class="nu0">0</span>
    url = <span class="kw4">URI</span>.<span class="me1">parse</span><span class="br0">&#40;</span>uri_str<span class="br0">&#41;</span>
    http = <span class="re2">Net::HTTP</span>.<span class="me1">new</span><span class="br0">&#40;</span>url.<span class="me1">host</span>,<span class="nu0">443</span><span class="br0">&#41;</span>
    http.<span class="me1">use_ssl</span> = <span class="kw2">true</span>
    http.<span class="me1">verify_mode</span> = <span class="re2">OpenSSL::SSL::VERIFY_NONE</span>
    response,content = http.<span class="me1">post</span><span class="br0">&#40;</span>url.<span class="me1">path</span>,data,header<span class="br0">&#41;</span>
    <span class="kw1">case</span> response
      <span class="kw1">when</span> <span class="re2">Net::HTTPSuccess</span>     <span class="kw1">then</span> content
      <span class="kw1">when</span> <span class="re2">Net::HTTPRedirection</span> <span class="kw1">then</span> postit<span class="br0">&#40;</span>response<span class="br0">&#91;</span><span class="st0">'location'</span><span class="br0">&#93;</span>,data,header, limit <span class="sy0">-</span> <span class="nu0">1</span><span class="br0">&#41;</span>
      <span class="kw1">else</span>
        <span class="kw3">puts</span> response.<span class="me1">inspect</span>
        response.<span class="me1">error</span>!
    <span class="kw1">end</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> getit<span class="br0">&#40;</span>uri_str, header, limit = <span class="nu0">3</span><span class="br0">&#41;</span>
    <span class="kw3">raise</span> <span class="kw4">ArgumentError</span>, <span class="st0">'HTTP redirect too deep'</span> <span class="kw1">if</span> limit == <span class="nu0">0</span>
    url = <span class="kw4">URI</span>.<span class="me1">parse</span><span class="br0">&#40;</span>uri_str<span class="br0">&#41;</span>
    http = <span class="re2">Net::HTTP</span>.<span class="me1">new</span><span class="br0">&#40;</span>url.<span class="me1">host</span>,url.<span class="me1">port</span><span class="br0">&#41;</span>
    http.<span class="me1">use_ssl</span> = <span class="kw2">true</span>
    http.<span class="me1">verify_mode</span> = <span class="re2">OpenSSL::SSL::VERIFY_NONE</span>
    response,content = http.<span class="me1">get</span><span class="br0">&#40;</span>url.<span class="me1">path</span>,header<span class="br0">&#41;</span>
    <span class="kw1">case</span> response
      <span class="kw1">when</span> <span class="re2">Net::HTTPSuccess</span>     <span class="kw1">then</span> content
      <span class="kw1">when</span> <span class="re2">Net::HTTPRedirection</span> <span class="kw1">then</span> getit<span class="br0">&#40;</span>response<span class="br0">&#91;</span><span class="st0">'location'</span><span class="br0">&#93;</span>,header, limit <span class="sy0">-</span> <span class="nu0">1</span><span class="br0">&#41;</span>
      <span class="kw1">else</span>
        response.<span class="me1">error</span>!
    <span class="kw1">end</span>
<span class="kw1">end</span>
&nbsp;
data = <span class="st0">&quot;accountType=GOOGLE&amp;Email=#{options[:username]}&amp;Passwd=#{options[:password]}&amp;service=grandcentral&amp;source=brettterpstra-CLISMS-2.0&quot;</span>
res = postit<span class="br0">&#40;</span><span class="st0">'https://www.google.com/accounts/ClientLogin'</span>,data<span class="br0">&#41;</span>
<span class="kw1">if</span> res
  authcode = res.<span class="me1">match</span><span class="br0">&#40;</span><span class="sy0">/</span>Auth=<span class="br0">&#40;</span>.<span class="sy0">+</span><span class="br0">&#41;</span><span class="sy0">/</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>
  header = <span class="br0">&#123;</span><span class="st0">'Authorization'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;GoogleLogin auth=#{authcode.strip}&quot;</span>,<span class="st0">'Content-Length'</span> <span class="sy0">=&gt;</span> <span class="st0">'0'</span><span class="br0">&#125;</span>
  newres = getit<span class="br0">&#40;</span><span class="st0">'https://www.google.com/voice'</span>,header<span class="br0">&#41;</span>
  <span class="kw1">if</span> newres
    rnrse = newres.<span class="me1">match</span><span class="br0">&#40;</span><span class="sy0">/</span><span class="st0">'_rnr_se'</span>: <span class="st0">'([^'</span><span class="br0">&#93;</span><span class="sy0">+</span><span class="br0">&#41;</span><span class="st0">'/)[1]
    options[:numbers].each {|num|
      data = &quot;_rnr_se=#{rnrse}&amp;phoneNumber=#{num.strip}&amp;text=#{CGI.escape(options[:message])}&amp;id=&quot;
      finalres = postit('</span>https:<span class="sy0">//</span>www.<span class="me1">google</span>.<span class="me1">com</span><span class="sy0">/</span>voice<span class="sy0">/</span>sms<span class="sy0">/</span>send<span class="sy0">/</span><span class="st0">',data,header)
      if finalres[&quot;ok&quot;]
        puts &quot;Message sent to #{num}&quot;
      else
        puts &quot;Error sending to #{num}&quot;
      end
    }
  else
    newres.error!
  end
else
  res.error!
end</span></pre></div></div>



</div>

<h3>Usage</h3>

<p>You can set default account name, password and send-to numbers at the top of the script. These can be overridden by command line options at runtime. The standard syntax is:</p>

<pre><code>voicesms.rb -n +15552525543,+15554342221 -m "The message to send" -u GVoiceUsername:GVoicePassword
</code></pre>

<p>Parameters can be in any order. The –n parameter takes one or more phone numbers in international format (+XX country code at the beginning, +1 for US numbers), separated by commas (no spaces).</p>

<p>The –m option (message) is required and can’t be set by default in the script. Just use –m “and a quoted message” and it will handle the rest.</p>

<p>–u defines a username/password combination for Google Voice. It’s probably most convenient to set these at the top of the script and ignore this parameter, but the option is there.</p>

<p>–h will provide the help information.</p>

<h4>Aliasing</h4>

<p>The point of the script is to let me automate SMS messages from my system, so its primary invocation will be from other scripts. However, it will function just fine as a command line texting utility, in which case you’d probably want to alias the core functions in your <code>.bash_profile</code>. Set your default username and password in the script, and maybe a default destination number. If you want to send to a different numbers, you might want to make several aliases which include different <code>-n #</code> parameters, one for each destination. The alias will look something like:</p>

<pre><code>alias sms="~/scripts/voicesms.rb -m"
</code></pre>

<p>Or, maybe:</p>

<pre><code>alias smsjohn="~/scripts/voicesms.rb -n +15554443333 -m"
</code></pre>

<p>Get it? Then you can just type <code>smsjohn "And your message"</code> to send the message straight to John. Whoever that is.</p>

<h3>What it does</h3>

<p>It’s pretty simple, just a series of POST and GET requests to the Google API. It uses Google’s client authentication to get an initial auth code. Then it uses the auth code to get an auth token. Then, it posts your information to the API with the proper headers (the auth token) to complete the call. All of your data is sent securely over SSL (https) connections.</p>

<p>Have fun!</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/single-keystroke-instapaper-in-google-reader/' rel='bookmark' title='Single-keystroke Instapaper in Google Reader'>Single-keystroke Instapaper in Google Reader</a></li>
<li><a href='http://brettterpstra.com/gvoice-command-line-sms-revisited/' rel='bookmark' title='GVoice command line SMS revisited'>GVoice command line SMS revisited</a></li>
<li><a href='http://brettterpstra.com/greader-instapaper-0-2/' rel='bookmark' title='GReader Instapaper 0.2'>GReader Instapaper 0.2</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/sms-from-the-command-line-with-google-voice/">SMS from the command line with Google Voice</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/sms-from-the-command-line-with-google-voice/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Things tasks from the command line</title>
		<link>http://brettterpstra.com/things-tasks-from-the-command-line/</link>
		<comments>http://brettterpstra.com/things-tasks-from-the-command-line/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 00:49:35 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[things]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1080</guid>
		<description><![CDATA[<p>If you’re a Things.app user (and a Terminal user), I’ve got a quick function for your .bash_profile that will allow you to quickly add todo items to your inbox with notes and natural-language date parsing. It uses php’s strtotime function, which does a pretty swell job with simple dates like “next tuesday” or “+12 days”. It’s not very smart, though;&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/things-tasks-from-the-command-line/">Things tasks from the command line</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/thingsicon.jpeg?9d7bd4" alt="thingsicon.jpeg" border="0" width="196" height="241" class="alignright" />If you’re a <a href="http://culturedcode.com/things/">Things.app</a> user (and a Terminal user), I’ve got a quick function for your .bash_profile that will allow you to quickly add todo items to your inbox with notes and natural-language date parsing.</p>

<p>It uses php’s strtotime function, which does a pretty swell job with simple dates like “next tuesday” or “+12 days”. It’s not very smart, though; you have to give it parameters in a specific order:</p>

<p><code>td "task name" "natural language date" "note"</code></p>

<p>Only the first parameter is required, so your task at least has a title. If you have two, it expects that the second is a date of some kind, and anything in the third will be added as a note.</p>

<p>Here’s the code…
<span id="more-1080"></span></p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw1">function</span> td<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$#</span> <span class="re5">-lt</span> <span class="nu0">1</span> <span class="br0">&#93;</span>; <span class="kw1">then</span> <span class="kw3">return</span> <span class="nu0">1</span>;<span class="kw1">fi</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$#</span> <span class="re5">-gt</span> <span class="nu0">1</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="re2">duedate</span>=<span class="sy0">`</span>php <span class="re5">-r</span> <span class="st0">&quot;date_default_timezone_set('America/Chicago');echo date('m/d/y',strtotime('$2'));&quot;</span><span class="sy0">`</span>
    <span class="re2">duedate</span>=<span class="st0">&quot;,due date:date <span class="es1">\&quot;</span><span class="es2">$duedate</span><span class="es1">\&quot;</span>&quot;</span>
  <span class="kw1">fi</span>
  osascript <span class="re5">-e</span> <span class="st0">&quot;tell application <span class="es1">\&quot;</span>Things<span class="es1">\&quot;</span>&quot;</span> \
  <span class="re5">-e</span> <span class="st0">&quot;make new to do at list <span class="es1">\&quot;</span>Inbox<span class="es1">\&quot;</span> with properties {name:<span class="es1">\&quot;</span>$1<span class="es1">\&quot;</span>,notes:<span class="es1">\&quot;</span>$3<span class="es1">\&quot;</span><span class="es2">$duedate</span>}&quot;</span> \
  <span class="re5">-e</span> <span class="st0">&quot;end tell&quot;</span>
<span class="br0">&#125;</span></pre></div></div>


<p>Just paste it at the end of your ~/.bash_profile and type <code>source ~/.bash_profile</code> to read it in. If you use it, I’d love to hear about it, and if you improve it, let me know what you did differently!</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/os-x-service-for-natural-language-dates/' rel='bookmark' title='OS X Service for natural language dates'>OS X Service for natural language dates</a></li>
<li><a href='http://brettterpstra.com/natural-language-dates-for-textexpander/' rel='bookmark' title='Natural language dates for TextExpander'>Natural language dates for TextExpander</a></li>
<li><a href='http://brettterpstra.com/a-simple-but-handy-bash-function-console/' rel='bookmark' title='A simple but handy Bash function: console'>A simple but handy Bash function: console</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/things-tasks-from-the-command-line/">Things tasks from the command line</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/things-tasks-from-the-command-line/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Is your URL too short? Try our system, free!</title>
		<link>http://brettterpstra.com/is-your-url-too-short-try-our-system-free/</link>
		<comments>http://brettterpstra.com/is-your-url-too-short-try-our-system-free/#comments</comments>
		<pubDate>Sat, 14 Aug 2010 15:00:05 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[experiments]]></category>
		<category><![CDATA[launchbar]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[snow leopard]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[url shortener]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=899</guid>
		<description><![CDATA[<p>I was sifting through my previous blog after Jeffery Zeldman kindly sent a lot of visitors in that direction for some TextMate starter tips. Whilst milling around, I stumbled upon an old trick I used to use in Quicksilver (before I gave up on it1), but had forgotten about since. It’s a very simple little shell command which uses curl&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/is-your-url-too-short-try-our-system-free/">Is your URL too short? Try our system, free!</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/08/urlextender_system.jpg?9d7bd4" alt="URL Extender System" border="0" width="300" height="260" class="alignright noshadow" />I was sifting through my <a href="http://blog.circlesixdesign.com">previous blog</a> after Jeffery Zeldman kindly <a href="http://www.zeldman.com/2010/08/13/how-to-use-textmate/">sent a lot of visitors</a> in that direction for some <a href="http://blog.circlesixdesign.com/2007/01/02/digging-in-to-textmate/">TextMate starter tips</a>. Whilst milling around, I stumbled upon an <a href="http://blog.circlesixdesign.com/2007/10/19/reverse-shortened-urls-with-quicksilver/">old trick I used to use</a> in <a href="http://www.blacktree.com/">Quicksilver</a> (before I gave up on it<sup id="fnref:quicksilver"><a href="#fn:quicksilver" rel="footnote">1</a></sup>), but had forgotten about since.</p>

<p>It’s a very simple little shell command which uses <code>curl</code> to track down the destination of a shortened url (or any link with a redirect). It works with an assortment of services, including bit.ly, tinyurl.com, ow.ly, etc. It returns the destination address (the original url), and you can pass that on to whatever you like!</p>

<p><strong>Side note</strong>: I’ve been working on a little site called <a href="http://justthelinks.com">JustTheLinks</a> which makes liberal use of url-lengthening. It grabs all of your tweets from your home timeline which contain links, and creates a live-updated list with expanded urls and titles. It uses PHP’s curl to do the trick, so it’s the same concept. It’s “in-progress,” but feel free to check it out at <a href="http://justthelinks.com">http://justthelinks.com</a>!</p>

<p>Anyway, I decided to update the Quicksilver action and adapt it for some other uses. I’m happy to report that it’s still quite useful as a command line script, a LaunchBar action or a System Service. This post has code for all three, so take your pick!</p>

<p><span id="more-899"></span></p>

<p>The <code>curl</code> command in this script has two options specified, –I and –s. –I tells it to fetch only the headers of the requested URI, and the –s tells it to suppress error messages (silent). The result is a short response which contains the location of the redirect, which is piped to <code>awk</code>. We look for the line in the response containing “Location” and print the second field of that line, which is the destination url. Here are a few ways I thought of to put it to use:</p>

<h3>Terminal</h3>

<p>The first thing I did was whip up a shell script to run from the command line. Just create a text file wherever you keep scripts<sup id="fnref:scripts"><a href="#fn:scripts" rel="footnote">2</a></sup>, or make a new directory somewhere for it. Paste in the code below, and name it something that makes sense to you. I went with <code>follow</code>, because it’s following the redirect path, and <code>expand</code> was taken (and lengthen didn’t seem as much fun to type…). The script looks for a single argument, which would be the shortened url, and if it doesn’t receive one it tries the clipboard. So, if you already have the url in your clipboard, which is a pretty safe bet in this case, you can just run the script with no arguments.</p>

<div markdown=0>
<pre><code class="bash">
#!/bin/bash

if [ $# -eq 0 ]; then
  curl -Is `pbpaste` | awk &#x27;/Location/ { print $2 }&#x27;  
else
  curl -Is $1 | awk &#x27;/Location/ { print $2 }&#x27;
fi
</code></pre>
</div>

<h3>LaunchBar</h3>

<p>I heart <a href="http://www.obdev.at/products/launchbar/index.html" title="LaunchBar 5">LaunchBar</a>. Like Quicksilver, you can easily build “actions” for it that act on different types of input. This one just acts on text you paste or send to it, and assumes it’s going to be a shortened URL. After it lengthens it, it just displays the result as large popup text. If you wanted to, you could easily have it <code>open location</code> or whatever, but the whole point is just to see where you’re going, right?</p>

<p>This just goes into <code>~/Library/Application Support/LaunchBar/Actions</code> as a compiled AppleScript (scpt) file. Open AppleScript Editor and paste in the code below (or just <a href="applescript://com.apple.scripteditor?action=new&amp;script=on%20handle_string%28message%29%0A%09%0A%09tell%20application%20%22LaunchBar%22%0A%09%09set%20_res%20to%20do%20shell%20script%20%22curl%20%2DIs%20%22%20%26%20message%20%26%20%22%20%7C%20awk%20%27%2FLocation%2F%20%7B%20print%20%242%20%7D%27%22%0A%09%09display%20in%20large%20type%20_res%0A%09end%20tell%0A%09%0Aend%20handle_string">click here to open it automatically</a> in your editor). Save the file to the Actions folder and give it a name you’ll recognize. Mine’s called ‘Expand Shortened URL.scpt’. Clever, I know. Here’s the code:</p>

<div markdown=0>
<pre><code class="as">
on handle_string(message)

    tell application &quot;LaunchBar&quot;
        set _res to do shell script &quot;curl -Is &quot; &amp; message &amp; &quot; | awk &#x27;/Location/ { print $2 }&#x27;&quot;
        display in large type _res
    end tell

end handle_string
</code></pre>
</div>

<h3>Snow Leopard Service</h3>

<p>Lastly, here’s a System Service that you can run on selected text in any Cocoa application. I’ve previously posted a <a href="http://brettterpstra.com/a-system-service-for-to-url-shortening/">Service for shortening urls</a>, so here’s the opposite. This one can actually take a whole block of text and will scan for any and all links in it, attempting to lengthen and replace any shortened urls in the text. Here’s how to build it:</p>

<ul>
<li>Open Automator.app</li>
<li>Select “Service” from the new file menu</li>
<li>Set “Service receives selected” to “text” in “any application”</li>
<li>Check the “Replaces selected text” box</li>
<li>Find the “Run Shell Script” action on the left and drag it into your workflow on the right</li>
<li>Set the Shell to Ruby (in this case)</li>
<li>Paste in the code below</li>
<li>Save the file to the <code>~/Library/Services</code> folder, named something like “Expand shortened urls in selection” (or something more interesting)</li>
</ul>

<p>Now, when you select text in any Cocoa application (Safari, Mail, TextEdit, etc.), you’ll be able to find your Service in the Services submenu of either the application menu in the menubar, or in the contextual menu that comes up when you right click (ctrl-click) the selected text. When you run it, it will replace your text with a new version with any shortened urls in it expanded.</p>

<div markdown=0>
<pre><code class="ruby">
#!/usr/bin/env ruby -rjcode -Ku

require &#x27;open-uri&#x27;

input = STDIN.read
links = input.scan(/\b((?:https?:\/\/)(?:www\.)?([^\/]+)\/[a-zA-Z0-9]+[^\s`!()\[\]{};:&#x27;&quot;.,&lt;&gt;?&laquo;&raquo;&ldquo;&rdquo;&lsquo;&rsquo;])/im)
links.each {|link|
  result = %x{curl -Is #{link[0]} | awk &#x27;/Location/ { print $2 }&#x27;}
  input = input.gsub(/#{link[0]}/,result.strip)
}
print input
</code></pre>
</div>

<p>How often will you need any of these little experiments? Probably not very often. Most of the time, I’m more than happy to just follow a shortened link and trust that the description it came with will hold true. Every once in a while, though, I come across a link of unknown origin that I’d prefer to run through something like this. Hopefully you’ll be able to find a use for it, too. It’s a cool little snippet.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:quicksilver">
<p>Sorry, Quicksilver fans. It used to be my absolute, must-have, favorite thing in the world, but it got too crashy on Snow Leopard, and then development just kind of died. <a href="http://www.obdev.at/products/launchbar/index.html" title="LaunchBar 5">LaunchBar</a> is way better these days. <a href="#fnref:quicksilver" rev="footnote">↩</a></p>
</li>

<li id="fn:scripts">
<p>I keep a ‘scripts’ folder in my home directory (~/scripts) and put that in my PATH environment variable in my .bash_profile. Then, I can run my scripts from anywhere but don’t have to muck around in <code>/usr/local/bin</code> or any such thing. <a href="#fnref:scripts" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/a-system-service-for-to-url-shortening/' rel='bookmark' title='A System Service for to. url shortening'>A System Service for to. url shortening</a></li>
<li><a href='http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/' rel='bookmark' title='LaunchBar actions for url encoding and decoding'>LaunchBar actions for url encoding and decoding</a></li>
<li><a href='http://brettterpstra.com/a-better-os-x-system-service-for-evernote-notes-with-multimarkdown/' rel='bookmark' title='A better System Service for Evernote clipping — with MultiMarkdown'>A better System Service for Evernote clipping — with MultiMarkdown</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/is-your-url-too-short-try-our-system-free/">Is your URL too short? Try our system, free!</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/is-your-url-too-short-try-our-system-free/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A quick TextMate KeyBindings tip</title>
		<link>http://brettterpstra.com/textmate-keybinding-tip/</link>
		<comments>http://brettterpstra.com/textmate-keybinding-tip/#comments</comments>
		<pubDate>Fri, 13 Aug 2010 19:19:52 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[keybindings]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[textmate]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=891</guid>
		<description><![CDATA[<p>I love the keyboard, and I love keyboard shortcuts. It’s one of the reasons TextMate and I get along so well. There’s one thing that bothers me any time I’m editing text (in any application), though: having to move my right hand all the way over to the arrow keys just to move forward a couple of characters, say, after&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/textmate-keybinding-tip/">A quick TextMate KeyBindings tip</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/08/keybindingstypewriter1.jpg?9d7bd4" alt="Typewriter Image" border="0" width="318" height="301" class="alignright noshadow" />I love the keyboard, and I love keyboard shortcuts. It’s one of the reasons TextMate and I get along so well. There’s one thing that bothers me any time I’m editing text (in any application), though: having to move my right hand <em>all</em> the way over to the arrow keys just to move forward a couple of characters, say, after an auto-paired set of parenthesis that I want to get out of.</p>

<p>I know, it’s stupid for two reasons: first, it’s just not that big a deal, and second, I could just use the Emacs keybindings (^F,^B,^P,^N, etc.). Well, to that I say “phooey” on both counts. It <em>is</em> a big deal; I’ve probably lost hours of my life to that motion. As to the latter, I didn’t grow up on Emacs, and those shortcuts have just never nestled into my muscle memory. In related news, I already have some of those keys bound elsewhere.</p>

<p>I used to use <a href="http://pqrs.org/macosx/keyremap4macbook/">KeyRemap4Macbook</a> to map control-j,i,l and m to the cursor keys, but haven’t installed it since my last clean wipe (just in case it was part of the reason I had to do the clean wipe to begin with). I missed that convenience, though, so after 15 minutes of Googling, here’s the answer…</p>

<p><span id="more-891"></span></p>

<p>Allan Odgaard, creator of TextMate, offers the beginning of the solution <a href="http://blog.macromates.com/2005/key-bindings-for-switchers/">on the TextMate blog</a>. I found a little <a href="http://xahlee.org/emacs/osx_keybinding.html">more detailed information</a> around the net, too. Basically, you can add or edit a file called <code>DefaultKeyBinding.dict</code> in <code>~/Library/KeyBindings/</code> to add the keystrokes to all Cocoa applications. Mine looks like this now:</p>

<div markdown=0>
<pre><code>
{
  "^j" = "moveBackward:";
  "^l" = "moveForward:";
  "^m" = "moveDown:";
  "^i" = "moveUp:";
  "^E" = "\"editInTextMate:\"";
}
</code></pre>
</div>

<p>The first part of each pair is the keystroke, and the second part is the action. To find a list of the available actions, I just looked at <code>/System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict</code>, which has all of the default OS X keybindings in it. You’ll need Property List Editor to view the file in its default state. To view the file in a text editor, you have to convert it to an XML (old school and plain text) plist. If you’re curious, copy the file to your Desktop and, in Terminal, run <code>plutil -convert xml1 ~/Desktop/StandardKeyBinding.dict</code>.</p>

<p>After editing <code>DefaultKeyBinding.dict</code> and restarting your Cocoa apps, your new keyboard shortcuts will be available. That’s when I found the next problem. TextMate has ^J mapped to “Reformat and Justify” under the Text menu. I never, ever use that command, so that was just annoying. I first tried to just override it in System Preferences-&gt;Keyboard-&gt;Application Shortcuts, but that didn’t do anything. Next I found a <a href="http://www.macosxhints.com/article.php?story=20040618093419348">post on macosxhints</a> that offered a Terminal (<code>defaults</code>) command for changing default Application shortcuts. For example:</p>

<div markdown=0>
<pre><code>
defaults write com.macromates.textmate NSUserKeyEquivalents -dict-add "Reformat and Justify" "nil"
</code></pre>
</div>

<p>Guess what? That didn’t do it. TextMate was still pwning the ^J shortcut. Next stop, the Resources folder of the TextMate application. There I found <code>KeyBindings.dict</code>, where it was easy to locate the offending shortcut. I commented out the line (//) and restarted TextMate. Ta. Dum. My new keyboard shortcuts now function perfectly.</p>

<p>By the way, the reason I didn’t use “k” for down is I actually do regularly use the <code>kill</code> keybinding to delete to the end of the line (as well as ^a to move to beginning and ^e to the end). Also, you might skip mapping “m” to down, as “n” right next to it is already mapped to moveDown:, as mentioned while complaining about Emacs keybindings. I have them both mapped now, so I can have lazy fingers if I want to. Further, note that these keybindings will not work when selecting text; once you press the shift key, you’re in a whole new world. You’d have map those as well if you wanted that functionality.</p>

<p>I’m happy now, and so are my fingers. Have any other brilliant keybinding stories? I’d love to hear them.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/keybindings-new-improved-surround-commands/' rel='bookmark' title='KeyBindings: new, improved “surround” commands'>KeyBindings: new, improved “surround” commands</a></li>
<li><a href='http://brettterpstra.com/keybinding-madness/' rel='bookmark' title='KeyBinding madness'>KeyBinding madness</a></li>
<li><a href='http://brettterpstra.com/the-keys-that-bind-keybinding-madness-part-2/' rel='bookmark' title='The keys that bind: KeyBinding Madness part 2'>The keys that bind: KeyBinding Madness part 2</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/textmate-keybinding-tip/">A quick TextMate KeyBindings tip</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/textmate-keybinding-tip/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>My new favorite Bash prompt</title>
		<link>http://brettterpstra.com/my-new-favorite-bash-prompt/</link>
		<comments>http://brettterpstra.com/my-new-favorite-bash-prompt/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 00:12:33 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[prompt]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/2009/11/17/my-new-favorite-bash-prompt/</guid>
		<description><![CDATA[<p>I do a lot in Terminal. Sometimes, it’s easier. Sometimes it’s faster. Sometimes I’d just rather type it out. Whatever the reason, I’ve never been able to stand looking at a boring shell prompt. Bash is my primary shell, mostly because I’ve never taken the time to learn much else. I’ll get there someday. For now, here’s my current Bash&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/my-new-favorite-bash-prompt/">My new favorite Bash prompt</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: left; padding: 4px; margin: 0 7px 2px 0; display:none'  class="alignleft headerimg" src="http://cdn2.brettterpstra.com/wp-content/uploads/2009/11/my_new_favorite_bash_prompt.jpg?9d7bd4" alt="My new favorite Bash prompt" width="440" height="187" />
I do a lot in Terminal. Sometimes, it’s easier. Sometimes it’s faster. Sometimes I’d just rather type it out. Whatever the reason, I’ve never been able to stand looking at a boring shell prompt. Bash is my primary shell, mostly because I’ve never taken the time to learn much else. I’ll get there someday. For now, here’s my current Bash shell prompt…</p>

<p>I’m using the <code>PROMPT_COMMAND</code> variable to run a few quick functions to generate the prompt. It doesn’t do anything processor-intensive, so I haven’t seen any lag caused by this one (unlike some of my previous experiments). <code>PROMPT_COMMAND</code> is set to call a function called, appropriately, <code>prompt_command()</code>. This, in turn, calls a few external functions defined in my <code>.bash_profile</code>. To use it, just stick all of the code below into your <code>.bash_profile</code>, and modify it as you see fit. Be sure to replace any definitions of <code>PROMPT_COMMAND</code> or <code>PS1</code>.</p>

<p><span id="more-163"></span>
The prompt has a few unique features, and some “hidden” features:</p>

<ul>
<li>The current time is formatted just the way I like it. You can modify the <code>fmt_time</code> function with your own <code>strftime</code> strings as desired.</li>
<li>The current 1m average CPU load is included in the prompt in dark grey, gathered using a quick <code>uptime</code> command.</li>
<li>If the previous command returned an error message, the error code returned will show up at the end of the first line in red.</li>
<li>If you use Git, and your current working directory is a Git repository, the current branch will be shown in green before the actual prompt on the second line. This might cause problems if you don’t have Git installed; if you see Git-related errors, you can remove the section of the code under the Git comment from <code>if</code> to <code>fi</code>. Also remove the <code>${BRANCH}</code> from the last line of the <code>prompt_command</code> function.</li>
<li>Lastly, it sets the title of the tab in Terminal to the last two portions of the current working directory (<code>pwd</code>) string, meaning the current directory and its parent directory.</li>
</ul>

<p><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-full wp-image-165" title="TerminalPromptFullMonty" src="http://cdn2.brettterpstra.com/wp-content/uploads/2009/11/TerminalPromptFullMonty.jpg?9d7bd4" alt="TerminalPromptFullMonty" width="536" height="133" /></p>

<p>All of the colors used in the prompt are defined as shell variables. In the final line of the <code>prompt_command</code> function, you can modify the colors just by replacing the color names in the line. That should be pretty self-explanatory.</p>


<div class="wp_syntax"><div class="code"><pre class="bash">prompt_command <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> <span class="re5">-eq</span> <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">then</span> <span class="co0"># set an error string for the prompt, if applicable</span>
        <span class="re2">ERRPROMPT</span>=<span class="st0">&quot; &quot;</span>
    <span class="kw1">else</span>
        <span class="re2">ERRPROMPT</span>=<span class="st_h">'-&amp;gt;($?) '</span>
    <span class="kw1">fi</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="st0">&quot;<span class="es1">\$</span>(type -t __git_ps1)&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span> <span class="co0"># if we're in a Git repo, show current branch</span>
        <span class="re2">BRANCH</span>=<span class="st0">&quot;<span class="es1">\$</span>(__git_ps1 '[ %s ] ')&quot;</span>
    <span class="kw1">fi</span>
    <span class="kw3">local</span> <span class="re2">TIME</span>=<span class="sy0">`</span>fmt_time<span class="sy0">`</span> <span class="co0"># format time for prompt string</span>
    <span class="kw3">local</span> <span class="re2">LOAD</span>=<span class="sy0">`</span><span class="kw2">uptime</span><span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{min=NF-2;print $min}'</span><span class="sy0">`</span>
    <span class="kw3">local</span> <span class="re2">GREEN</span>=<span class="st0">&quot;\[\033[0;32m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">CYAN</span>=<span class="st0">&quot;\[\033[0;36m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">BCYAN</span>=<span class="st0">&quot;\[\033[1;36m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">BLUE</span>=<span class="st0">&quot;\[\033[0;34m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">GRAY</span>=<span class="st0">&quot;\[\033[0;37m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">DKGRAY</span>=<span class="st0">&quot;\[\033[1;30m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">WHITE</span>=<span class="st0">&quot;\[\033[1;37m\]&quot;</span>
    <span class="kw3">local</span> <span class="re2">RED</span>=<span class="st0">&quot;\[\033[0;31m\]&quot;</span>
    <span class="co0"># return color to Terminal setting for text color</span>
    <span class="kw3">local</span> <span class="re2">DEFAULT</span>=<span class="st0">&quot;\[\033[0;39m\]&quot;</span>
    <span class="co0"># set the titlebar to the last 2 fields of pwd</span>
    <span class="kw3">local</span> <span class="re2">TITLEBAR</span>=<span class="st_h">'\[\e]2;`pwdtail`\a'</span>
    <span class="kw3">export</span> <span class="re2">PS1</span>=<span class="st0">&quot;\[<span class="es3">${TITLEBAR}</span>\]<span class="es3">${CYAN}</span>[ <span class="es3">${BCYAN}</span>\u<span class="es3">${GREEN}</span>@<span class="es3">${BCYAN}</span><span class="es1">\
</span>\h<span class="es3">${DKGRAY}</span>(<span class="es3">${LOAD}</span>) <span class="es3">${WHITE}</span><span class="es3">${TIME}</span> <span class="es3">${CYAN}</span>]<span class="es3">${RED}</span><span class="es2">$ERRPROMPT</span><span class="es3">${GRAY}</span><span class="es1">\
</span>\w<span class="es1">\n</span><span class="es3">${GREEN}</span><span class="es3">${BRANCH}</span><span class="es3">${DEFAULT}</span>$ &quot;</span>
<span class="br0">&#125;</span>
<span class="re2">PROMPT_COMMAND</span>=prompt_command
&nbsp;
fmt_time <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="co0">#format time just the way I likes it</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="sy0">`</span><span class="kw2">date</span> +<span class="sy0">%</span>p<span class="sy0">`</span> = <span class="st0">&quot;PM&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
        <span class="re2">meridiem</span>=<span class="st0">&quot;pm&quot;</span>
    <span class="kw1">else</span>
        <span class="re2">meridiem</span>=<span class="st0">&quot;am&quot;</span>
    <span class="kw1">fi</span>
    <span class="kw2">date</span> +<span class="st0">&quot;%l:%M:%S<span class="es2">$meridiem</span>&quot;</span><span class="sy0">|</span><span class="kw2">sed</span> <span class="st_h">'s/ //g'</span>
<span class="br0">&#125;</span>
pwdtail <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="co0">#returns the last 2 fields of the working directory</span>
    <span class="kw3">pwd</span><span class="sy0">|</span><span class="kw2">awk</span> -F<span class="sy0">/</span> <span class="st_h">'{nlast = NF -1;print $nlast&quot;/&quot;$NF}'</span>
<span class="br0">&#125;</span>
chkload <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="co0">#gets the current 1m avg CPU load</span>
    <span class="kw3">local</span> <span class="re2">CURRLOAD</span>=<span class="sy0">`</span><span class="kw2">uptime</span><span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{print $8}'</span><span class="sy0">`</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="st0">&quot;<span class="es2">$CURRLOAD</span>&quot;</span> <span class="sy0">&amp;</span>gt; <span class="st0">&quot;1&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
        <span class="kw3">local</span> <span class="re2">OUTP</span>=<span class="st0">&quot;HIGH&quot;</span>
    <span class="kw1">elif</span> <span class="br0">&#91;</span> <span class="st0">&quot;<span class="es2">$CURRLOAD</span>&quot;</span> <span class="sy0">&amp;</span>lt; <span class="st0">&quot;1&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
        <span class="kw3">local</span> <span class="re2">OUTP</span>=<span class="st0">&quot;NORMAL&quot;</span>
    <span class="kw1">else</span>
        <span class="kw3">local</span> <span class="re2">OUTP</span>=<span class="st0">&quot;UNKNOWN&quot;</span>
    <span class="kw1">fi</span>
    <span class="kw3">echo</span> <span class="re1">$CURRLOAD</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/geeklet-top-cpu-processes/' rel='bookmark' title='Geeklet: Top CPU processes'>Geeklet: Top CPU processes</a></li>
<li><a href='http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/' rel='bookmark' title='oft: Bash function for opening a specific filetype'>oft: Bash function for opening a specific filetype</a></li>
<li><a href='http://brettterpstra.com/na-per-project-todos-in-terminal/' rel='bookmark' title='na: per-project todos in Terminal'>na: per-project todos in Terminal</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/my-new-favorite-bash-prompt/">My new favorite Bash prompt</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/my-new-favorite-bash-prompt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic (Feed is rejected)
Page Caching using disk: enhanced
Database Caching 35/178 queries in 0.338 seconds using xcache
Object Caching 4435/4628 objects using xcache
Content Delivery Network via cdn2.brettterpstra.com

Served from: brettterpstra.com @ 2012-05-23 04:40:32 -->
