<?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 Terpstrabash page  - Brett Terpstra</title>
	<atom:link href="http://brettterpstra.com/tag/bash/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>Bash auto-complete for running applications</title>
		<link>http://brettterpstra.com/bash-auto-complete-for-running-applications/</link>
		<comments>http://brettterpstra.com/bash-auto-complete-for-running-applications/#comments</comments>
		<pubDate>Tue, 04 Oct 2011 22:58:19 +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[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2921</guid>
		<description><![CDATA[<p>I’m not up for doing a full Bash autocomplete tutorial tonight, but wanted to share something I figured out instead of eating lunch. Here it is with a modicum of explanation. I’ve been using Jon Stovell’s quit script to stop running applications with various save options as part of tweaking a safer universal computing setup with Dropbox. For various reasons&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/bash-auto-complete-for-running-applications/">Bash auto-complete for running applications</a></p>]]></description>
			<content:encoded><![CDATA[<p>I’m not up for doing a full Bash autocomplete tutorial tonight, but wanted to share something I figured out instead of eating lunch. Here it is with a modicum of explanation.</p>

<p>I’ve been using Jon Stovell’s <a href="http://web.me.com/jonstovell/personal/Software.html">quit script</a> to stop running applications with various save options as part of tweaking a safer <a href="http://brettterpstra.com/dropbox-and-seamless-mutli-mac-computing/">universal computing setup with Dropbox</a>. For various reasons I found myself wanting to autocomplete application names, but only ones that were currently running. This technique could be used for any command line tool that runs on running, windowed applications. This version doesn’t do anything for faceless processes, but I’ll show you that in a minute.</p>

<p>A short version to start with. You can run a long one-liner in .bash_profile to return an array of running apps using <code>osascript</code> (AppleScript) and pass it to <code>complete</code> with the <code>-W</code> parameter to accept the variable instead of a function:</p>

<pre><code>APP_COMPLETE=( $( echo "$(osascript -e "set AppleScript's text item delimiters to \"\n\"" -e "tell application \"System Events\" to return (displayed name of every application process whose (background only is false and displayed name is not \"Finder\")) as text" 2&gt;/dev/null)"|sed -e 's/ /\\ /g' ) )

complete -o default -W "${APP_COMPLETE[*]}" quit
</code></pre>

<p>This works but isn’t case insensitive, and I’m never satisfied until things are as lazy as possible.</p>

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

<h3>Case-insensitive completion of running app names</h3>

<p>The script below is in <code>~/.app_completions</code> along with my app name completion script for launching (as mentioned in the <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/">Bash version of my Get an App’s Icon series</a>). You could just as easily add it to your <code>.bash_profile</code>, but it’s easier for me to keep track of if it’s external.</p>

<p>In <code>.app_completions</code> is this function and <code>complete</code> command:</p>


<div class="wp_syntax"><div class="code"><pre class="bash">_complete_running_apps <span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="kw3">local</span> cur prev 
  <span class="kw3">local</span> <span class="re2">LC_ALL</span>=<span class="st_h">'C'</span>
&nbsp;
  <span class="re2">COMPREPLY</span>=<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="re2">cur</span>=<span class="co1">${COMP_WORDS[COMP_CWORD]}</span>
  <span class="re2">prev</span>=<span class="co1">${COMP_WORDS[COMP_CWORD-1]}</span>
&nbsp;
  <span class="co0"># do not attempt completion if we're specifying an option</span>
  <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="st0">&quot;<span class="es2">$cur</span>&quot;</span> == -<span class="sy0">*</span> <span class="br0">&#93;</span><span class="br0">&#93;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">return</span> <span class="nu0">0</span>
&nbsp;
  <span class="co0"># Escape dots in paths for grep </span>
  <span class="re2">cur</span>=<span class="co1">${cur//\./\\\.}</span>
&nbsp;
  <span class="kw3">local</span> <span class="re2">IFS</span>=<span class="st0">&quot;
&quot;</span>
  <span class="re2">COMPREPLY</span>=<span class="br0">&#40;</span> $<span class="br0">&#40;</span> <span class="kw3">echo</span> <span class="st0">&quot;<span class="es4">$(osascript -e &quot;set AppleScript's text item delimiters to \&quot;\n\&quot;&quot; -e &quot;tell application \&quot;System Events\&quot; to return (displayed name of every application process whose (background only is false and displayed name is not \&quot;Finder\&quot;)</span>) as text&quot;</span> <span class="nu0">2</span><span class="sy0">&gt;/</span>dev<span class="sy0">/</span>null<span class="br0">&#41;</span><span class="st0">&quot;|grep -i &quot;</span>^<span class="re1">$cur</span><span class="st0">&quot; | sed -e 's/ /\\ /g' ) )
&nbsp;
  return 0
}
&nbsp;
complete -o bashdefault -o default -o nospace -F _complete_running_apps quit 2&gt;/dev/null || complete -o default -o nospace -F _complete_running_apps quit</span></pre></div></div>


<p>It starts start by setting up a few variables to read what the completion command provides as partial text and preceding words. Then it runs the same AppleScript<sup id="fnref:ps"><a href="#fn:ps" rel="footnote">1</a></sup> from before, except that by running it through a function we’re taking control of the matching process. Thus, we can use <code>grep -i</code> for case-insensitive matching. We set $COMPREPLY to the result and it’s read in by the auto-complete on the command line.</p>

<p>In the <code>complete</code> command at the end, note that it’s only currently setting up completion for the <code>quit</code> command. Just change <code>quit</code> to something else if you’re using it for something else.</p>

<p>Now, just add a line to <code>.bash_profile</code> to read in the script on login:</p>

<pre><code>source ~/.app_completions
</code></pre>

<h3>Bonus: kill ‘em all.</h3>

<p>You can also do something similar with all running processes, handy for commands like <code>killall</code>. This could also be easily converted to a one-liner like the first script above, but just for the sake of laziness:</p>


<div class="wp_syntax"><div class="code"><pre class="bash">_complete_running_processes <span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="kw3">local</span> cur prev 
    <span class="kw3">local</span> <span class="re2">LC_ALL</span>=<span class="st_h">'C'</span>
&nbsp;
    <span class="re2">COMPREPLY</span>=<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="re2">cur</span>=<span class="co1">${COMP_WORDS[COMP_CWORD]}</span>
    <span class="re2">prev</span>=<span class="co1">${COMP_WORDS[COMP_CWORD-1]}</span>
&nbsp;
    <span class="co0"># do not attempt completion if we're specifying an option</span>
    <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="st0">&quot;<span class="es2">$cur</span>&quot;</span> == -<span class="sy0">*</span> <span class="br0">&#93;</span><span class="br0">&#93;</span> <span class="sy0">&amp;&amp;</span> <span class="kw3">return</span> <span class="nu0">0</span>
&nbsp;
    <span class="co0"># Escape dots in paths for grep</span>
    <span class="re2">cur</span>=<span class="co1">${cur//\./\\\.}</span>
&nbsp;
    <span class="kw3">local</span> <span class="re2">IFS</span>=<span class="st0">&quot;
&quot;</span>
    <span class="re2">COMPREPLY</span>=<span class="br0">&#40;</span> $<span class="br0">&#40;</span><span class="kw2">ps</span> axc<span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{ print $5 }'</span><span class="sy0">|</span><span class="kw2">sort</span> <span class="re5">-u</span><span class="sy0">|</span><span class="kw2">grep</span> <span class="re5">-v</span> <span class="st0">&quot;^[\-\(]&quot;</span><span class="sy0">|</span><span class="kw2">grep</span> <span class="re5">-i</span> <span class="st0">&quot;^<span class="es2">$cur</span>&quot;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>
&nbsp;
    <span class="kw3">return</span> <span class="nu0">0</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw3">complete</span> <span class="re5">-o</span> bashdefault <span class="re5">-o</span> default <span class="re5">-o</span> nospace <span class="re5">-F</span> _complete_running_processes <span class="kw2">killall</span> <span class="nu0">2</span><span class="sy0">&gt;/</span>dev<span class="sy0">/</span>null <span class="sy0">||</span> <span class="kw3">complete</span> <span class="re5">-o</span> default <span class="re5">-o</span> nospace <span class="re5">-F</span> _complete_running_processes <span class="kw2">killall</span></pre></div></div>


<p>The <code>ps axc</code> reports all running processes with just their executable name. The <code>awk</code> after it grabs the executable names from each line. They’re passed as a list to <code>sort -u</code> which removes duplicates and sorts them in alphabetical order. The first grep removes processes beginning with “(“ or “-” so we can exclude private and terminal commands. There are still plenty of lines autocompleting that you really don’t want to kill, but hey, the command line can be a dangerous place. The last grep does our case-insensitive match for anything that begins with the partial string that we’re completing off of.</p>

<p>So that’s my lunch break. It will ease my hunger pains if someone else finds any use for this. Be sure to let me know!</p>

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

<li id="fn:ps">
<p>There’s probably a way to do this with <code>ps</code> and some string manipulation, but it was lunchtime and I was hungry. <a href="#fnref:ps" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<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/duplicating-safari-browsing-sessions-between-macs/' rel='bookmark' title='Duplicating Safari browsing sessions between Macs'>Duplicating Safari browsing sessions between Macs</a></li>
<li><a href='http://brettterpstra.com/quick-tip-some-inputrc-fun/' rel='bookmark' title='Quick Tip: some .inputrc fun'>Quick Tip: some .inputrc fun</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/bash-auto-complete-for-running-applications/">Bash auto-complete for running applications</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/bash-auto-complete-for-running-applications/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quick Tip: some .inputrc fun</title>
		<link>http://brettterpstra.com/quick-tip-some-inputrc-fun/</link>
		<comments>http://brettterpstra.com/quick-tip-some-inputrc-fun/#comments</comments>
		<pubDate>Sun, 25 Sep 2011 13:52:08 +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[inputrc]]></category>
		<category><![CDATA[quicktip]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2839</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 was playing around with some readline options this morning, after reading this post on Reddit Commandline. A few of them wouldn’t work for me, so I did some research into&#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-some-inputrc-fun/">Quick Tip: some .inputrc fun</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><img style=' display: block; margin-right: auto; margin-left: auto;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/09/old-typewriter-keys.jpeg?9d7bd4" alt="" title="old typewriter keys" width="650" height="138" class="aligncenter size-full wp-image-2842" /></p>

<p>I was playing around with some <code>readline</code> options this morning, after reading <a href="http://www.reddit.com/r/commandline/comments/kbeoe/you_can_make_readline_and_bash_much_more_user/">this post</a> on <a href="http://www.reddit.com/r/commandline/">Reddit Commandline</a>. A few of them wouldn’t work for me, so I did some research into the version of Bash that comes with OS X.</p>

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

<p>Specifically, I wanted to get <code>menu-complete-backward</code> to work in my <code>~/.inputrc</code> file. <code>menu-complete</code> is a cool feature where you bind a key combination and typing it cycles through available completions. It follows, then, that <code>menu-complete-backward</code> would cycle in the reverse order. It turns out you need a special escape sequence to pull this off on OS X.</p>

<p>Say you want to bind the Tab key to cycle completions one at a time instead of listing them all and requiring you to type characters until there’s only one match. In your <code>.inputrc</code> you would include:</p>

<pre><code>TAB: menu-complete
</code></pre>

<p>Binding Shift-Tab to go backward is a little tricker:</p>

<pre><code>"\e[Z": "\e-1\C-i"
</code></pre>

<p>The above is working perfectly for me in iTerm2 on GNU Bash 3.2.48(1)-release-(x86_64-apple-darwin11). It will take a few days to decide if I prefer this completion to the normal Tab-complete behavior or whether I want to bind this to a secondary key combination. Either way, it’s handy info to have.</p>

<p>While I’m on the subject, I was playing around with binding commands a while ago and added a couple to my <code>.inputrc</code> which I’ve found helpful. The following will bind Option-z to run <code>cd -</code> followed by <code>ls</code>, returning you to the previous directory in your stack and doing a file listing in one keystroke:</p>

<pre><code>"\ez": 'cd -\015ls\015'
</code></pre>

<p>The <code>\015</code> in the command is the return key, so it’s entering <code>cd -</code>, executing with return, then repeating with <code>ls</code>. You could add any parameters you want (<code>ls -aF</code>) if you don’t already have it aliased in your <code>.bash_profile</code>.</p>

<p>The next one binds Option-x to <code>cd</code> to the folder that was the last argument in my previous command. If I run <code>cp myfile.txt ~/Desktop/</code>, then hitting Option-X will take me to <code>~/Desktop/</code> and list its contents:</p>

<pre><code>"\ex": 'cd !$\015ls\015'
</code></pre>

<p>Just some Terminal fun… to be clear, all of the above commands would go into the <code>.inputrc</code> file in your home folder. Create it if it doesn’t exist, and be sure to restart your bash shell before trying them out.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/quick-tip-repeat-cocoa-text-actions-emacsvim-style/' rel='bookmark' title='Quick Tip: repeat Cocoa text actions, Emacs/Vim style'>Quick Tip: repeat Cocoa text actions, Emacs/Vim style</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>
<li><a href='http://brettterpstra.com/textmate-keybinding-tip/' rel='bookmark' title='A quick TextMate KeyBindings tip'>A quick TextMate KeyBindings tip</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-some-inputrc-fun/">Quick Tip: some .inputrc fun</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-some-inputrc-fun/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>oft: Bash function for opening a specific filetype</title>
		<link>http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/</link>
		<comments>http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/#comments</comments>
		<pubDate>Thu, 07 Jul 2011 22:03:46 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2424</guid>
		<description><![CDATA[<p>Here’s another simple Bash function that I’ve used so much recently I thought I should share. It’s called oft, which stands for Open File Type, and can be used as a standalone shell script or as a function in your .bash_profile. When run, it looks in the current directory for files with extensions that match (or partially match) the first&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/">oft: Bash function for opening a specific filetype</a></p>]]></description>
			<content:encoded><![CDATA[<p>Here’s another simple Bash function that I’ve used so much recently I thought I should share. It’s called <code>oft</code>, which stands for Open File Type, and can be used as a standalone shell script or as a function in your <code>.bash_profile</code>. When run, it looks in the current directory for files with extensions that match (or partially match) the first argument and opens them.</p>

<p>My most obvious use case is Xcode projects, where I may have dozens (and dozens) of files, but there’s only one <code>.xcodeproj</code> file (folder). I don’t always know the name of the project in the folder, but if I run <code>oft xco</code> it will open it without my having to search. If there is more than one result, it gives you a numeric menu to select the file you want to open. You can cancel, select a single file or “Open ALL” from that menu. If you run <code>oft</code> with no arguments, it will read a (partial) extension from a prompt.</p>

<p>This is a script born of laziness (so many good ones are, though). You can accomplish the same with an <code>ls *.ext</code>, spot the file and <code>open filename.ext</code>. This is just faster and better for me when I’m working with less-than-optimal amounts of sleep.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0"># Open filetype</span>
<span class="co0"># Finds every file in folder whose extension starts with the first parameter passed</span>
<span class="co0"># if more than one file of given type is found, it offers a menu</span>
oft <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="br0">&#91;</span> <span class="re4">$#</span> == <span class="nu0">0</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw3">echo</span> <span class="re5">-n</span> <span class="st0">&quot;Enter an extension or partial extension: &quot;</span>
    <span class="kw2">read</span> extension
  <span class="kw1">fi</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re4">$#</span> <span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw3">echo</span> <span class="st0">&quot;Usage: oft [(partial) file extension]&quot;</span>
    <span class="kw3">return</span>
  <span class="kw1">fi</span>
  <span class="re2">extension</span>=<span class="re4">$1</span>
&nbsp;
  <span class="kw2">ls</span> <span class="sy0">*</span>.<span class="sy0">*</span><span class="re1">$extension</span><span class="sy0">*</span> <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re4">$?</span> == <span class="nu0">1</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw3">echo</span> <span class="st0">&quot;No files matching <span class="es1">\&quot;</span><span class="es2">$extension</span><span class="es1">\&quot;</span> found.&quot;</span>
    <span class="kw3">return</span>
  <span class="kw1">fi</span>
  <span class="kw3">declare</span> <span class="re5">-a</span> <span class="re2">fileList</span>=<span class="br0">&#40;</span> <span class="sy0">*</span>\.<span class="sy0">*</span><span class="re1">$extension</span><span class="sy0">*</span> <span class="br0">&#41;</span>
&nbsp;
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="co1">${#fileList[*]}</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">IFS</span>=$<span class="st_h">'\n'</span>
    <span class="re2">PS3</span>=<span class="st_h">'Open which file? '</span>
    <span class="kw1">select</span> OPT <span class="kw1">in</span> <span class="st0">&quot;Cancel&quot;</span> <span class="co1">${fileList[*]}</span> <span class="st0">&quot;Open ALL&quot;</span>; <span class="kw1">do</span>
      <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re1">$OPT</span> == <span class="st0">&quot;Open ALL&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
        <span class="kw2">read</span> <span class="re5">-n1</span> <span class="re5">-p</span> <span class="st0">&quot;Open all matching files? (y/N): &quot;</span>
        <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$REPLY</span> = <span class="br0">&#91;</span>Yy<span class="br0">&#93;</span> <span class="br0">&#93;</span><span class="br0">&#93;</span> <span class="sy0">&amp;&amp;</span> $<span class="br0">&#40;</span><span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>open <span class="co1">${fileList[*]}</span><span class="br0">&#41;</span>
      <span class="kw1">elif</span> <span class="br0">&#91;</span> <span class="re1">$OPT</span> <span class="sy0">!</span>= <span class="st0">&quot;Cancel&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
        $<span class="br0">&#40;</span><span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>open <span class="st0">&quot;<span class="es2">$OPT</span>&quot;</span><span class="br0">&#41;</span>
      <span class="kw1">fi</span>
      <span class="kw3">unset</span> IFS
      <span class="kw3">break</span>
    <span class="kw1">done</span>
  <span class="kw1">else</span>
    $<span class="br0">&#40;</span><span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>open <span class="st0">&quot;<span class="es3">${fileList[0]}</span>&quot;</span><span class="br0">&#41;</span>
  <span class="kw1">fi</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Related posts:<ol>
<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>
<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/fk-redux/' rel='bookmark' title='fk: redux'>fk: redux</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/oft-bash-function-for-opening-a-specific-filetype/">oft: Bash function for opening a specific filetype</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/oft-bash-function-for-opening-a-specific-filetype/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A Bash function for Markdown bloggers</title>
		<link>http://brettterpstra.com/a-bash-function-for-markdown-bloggers/</link>
		<comments>http://brettterpstra.com/a-bash-function-for-markdown-bloggers/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 18:37:46 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[markdown]]></category>
		<category><![CDATA[mdfind]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[spotlight]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2396</guid>
		<description><![CDATA[<p>I store all of my writing as separate Markdown files. A basic tagging system1 adds more “searchability,” and I can quickly locate any file with Spotlight2. Given the amount of time I spend in Terminal (well, iTerm 2 these days), I use mdfind quite a bit to do the Spotlight searching. This function just makes it a little more convenient&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/a-bash-function-for-markdown-bloggers/">A Bash function for Markdown bloggers</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/06/markdowntypewriter.jpg?9d7bd4" alt="Markdown Typewriter Image" class="alignright" />I store all of my writing as separate Markdown files. A basic tagging system<sup id="fnref:tag"><a href="#fn:tag" rel="footnote">1</a></sup> adds more “searchability,” and I can quickly locate any file with Spotlight<sup id="fnref:spot"><a href="#fn:spot" rel="footnote">2</a></sup>. Given the amount of time I spend in Terminal (well, <a href="http://www.iterm2.com/">iTerm 2</a> these days), I use <a href="http://osxdaily.com/2006/12/05/use-spotlight-from-the-command-line-with-mdfind/"><code>mdfind</code></a> quite a bit to do the Spotlight searching. This function just makes it a little more convenient to search for and quickly edit an existing document.</p>

<p>By default, it looks in a Dropbox “Writing” folder, but you can adjust that to restrict to any folder at the top of the script. You can also set your edit command there (<code>mate</code>, <code>mvim</code>, <code>vim</code>, etc.). Then it takes all arguments and uses them as a Spotlight search, restricted to your writing folder and the Markdown filetype, and offers you a quick menu of matches. Selecting a match opens the file with your preferred editor. If there’s only one match, it’s opened automatically.</p>

<p>It’s written as a function to be included in your .bash_profile (or sourced from there). If you want to run it as a shell script, just remove the <code>edmd () {</code> at the top and the closing <code>}</code>, put it in your path and run <code>chmod a+x filename</code>.</p>

<p>Once it’s installed you can just type <code>edmd keyword</code> to find posts and drafts related to keyword. You can use multiple words (no quotes required) and prefixes like “keyword:” or “tag:”, just like a Spotlight query.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0"># Edit Markdown File from Writing directory</span>
<span class="co0"># Finds Markdown files matching a Spotlight-style search query</span>
<span class="co0"># If there's more than one, you get a menu</span>
edmd <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re2">WRITINGDIR</span>=<span class="st0">&quot;~/Dropbox/Writing&quot;</span>
  <span class="re2">EDITCMD</span>=<span class="st0">&quot;mate&quot;</span>
  <span class="re2">filelist</span>=$<span class="br0">&#40;</span>mdfind <span class="re5">-onlyin</span> <span class="st0">&quot;<span class="es2">$WRITINGDIR</span>&quot;</span> <span class="st0">&quot;($@) AND kind:markdown&quot;</span><span class="br0">&#41;</span>
  <span class="re2">listlength</span>=$<span class="br0">&#40;</span>mdfind <span class="re5">-onlyin</span> <span class="st0">&quot;<span class="es2">$WRITINGDIR</span>&quot;</span> <span class="re5">-count</span> <span class="st0">&quot;($@) AND kind:markdown&quot;</span><span class="br0">&#41;</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$listlength</span> <span class="sy0">&gt;</span> <span class="nu0">0</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$listlength</span> == <span class="nu0">1</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
      <span class="re1">$EDITCMD</span> <span class="re1">$filelist</span>
    <span class="kw1">else</span>
      <span class="re2">IFS</span>=$<span class="st_h">'\n'</span>
      <span class="re2">PS3</span>=<span class="st_h">'Edit which file? (1 to cancel): '</span>
      <span class="kw1">select</span> OPT <span class="kw1">in</span> <span class="st0">&quot;Cancel&quot;</span> <span class="re1">$filelist</span>; <span class="kw1">do</span>
        <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re1">$OPT</span> <span class="sy0">!</span>= <span class="st0">&quot;Cancel&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span>
          <span class="re1">$EDITCMD</span> <span class="re1">$OPT</span>
        <span class="kw1">fi</span>
        <span class="kw3">break</span>
      <span class="kw1">done</span>
    <span class="kw1">fi</span>
  <span class="kw1">else</span>
    <span class="kw3">return</span> <span class="nu0">1</span>
  <span class="kw1">fi</span>
  <span class="kw3">return</span> <span class="nu0">0</span>
<span class="br0">&#125;</span></pre></div></div>


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

<li id="fn:tag">
<p>I save drafts and posts to my desktop as <code>.md</code> files. During my daily review I use <a href="http://www.caseapps.com/tags/">Tags.app</a> or <a href="http://itunes.apple.com/us/app/filr/id402468144?mt=12">Filr</a> to quickly add target keywords (‘blogging’, a tag for which blog it’s for and one, maybe two topical tags). <a href="http://www.noodlesoft.com/hazel.php">Hazel</a> picks these up and stores them in my Dropbox “Writing” folder, in subfolders based on blog and filetype. <a href="#fnref:tag" rev="footnote">↩</a></p>
</li>

<li id="fn:spot">
<p>I never realized it, but apparently Spotlight doesn’t search these by default. My use of the <a href="https://github.com/toland/qlmarkdown">QLMarkdown Quick Look plugin</a> fixes that, I guess. <a href="#fnref:spot" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/fixing-spotlight-indexing-of-markdown-content/' rel='bookmark' title='Fixing Spotlight indexing of Markdown content'>Fixing Spotlight indexing of Markdown content</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/fk-a-useful-bash-function/' rel='bookmark' title='fk: a useful bash function'>fk: a useful bash function</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-bash-function-for-markdown-bloggers/">A Bash function for Markdown bloggers</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/a-bash-function-for-markdown-bloggers/feed/</wfw:commentRss>
		<slash:comments>1</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>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>Automating HTML5 video encodes</title>
		<link>http://brettterpstra.com/automating-html5-video-encodes/</link>
		<comments>http://brettterpstra.com/automating-html5-video-encodes/#comments</comments>
		<pubDate>Mon, 28 Mar 2011 00:19:08 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2113</guid>
		<description><![CDATA[<p>I spent an inordinate amount of time not doing useful things today. During this non-productivity bender, I got a little obsessed with making the HTML5 video encoding process easier. I’ve been working on a tutorial site for the Blogsmith Bundle, so this whole deal needed to be sped up. I came out with a script which, when combined with the&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/automating-html5-video-encodes/">Automating HTML5 video encodes</a></p>]]></description>
			<content:encoded><![CDATA[<p>I spent an inordinate amount of time <em>not</em> doing useful things today. During this non-productivity bender, I got a little obsessed with making the HTML5 video encoding process easier. I’ve been working on a <a href="http://bundle.weblogzinc.com/video">tutorial site</a> for the Blogsmith Bundle, so this whole deal needed to be sped up. I came out with a script which, when combined with the right command line utilities, takes 90% of the manual labor out of creating the multiple formats needed.</p>

<p>HTML5 video, if you’re not familiar, provides a means to supply modern browsers with high-quality video <em>without</em> using Flash. It works across iOS devices beautifully, and the markup is highly semantic. The problem is that every browser has chosen a different format to promote, and using HTML5 video effectively means providing the same video in three formats (OGV, MP4, WEBM). Then, you need to code in a Flash fallback for older browsers. This would all be fine if my usual video conversion tools had a multiple-encode feature. They don’t. The only one that comes close is <a href="http://thelittleappfactory.com/evom/">Evom</a>, which has an HTML5 preset to encode OGV and MP4 at the same time, but the OGV files won’t play in Firefox and it can’t do WEBM at <em>all</em> right now.</p>

<p>So, taking matters into my own hands…</p>

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

<h3>The workflow</h3>

<p>Here’s the workflow I’m using now:</p>

<ol>
<li>Export a screencast as an MP4 file to a bucket folder</li>
<li>Hazel detects a new MP4 file and runs a shell script on it which:

<ol>
<li>Creates a new folder based on the file’s base name and moves the file into it</li>
<li>Runs an ffmpeg sequence to create a webm version</li>
<li>Runs an ffmpeg2theora command to create an ogv</li>
<li>Uses ffmpeg to create a poster image from the first frame of the mp4</li>
<li>Uses rsync to put the finished folder on my server</li>
</ol></li>
<li>I get a growl notification from Hazel that files are converted and uploaded</li>
<li>I insert the ungodly-long “shortcode” for the <a href="http://wordpress.org/extend/plugins/videojs-html5-video-player-for-wordpress/installation/">VideoJS plugin</a> using TextExpander into a new WordPress post.</li>
</ol>

<p>Four steps, and I only have to interact with two of them. The script is pretty hardcoded for my setup, but I moved some of the config up to the top for convenience. You’ll need ffmpeg and ffmpeg2theora installed, both of which are really easy to set up with <a href="https://github.com/mxcl/homebrew">homebrew</a>. You can probably find binaries, too, but I just used <code>brew</code> for these.</p>

<h3>The script</h3>

<p>Here’s the script, hope it helps someone else, too:</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0">#!/bin/bash</span>
<span class="co0"># html5encode.sh</span>
<span class="co0"># Brett Terpstra, 2011 - http://brettterpstra.com/automating-html5-video-encodes</span>
<span class="co0"># Requires ffmpeg and ffmpeg2theora</span>
<span class="co0">##################</span>
<span class="co0">### CONFIG #######</span>
<span class="re2">MAXSIZE</span>=<span class="st0">&quot;960x540&quot;</span>
<span class="re2">SSHURL</span>=<span class="st0">&quot;username@your.webserver.com&quot;</span>
<span class="re2">SSHDIR</span>=<span class="st0">&quot;/www/video/media/&quot;</span>
<span class="co0">### END CONFIG ###</span>
&nbsp;
<span class="re2">INPUT</span>=<span class="re4">$1</span>
<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>
&nbsp;
<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>
  <span class="co0"># /usr/local/bin/growlnotify -s -i &quot;Terminal.app&quot; -m &quot;Found $FILENAME, but directory $BASENAME already exists. Aborting&quot;</span>
  <span class="kw3">exit</span> <span class="nu0">1</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>
&nbsp;
<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">-pass</span> <span class="nu0">1</span> <span class="re5">-passlogfile</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-threads</span> <span class="nu0">16</span>  -keyint_min <span class="nu0">0</span> \
<span class="re5">-g</span> <span class="nu0">250</span> -skip_threshold <span class="nu0">0</span> <span class="re5">-qmin</span> <span class="nu0">1</span> <span class="re5">-qmax</span> <span class="nu0">51</span> <span class="re5">-i</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-vcodec</span> libvpx <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="re5">-an</span> <span class="re5">-y</span> temp.webm
&nbsp;
<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">-pass</span> <span class="nu0">2</span> <span class="re5">-passlogfile</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-threads</span> <span class="nu0">16</span>  -keyint_min <span class="nu0">0</span> \
<span class="re5">-g</span> <span class="nu0">250</span> -skip_threshold <span class="nu0">0</span> <span class="re5">-qmin</span> <span class="nu0">1</span> <span class="re5">-qmax</span> <span class="nu0">51</span> <span class="re5">-i</span> <span class="st0">&quot;<span class="es2">$FILENAME</span>&quot;</span> <span class="re5">-vcodec</span> libvpx <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="re5">-acodec</span> libvorbis <span class="re5">-y</span> <span class="st0">&quot;<span class="es2">$BASENAME</span>&quot;</span>.webm
&nbsp;
<span class="kw2">rm</span> temp.webm
<span class="kw2">rm</span> <span class="sy0">*</span>.log
&nbsp;
<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>
<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>
<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></pre></div></div>


<p>The Hazel rule I’m running simply looks for files in the bucket folder with the <code>.mp4</code> extension and passes them to the shell script.</p>

<p>Let me know if you have a better way to automate this. Also, let me know if you’ve found a good way to encode h.264 from the command line on a Mac. I haven’t been able to get ffmpeg to compile with x/h.264 support yet, but it was irrelevant as I had to output <em>some</em> format to begin with. Might as well save to the one format I can’t encode properly from a shell script…</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/automated-html5-video-encoding-revisited/' rel='bookmark' title='Automated HTML5 video encoding revisited'>Automated HTML5 video encoding revisited</a></li>
<li><a href='http://brettterpstra.com/quick-notes-on-cross-browser-html5-video/' rel='bookmark' title='Quick notes on cross-browser HTML5 video'>Quick notes on cross-browser HTML5 video</a></li>
<li><a href='http://brettterpstra.com/fog-in-the-valley/' rel='bookmark' title='Fog In The Valley'>Fog In The Valley</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/automating-html5-video-encodes/">Automating HTML5 video encodes</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/automating-html5-video-encodes/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Grabbing a Mac app’s icon: Automator style</title>
		<link>http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/</link>
		<comments>http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 00:40:38 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[automator]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2030</guid>
		<description><![CDATA[<p>We’ve covered a small truckload of Bash scripting ideas for Mac and OS X in the previous two posts. It’s time to put them to use and create an Automator app that we can use as a droplet in Finder. If you skipped straight here, it probably means you don’t really want to know about the messy details of the&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/">Grabbing a Mac app’s icon: Automator style</a></p>]]></description>
			<content:encoded><![CDATA[<p>We’ve covered a small truckload of Bash scripting ideas for Mac and OS X in the previous <a href="http://brettterpstra.com/?p=2028">two</a> <a href="http://brettterpstra.com/?p=2029">posts</a>. It’s time to put them to use and create an Automator app that we can use as a droplet in Finder. If you skipped straight here, it probably means you don’t really want to know about the messy details of the scripts, so this post won’t go into a lot of Unix mumbo jumbo.</p>

<p>You can download ready-to-go versions of the workflows covered in this post here: <a href="/share/GrabIconWorkflows.zip?9d7bd4"><strong>GrabIconWorkflows.zip</strong></a>.</p>

<p>If you want to customize these workflows, you’ll need to know a little bit about the inner Bash workings, but nothing an up-and-coming nerd can’t figure out. To get started, open up Automator.app and create a new file with the “Application” preset.<span id="more-2030"></span><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/03/automator_application_workflow.jpg?9d7bd4" alt="Automator Application Workflow" /></p>

<h3>A basic workflow</h3>

<p>We’ll start with a really simple Automator application that you can drop an application onto to extract its icon at 512px and save it as a JPEG to the Desktop. One step, no interaction.</p>

<p>In your new Automator workflow, find “Run Shell Script” in the Library on the left. You can use the filter at the top to quickly narrow down the choices. Drag the action into your workflow editor on the right, and paste the following code into it:</p>

<pre><code>APPDIR=$1
ICON=`defaults read "$APPDIR/Contents/Info" CFBundleIconFile|sed -e 's/\.icns$//'`
ICONFILE="$APPDIR/Contents/Resources/$ICON.icns"
APPNAME=`basename "$APPDIR" .app`
OUTFILE="$HOME/Desktop/${APPNAME}_icon.jpg"
/usr/bin/sips -s format jpeg --resampleHeightWidthMax 512 "$ICONFILE" --out "$OUTFILE"
</code></pre>

<p>Make sure the shell is set to “/bin/bash” and change “Pass input” to “as arguments”. Save the workflow. You’ll probably want to name it something creative and put it somewhere useful, such as <code>~/Applications/512Desktop.app</code>. I have the utmost faith that you’ll come up with something brilliant. Here’s what your workflow should look like:</p>

<p><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/03/512desktopapp.jpg?9d7bd4" alt="512desktop.app" /></p>

<p>Now, you can just drop an application onto the icon for 512Desktop.app and the extracted icon will show up on your Desktop, named based on the name of the application you dropped on the workflow, with “_icon.jpg” appended to it. That was easy, right?</p>

<h3>A complete workflow with user interaction</h3>

<p>To make something more universally useful, we’ll create a workflow that asks the user where to save it. This time, we’ll output a PNG file and use the maximum available icon size. We covered how to do both of these in the last post, so I won’t go into all of the details in this one. Page back if you’re curious (or confused).</p>

<p>We’ll also need to store variables and pass multiple arguments to shell scripts in the workflow to pull this off. This is the stuff that makes Automator both awesome and frustrating, but once you get the hang of it, new possibilities open up. In this example it may seem like a lot of work just to ask a user where to save a file, but the concept allows you to get user input (without using AppleScript) in shell scripts. It’s worth knowing.</p>

<p>Create a new Automator application, just like above. Since this is going to be a droplet, the path of the Application will be passed to the first action when you run it (by dragging an app onto it). We need to store that as a variable for later, and then pass it on to the first shell script. To do so, drag the “Set Value of Variable” action from the library into your workflow. Click the dropdown for “Variable:” and choose “New variable”. Title the variable “appname”.</p>

<p>Next, drag the “Run Shell Script” action in after the variable action. Paste the following code into it:</p>

<pre><code>ICON=`defaults read "$1/Contents/Info" CFBundleIconFile|sed -e 's/\.icns$//'`
echo "$1/Contents/Resources/$ICON.icns"
</code></pre>

<p>This gets the icon file’s name and hands it back to Automator. We’ve got the application name and location, as well as the name and path of the icon file we need. We just need to know where the user wants to save it to. Add the “Ask for Finder Items” action in next, and set the prompt to “Save to:”. “Start at:” should be set to Desktop by default, but you can modify that to open the dialog to whatever directory makes sense for you. Change “Type:” to “Folders” and make sure that “Allow Multiple Section” is unchecked.</p>

<p>Now we need our <code>appname</code> variable back, so drag “Get Value of Variable” in as the next action. Set “Variable:” to “appname” (which will be available in the dropdown). The outputs of each command stack up, so now we have the icon file path, the user’s destination selection and the Application’s name (appname) all ready to pass to the final shell script as arguments ($1 $2 $3).</p>

<p>Drag in a “Run Shell Script” action as the last command. Again, set it to “/bin/bash” and pass input as arguments. Then, paste this code into it:</p>

<pre><code>APPNAME=`basename "$3" .app`
OUTFILE="$2/${APPNAME}_icon.png"
MAX=`sips -g pixelWidth "$1"|tail -1|awk '{print $2}'`
/usr/bin/sips -s format png --resampleHeightWidthMax $MAX "$1" --out "$OUTFILE"
</code></pre>

<p>Here’s what it should look like now:</p>

<p><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/03/max_png_to_user_loc.jpg?9d7bd4" alt="Max PNG to User loc" /></p>

<p>Done. Save the workflow to a file such as <code>~/Applications/SaveMaxIcon.app</code>. Try dragging an application directly onto it. You’ll be asked to choose a folder. Click “OK” and the resulting icon image file will show up in the selected location. You can stick this app on your Desktop (or alias it there) for easy access, add it to your Finder sidebar or even drag it into the toolbar of a Finder window.</p>

<p>If you want to choose an app from a dialog instead, you can insert an “Ask for Finder Items” action at the beginning of the workflow. Set “Start at:” to “/Applications”, “Type:” to “Files” and uncheck “Allow Multiple Selections”. Running the workflow will pop up a file dialog asking you to select an application manually before requesting the destination and running the rest of the script. This might be faster than finding, dragging and dropping, in some cases.</p>

<p><em>Bonus tip:</em> you can incorporate Automator workflows into shell scripts (and AppleScripts using <code>do shell script</code>) with the <code>automator</code> command line utility. You can call it directly on a workflow (<code>automator nameof.workflow</code>) or pass input to it using the –i parameter. The most practical application I can think of in this case would be to create an AppleScript application bundle containing both <code>on run</code> and <code>on open</code> handlers and both versions of the above workflow embedded in it. Then you could create a single application that would act on dropped files <em>or</em> offer a dialog if it was run directly. There’s probably an easier way to do that, though.</p>

<p>Grab copies of the workflows to get started (<a href="/share/GrabIconWorkflows.zip?9d7bd4"><strong>GrabIconWorkflows.zip</strong></a>), and I’d love to hear if you come up with other uses for them. That’s a wrap, hope it gave you some ideas for your own nerdery.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/' rel='bookmark' title='Grabbing a Mac app’s icon: building blocks'>Grabbing a Mac app’s icon: building blocks</a></li>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/' rel='bookmark' title='Grabbing a Mac app’s icon: advanced Bash usage'>Grabbing a Mac app’s icon: advanced Bash usage</a></li>
<li><a href='http://brettterpstra.com/dropbox-and-seamless-mutli-mac-computing/' rel='bookmark' title='Dropbox and seamless mutli-Mac computing?'>Dropbox and seamless mutli-Mac computing?</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/grabbing-a-mac-apps-icon-automator-style/">Grabbing a Mac app’s icon: Automator style</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Grabbing a Mac app’s icon: advanced Bash usage</title>
		<link>http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/</link>
		<comments>http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 00:35:29 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2029</guid>
		<description><![CDATA[<p>In the previous post in this series, we looked at the basic Terminal commands we’d use to grab a Mac application’s icon from the command line. In this post, we’ll flesh out the script a little and turn it into a Bash function with some added features: Logic to locate the app if it exists outside of /Applications A check&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/">Grabbing a Mac app’s icon: advanced Bash usage</a></p>]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://brettterpstra.com/?p=2028">previous post</a> in this series, we looked at the basic Terminal commands we’d use to grab a Mac application’s icon from the command line. In this post, we’ll flesh out the script a little and turn it into a Bash function with some added features:</p>

<ul>
<li>Logic to locate the app if it exists outside of /Applications</li>
<li>A check using <code>sips</code> to find the maximum available image size</li>
<li>Allow user input to set the final output size</li>
<li>Allow the user to decide whether to open the result in Preview.app</li>
</ul>

<p>We’ll also look at a very, very cool trick for adding tab-completion for application names to the <code>open -a</code> command, as well as our <code>geticon()</code> function. Yes, it’s that nerdy.</p>

<p>In the next post, we’ll use Automator to make this into a droplet we can drag apps onto from Finder. If you don’t give a flying fire truck about Terminal, you can skip straight there and create something useful without touching the command line. This one’s for the nerds (and wannabe nerds).<span id="more-2029"></span>### A for loop directory search ###</p>

<p>We’ll use a bash <code>for</code> loop to search some predefined locations. You could also use <code>mdfind</code><sup id="fnref:mdfind"><a href="#fn:mdfind" rel="footnote">1</a></sup> to let Spotlight locate the app, but we’ll keep it simple for now. I’ve set it up to look in some standard locations for the file:</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="re2">APPDIR</span>=<span class="st_h">''</span>
 <span class="kw1">for</span> <span class="kw2">dir</span> <span class="kw1">in</span> <span class="st0">&quot;/Applications/&quot;</span> <span class="st0">&quot;/Applications/Utilities/&quot;</span> <span class="st0">&quot;/Developer/Applications/&quot;</span> <span class="st0">&quot;/Developer/Applications/Utilties/&quot;</span>; <span class="kw1">do</span>
   <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re5">-d</span> <span class="co1">${dir}</span><span class="re1">$APP</span>.app <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span> 
       <span class="re2">APPDIR</span>=<span class="re1">$dir</span>
       <span class="kw3">break</span>
   <span class="kw1">fi</span>
 <span class="kw1">done</span></pre></div></div>


<p>$APPDIR is now set to the location that $APP was found, or to ” (blank) if it wasn’t found in any of the specified folders. We can check for that in the next part and fail gracefully if we didn’t find the specified app.</p>

<h3>Getting the maximum image size</h3>

<p>Modern Mac icons generally have a pixel width of 512 or greater, but some legacy applications’ icons are 256px or smaller. Finding the maximum pixel width of the image allows us to avoid creating a distorted image as a result of sizing up beyond the largest image in the .icns file. The <code>sips</code> command can do this with a little help from <code>awk</code><sup id="fnref:awk"><a href="#fn:awk" rel="footnote">2</a></sup> to clean up the output. The following command gets the <code>pixelWidth</code> property from the icon file, grabs the last line of output and removes extraneous text to leave us with just a number:</p>

<pre><code>MAXAVAIL=`sips -g pixelWidth "${APPDIR}$APP.app/Contents/Resources/$ICON.icns"|tail -1|awk '{print $2}'`
</code></pre>

<p>We could use the number we found to output a file with the maximum dimensions, but since we’re making a general-purpose function, we’ll ask the user what they want.</p>

<h3>Getting user input</h3>

<p>There are a few ways to offer options in Bash. This is the simplest route I know. It doesn’t innately allow for a lot of error checking; the user could enter letters instead of numbers or an unattainable dimension, for example. We’ll add some basic checks, but we’ll assume that you can properly enter a number when asked. You’re smart like that.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw3">echo</span> <span class="re5">-n</span> <span class="st0">&quot;Enter max pixel width (<span class="es2">$MAXAVAIL</span>): &quot;</span>
<span class="kw2">read</span> MAX
<span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$MAX</span> == <span class="st_h">''</span> <span class="sy0">||</span> <span class="re1">$MAX</span> <span class="re5">-gt</span> <span class="re1">$MAXAVAIL</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
  <span class="re2">MAX</span>=<span class="re1">$MAXAVAIL</span>
<span class="kw1">fi</span></pre></div></div>


<p>We echo the prompt (the –n keeps it from echoing a newline), and we use our previously determined $MAXAVAIL variable to set a cap. If the user’s answer is empty or larger than $MAXAVAIL, we default to $MAXAVAIL.</p>

<h3>The whole shebang</h3>

<p>Here’s a complete Bash function that you can paste at the end of your <code>~/.bash_profile</code>. It offers to open the resulting image in Preview.app, but you can easily modify that to whatever app makes sense in your workflow.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw1">function</span> geticon<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re2">APP</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="re5">-e</span> <span class="st_h">'s/\.app$//'</span><span class="sy0">`</span>
  <span class="re2">APPDIR</span>=<span class="st_h">''</span>
  <span class="kw1">for</span> <span class="kw2">dir</span> <span class="kw1">in</span> <span class="st0">&quot;/Applications/&quot;</span> <span class="st0">&quot;/Applications/Utilities/&quot;</span> <span class="st0">&quot;/Developer/Applications/&quot;</span> <span class="st0">&quot;/Developer/Applications/Utilties/&quot;</span>; <span class="kw1">do</span>
    <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re5">-d</span> <span class="co1">${dir}</span><span class="re1">$APP</span>.app <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span> 
        <span class="re2">APPDIR</span>=<span class="re1">$dir</span>
        <span class="kw3">break</span>
    <span class="kw1">fi</span>
  <span class="kw1">done</span>
  <span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$APPDIR</span> == <span class="st_h">''</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw3">echo</span> <span class="st0">&quot;App not found&quot;</span>
  <span class="kw1">else</span>
    <span class="re2">ICON</span>=<span class="sy0">`</span>defaults <span class="kw2">read</span> <span class="st0">&quot;<span class="es3">${APPDIR}</span><span class="es2">$APP</span>.app/Contents/Info&quot;</span> CFBundleIconFile<span class="sy0">|</span><span class="kw2">sed</span> <span class="re5">-e</span> <span class="st_h">'s/\.icns$//'</span><span class="sy0">`</span>
    <span class="re2">OUTFILE</span>=<span class="st0">&quot;<span class="es2">$HOME</span>/Desktop/<span class="es3">${APP}</span>_icon.jpg&quot;</span>
    <span class="re2">MAXAVAIL</span>=<span class="sy0">`</span>sips <span class="re5">-g</span> pixelWidth <span class="st0">&quot;<span class="es3">${APPDIR}</span><span class="es2">$APP</span>.app/Contents/Resources/<span class="es2">$ICON</span>.icns&quot;</span><span class="sy0">|</span><span class="kw2">tail</span> <span class="re5">-1</span><span class="sy0">|</span><span class="kw2">awk</span> <span class="st_h">'{print $2}'</span><span class="sy0">`</span>
    <span class="kw3">echo</span> <span class="re5">-n</span> <span class="st0">&quot;Enter max pixel width (<span class="es2">$MAXAVAIL</span>): &quot;</span>
  	<span class="kw2">read</span> MAX
  	<span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$MAX</span> == <span class="st_h">''</span> <span class="sy0">||</span> <span class="re1">$MAX</span> <span class="re5">-gt</span> <span class="re1">$MAXAVAIL</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
  	  <span class="re2">MAX</span>=<span class="re1">$MAXAVAIL</span>
  	<span class="kw1">fi</span>
    <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>sips <span class="re5">-s</span> format jpeg <span class="re5">--resampleHeightWidthMax</span> <span class="re1">$MAX</span> <span class="st0">&quot;<span class="es3">${APPDIR}</span><span class="es2">$APP</span>.app/Contents/Resources/<span class="es2">$ICON</span>.icns&quot;</span> <span class="re5">--out</span> <span class="st0">&quot;<span class="es2">$OUTFILE</span>&quot;</span> <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>null <span class="nu0">2</span><span class="sy0">&gt;&amp;</span><span class="nu0">1</span>
    <span class="kw3">echo</span> <span class="st0">&quot;Wrote JPEG to <span class="es2">$OUTFILE</span>.&quot;</span>
  	<span class="kw3">echo</span> <span class="re5">-n</span> <span class="st_h">'Open in Preview? (y/N): '</span>
  	<span class="kw2">read</span> ANSWER
  	<span class="kw1">if</span> <span class="br0">&#91;</span><span class="br0">&#91;</span> <span class="re1">$ANSWER</span> == <span class="st_h">'y'</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
  	  open <span class="re5">-a</span> <span class="st0">&quot;Preview.app&quot;</span> <span class="st0">&quot;<span class="es2">$OUTFILE</span>&quot;</span>
  	<span class="kw1">fi</span>
  <span class="kw1">fi</span>
<span class="br0">&#125;</span></pre></div></div>


<h3>Extra credit: tab completion for app names</h3>

<p>Before we get into making this into a GUI using Automator, wouldn’t it be cool if you could autocomplete an app name from the command line when you use this? This is where you find out that I can nerd anything to death, but let’s do it.</p>

<p>First, we need some functions to build a list of all of our available applications and provide them to Bash’s completion command. I’m modifying a script from <a href="http://www.holburn.net/">Kim Holburn</a> for this, updated to work on 10.6 and provide case-insensitive completion. Just put the file in your user’s home directory for now. When we’re done, it will also provide application name tab completion for <code>open -a</code> (and <code>o</code> if you alias o=“open –a” in your .bash_profile). Click the link below to open the script, then save it to your home folder as “.app_completions”.</p>

<p><a href="/share/app_completions"><strong>Download .app_completions</strong></a></p>

<p>Once you have that file located in <code>~/.app_completions</code>, we just need to reference it in <code>.bash_profile</code> and add a few settings. Put this near the top of <code>~/.bash_profile</code>:</p>

<pre><code>source ~/.app_completions
bind "set completion-ignore-case on"
set show-all-if-ambiguous on
alias o="open -a"
</code></pre>

<p>At the command line, run <code>source ~/.bash_profile</code>. Now, assuming you’ve also added the previous <code>geticon</code> function to <code>.bash_profile</code>, you should be able to type <code>geticon term</code> and hit tab right after the ‘m’ to have it complete to “Terminal.app” automatically. This makes it a lot easier to get the app’s name, spacing and capitalization exactly right. You’ve also aliased “o” to launch an app in the process. Type <code>o auto</code> to complete to “Automator.app” and launch it.</p>

<p>We’ll <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/">dig into Automator next</a> and turn this whole thing into something pretty.</p>

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

<li id="fn:mdfind">
<p><a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/mdfind.1.html">mdfind man page</a> <a href="#fnref:mdfind" rev="footnote">↩</a></p>
</li>

<li id="fn:awk">
<p><a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/awk.1.html">awk man page</a> <a href="#fnref:awk" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/' rel='bookmark' title='Grabbing a Mac app’s icon: Automator style'>Grabbing a Mac app’s icon: Automator style</a></li>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/' rel='bookmark' title='Grabbing a Mac app’s icon: building blocks'>Grabbing a Mac app’s icon: building blocks</a></li>
<li><a href='http://brettterpstra.com/mac-app-giveaway-textexpander/' rel='bookmark' title='Mac App Giveaway: TextExpander'>Mac App Giveaway: 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/grabbing-a-mac-apps-icon-advanced-bash-usage-2/">Grabbing a Mac app’s icon: advanced Bash usage</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Grabbing a Mac app’s icon: building blocks</title>
		<link>http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/</link>
		<comments>http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 00:30:20 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2028</guid>
		<description><![CDATA[<p>I spent a few hours last night nerding out over an easy way to grab a Mac application’s icon. I sent the basic Bash script and an example Automator action off to the other writers at TUAW. Then there was dinner, a movie, drinks and dessert. I found myself back at it when I got home. I am Jack’s complete&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/">Grabbing a Mac app’s icon: building blocks</a></p>]]></description>
			<content:encoded><![CDATA[<p>I spent a few hours last night nerding out over an easy way to grab a Mac application’s icon. I sent the basic Bash script and an example Automator action off to the other writers at TUAW. Then there was dinner, a movie, drinks and dessert. I found myself back at it when I got home. I am Jack’s complete inability to leave well enough alone<sup id="fnref:fightclub"><a href="#fn:fightclub" rel="footnote">1</a></sup>.</p>

<p>My solution ended up having some tricks in it that I thought were worth sharing, so I’m going to write it up here. This is the first post in a three-part series; an epic tribute to obsessive nerdery. It will probably eventually be summarized into the <a href="http://brettterpstra.com/howtos/">how-to section</a>, but this is the ever-so-informative longhand version.</p>

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

<h2>Introduction/excusatory verbage</h2>

<p>I use application icons quite a bit in my <a href="http://www.tuaw.com/bloggers/brett-terpstra/">writing for TUAW</a>, so having a quick way to do this is worthwhile. You may never need an application icon as a ready-to-post JPEG, but it’s worthwhile to know tricks such as how to grab, resize and convert images from the command line or how to build an Automator action which combines Finder dialogs, shell scripts and Automator variables.</p>

<p>I’ll start with the basic Terminal commands to lay a foundation.</p>

<h3>Finding an app’s icon with the defaults command</h3>

<p>On a Mac, every application is actually a folder, referred to as a “bundle”. Within that folder are libraries, executables and resources (like images and icons). There’s also an important file called Info.plist which stores information like the application’s name, identifiers, file types and–most relevant right now–the name of the file containing the application’s icon. The application icon is an an <code>.icns</code> file, stored in <code>AppName.app/Contents/Resources</code>. Its title does not have to be the same as the app’s, so–before we can extract and convert it–we need to get its actual filename from Info.plist.</p>

<p>Info.plist is stored as an XML file (as opposed to a binary plist). As such, we could grep for the filename and run a bunch of Unix commands to parse out the filename, but there’s an easier and more reliable way to do it using the <code>defaults</code><sup id="fnref:defaults"><a href="#fn:defaults" rel="footnote">2</a></sup> command built into OS X. <code>defaults</code> reads plist files and can output the value of specific keys. The key we want is <code>CFBundleIconFile</code>, which holds the icon’s filename. We’ll assume that we’ve already retrieved the name of the app and stored it in a variable called <code>$APP</code>. Here’s what you would run on the command line:</p>

<pre><code>defaults read "/Applications/$APP.app/Contents/Info" CFBundleIconFile
</code></pre>

<p>The response may or may not have a file extension (.icns). We want to trim the extension if it exists so that we have a clean foundation to build on. You can do this with several different Unix utilities, including basic bash substitution; we’ll stick with <code>sed</code><sup id="fnref:sed"><a href="#fn:sed" rel="footnote">3</a></sup> for now. We pipe (<code>|</code>) the output of the <code>defaults</code> command into <code>sed</code>, and remove “.icns” if it exists:</p>

<pre><code>defaults read "/Applications/$APP.app/Contents/Info" CFBundleIconFile|sed -e 's/\.icns$//'
</code></pre>

<h3>Converting the icon file to an image format</h3>

<p>The .icns format holds multiple versions of the icon, and doesn’t do us much good if we want an image file for the web. Fortunately, the built-in command <code>sips</code> can do some neat tricks with it, including converting it to various formats<sup id="fnref:macworld1"><a href="#fn:macworld1" rel="footnote">4</a></sup>. We know what the icon file is titled now, and we know where to look for it. We just build a <code>sips</code> command to read it, convert it and output the result.</p>

<p>The <code>-s format</code> parameter sets an output format in sips. This can be one of many formats, but we’ll use the JPEG format for this example. This will compress the result to a web jpeg with a solid, white background. Using the PNG format instead would preserve the transparency, so if you need to do other image manipulation, you can substitute “png” for “jpeg”.</p>

<p>Let’s use the $APP variable we’ve created to set a default output filename on the Desktop. For now, we’re assuming the app exists in the standard /Applications folder (I’ll show a more complex workflow for locating the app in a bit). We’re also assuming that we’ve stored the result of the above <code>defaults</code> command in <code>$ICON</code>.</p>

<pre><code>OUTFILE="$HOME/Desktop/${APP}_icon.jpg"
sips -s format jpeg "/Applications/$APP.app/Contents/Resources/$ICON.icns" --out $OUTFILE
</code></pre>

<p>Now we have the basic pieces we can use to build a script to automate this from the command line. Here’s an example which expects the application name as the only argument, properly cased:</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0">#!/bin/bash</span>
&nbsp;
<span class="re2">APP</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="re5">-e</span> <span class="st_h">'s/\.app$//'</span><span class="sy0">`</span>
<span class="co0"># Removes &quot;.app&quot; if it was passed</span>
&nbsp;
<span class="re2">ICON</span>=<span class="sy0">`</span>defaults <span class="kw2">read</span> <span class="sy0">/</span>Applications<span class="sy0">/</span><span class="re1">$APP</span>.app<span class="sy0">/</span>Contents<span class="sy0">/</span>Info CFBundleIconFile<span class="sy0">|</span><span class="kw2">sed</span> <span class="re5">-e</span> <span class="st_h">'s/\.icns$//'</span><span class="sy0">`</span>
<span class="co0"># Removes &quot;.icns&quot; if the Info.plist value includes it</span>
<span class="co0"># Harcoded for /Applications, needs to be rewritten for other locations or droplets</span>
&nbsp;
<span class="co0">## Save icon on Desktop in JPEG format, resized to 256 max width/height</span>
<span class="re2">OUTFILE</span>=<span class="st0">&quot;<span class="es2">$HOME</span>/Desktop/<span class="es3">${APP}</span>_icon.jpg&quot;</span>
<span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>sips <span class="re5">-s</span> format jpeg <span class="st0">&quot;/Applications/<span class="es2">$APP</span>.app/Contents/Resources/<span class="es2">$ICON</span>.icns&quot;</span> <span class="re5">--out</span> <span class="re1">$OUTFILE</span></pre></div></div>


<h2>Extra credit: image optimization</h2>

<p>Since we’re automating, we can add a final step to the script to handle whatever steps we would normally take next. For example, we could open it in <a href="http://skitch.com/">Skitch</a> for quick resizing, or in <a href="http://flyingmeat.com/acorn/">Acorn</a> for more complex manipulation. If we saved a JPEG to a size we already know is correct for our purposes, we could open it straight in an optimizer such as <a href="http://imageoptim.pornel.net/">ImageOptim</a> to quickly improve the compression. We could also make use of a command line utility like ImageMagick, jpegtran or pngcrush, all of which require some installation and extra work. If you have them, great, if not, that’s an article for another time.</p>

<p><em>For the record, Skitch saves horribly large JPEGs, whereas Acorn saves amazingly well-compressed images. If you resize with Skitch, you’ll want to compress it with something else as well.</em></p>

<p>Assuming we’re using an application and not a CLI utility, we can use the <code>open</code> command to send the resulting file to the app. We can also avoid some confusion by initially saving the converted icon file to a default temporary directory and then opening it from there. Here’s a revised script that does that, then opens the final image in Acorn for quick resizing and saving to any location. We’ll use the PNG format to preserve the original transparency, and you can substitute any graphics application for Acorn:</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="co0">#!/bin/bash</span>
&nbsp;
<span class="re2">APP</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="re5">-e</span> <span class="st_h">'s/\.app$//'</span><span class="sy0">`</span>
<span class="co0"># Removes &quot;.app&quot; if it was passed</span>
&nbsp;
<span class="re2">ICON</span>=<span class="sy0">`</span>defaults <span class="kw2">read</span> <span class="sy0">/</span>Applications<span class="sy0">/</span><span class="re1">$APP</span>.app<span class="sy0">/</span>Contents<span class="sy0">/</span>Info CFBundleIconFile<span class="sy0">|</span><span class="kw2">sed</span> <span class="re5">-e</span> <span class="st_h">'s/\.icns$//'</span><span class="sy0">`</span>
<span class="co0"># Removes &quot;.icns&quot; if the Info.plist has it</span>
<span class="co0"># Harcoded for /Applications, needs to be rewritten for other locations or droplets</span>
&nbsp;
<span class="co0">## Output file to a temp directory (TMPDIR) as a PNG and open in Acorn for resizing and conversion</span>
&nbsp;
<span class="re2">OUTFILE</span>=<span class="st0">&quot;<span class="es2">$TMPDIR</span><span class="es3">${APP}</span>_icon.png&quot;</span>
sips <span class="re5">-s</span> format png <span class="st0">&quot;/Applications/<span class="es2">$APP</span>.app/Contents/Resources/<span class="es2">$ICON</span>.icns&quot;</span> <span class="re5">--out</span> <span class="re1">$OUTFILE</span>
open <span class="re5">-a</span> <span class="st0">&quot;Acorn.app&quot;</span> <span class="re1">$OUTFILE</span></pre></div></div>


<p>I think you get the idea. You can take this script and easily adjust the output format and destination application. In the <a href="http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/">next post</a>, we’ll cover making this into a fully customized Bash function, with some extra goodies.</p>

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

<li id="fn:fightclub">
<p>Oh, you got the Fight Club reference, huh? You’re still not a snowflake. <a href="#fnref:fightclub" rev="footnote">↩</a></p>
</li>

<li id="fn:defaults">
<p><a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/defaults.1.html">defaults man page</a> <a href="#fnref:defaults" rev="footnote">↩</a></p>
</li>

<li id="fn:sed">
<p><a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/sed.1.html">sed man page</a> <a href="#fnref:sed" rev="footnote">↩</a></p>
</li>

<li id="fn:macworld1">
<p><a href="http://www.macworld.com/article/60156/2007/09/sipsicns.html">“Convert ICNS files with sips”</a> via Macworld. <a href="#fnref:macworld1" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-automator-style/' rel='bookmark' title='Grabbing a Mac app’s icon: Automator style'>Grabbing a Mac app’s icon: Automator style</a></li>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/' rel='bookmark' title='Grabbing a Mac app’s icon: advanced Bash usage'>Grabbing a Mac app’s icon: advanced Bash usage</a></li>
<li><a href='http://brettterpstra.com/bored-with-your-macvim-icon-me-too/' rel='bookmark' title='Bored with your MacVim icon? Me too.'>Bored with your MacVim icon? Me too.</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/grabbing-a-mac-apps-icon-building-blocks/">Grabbing a Mac app’s icon: building blocks</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/grabbing-a-mac-apps-icon-building-blocks/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Quick calculations in Bash</title>
		<link>http://brettterpstra.com/quick-calculations-in-bash/</link>
		<comments>http://brettterpstra.com/quick-calculations-in-bash/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 04:34:52 +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[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1761</guid>
		<description><![CDATA[<p>This is probably going to seem stupid, but every time I decide to do something in Bash that should only take me a minute, I end up losing an hour. I obsess over “better” ways to do everything. Not surprisingly, my motivation often wanes before I actually find the better, more elegant way, so these little projects end up lackluster.&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-calculations-in-bash/">Quick calculations in Bash</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/02/calculatorretrop.jpg?9d7bd4" alt="Retro Calculator image" border="0" width="268" height="328" class="alignright" />This is probably going to seem stupid, but every time I decide to do something in Bash that should only take me a minute, I end up losing an hour. I obsess over “better” ways to do everything. Not surprisingly, my motivation often wanes before I actually find the better, more elegant way, so these little projects end up lackluster. Fortunately, I end up learning all kinds of new, mostly unrelated things in the process, which is what happened this evening. It’s amazing to me that I use UNIX every day, and can still be blown away by a new trick every time I go digging on Stack Overflow. There are some very, very smart people out there.</p>

<p>Anyway, I had two goals: first, I wanted a basic calculator on the command line with the ability to optionally output a result with no newlines, so it would be easy to substitute within another command or pass to <code>pbcopy</code>. Basic inline math. Then, as a side project to this side project, I wanted a tally-keeper that would allow me to just keep inputting numbers until I told it to stop, and then just add them all up. Nothing brilliant, and I had simple answers for both problems in about 10 minutes.</p>

<p>Built-in evaluators in Bash kind of stink, though, and they need special formatting and escaping to deal with floats and accommodate basic symbols. <a href="http://man.cx/bc"><code>bc</code></a> seemed like the logical answer to that, and that’s what I’m using right now. I picked up a few good tips from the blog post that Allan Odgaard wrote when he was on <a href="http://sigpipe.macromates.com/2005/07/26/shell-calculator/">a similar mission</a>, both from Allan and from the commenters. I love the web.</p>

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

<p>So here’s what I’ve got for the calculator. It strips any character that’s not grade-school math out and normalizes spaces, which works well for my needs. You can actually just trash the whole second line and pass “$@” to bc if you want to use additional symbols. The second function in this block calls the first and strips newlines, good for integration elsewhere. You can also alias either of these to a question mark for fast access (inspired by Allan) with <code>alias ?="calc"</code> in your <code>.bash_profile</code>. That’s where these functions are likely to go as well. If you want to try them out, paste them into ~/.bash_profile, save it, run <code>source ~/.bash_profile</code> in Terminal and then type <code>calc 3+(5*2)</code> or whatever you like.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw1">function</span> calc<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re2">equat</span>=$<span class="br0">&#40;</span><span class="kw3">echo</span> <span class="co1">${@//[^0-9\.\+\/\*\(\)]/ }</span><span class="sy0">|</span> <span class="kw2">sed</span> <span class="sy0">&amp;</span><span class="co0">#x27;s/[ \t]*//g&amp;#x27;)</span>
  <span class="kw3">echo</span> <span class="re1">$equat</span><span class="sy0">|</span><span class="kw2">bc</span> <span class="re5">-lq</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co0">## just for fun, ccalc trims the newline </span>
<span class="co0">## and copies the result directly to the clipboard</span>
<span class="kw1">function</span> ccalc <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  calc $<span class="sy0">@|</span><span class="kw2">tr</span> <span class="re5">-d</span> <span class="sy0">&amp;</span><span class="co0">#x27;\n&amp;#x27;|pbcopy</span>
<span class="br0">&#125;</span></pre></div></div>


<p>Things get tricky if you need to control the number of decimal places you have in the result. You need to pass additional commands to <code>bc</code>, which appears to require some heredoc magic. This works for me (the scale=4 sets it to four decimal places):</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw1">function</span> calc2<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw2">bc</span> <span class="re5">-l</span> <span class="co2">&lt;&lt; EOF
scale=4
$@
quit
EOF</span>
<span class="br0">&#125;</span></pre></div></div>


<p>Next up is <code>tally()</code>, a function that does what it says. You can either pass it a list of numbers, or run it and let it go into interactive mode. It will let you type numbers separated by returns, spaces or a combination, as long as there’s a separation. When you press “=” it adds up all of the numbers you’ve entered. I wanted it for when people start giving me numbers and amounts on the phone. And yes, I can do it in LaunchBar (et al), but like I said, sometimes I just get a bug to do it the hard way. The only thing I hate about this implementation is that you can’t use the default mapping of the Backspace key, as everything is interpreted raw. You have to run <code>read</code> in readline mode to avoid this, but that means you can’t use Enter anymore. That’s the kind of thing that makes me spend an hour trying to solve it. This version is my compromise; you can try it with the “-e” argument and see if you prefer backspace to enter. Same installation: paste it, source and run it.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw1">function</span> tally<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="br0">&#91;</span> <span class="re4">$#</span> == <span class="nu0">0</span> <span class="br0">&#93;</span><span class="br0">&#93;</span>; <span class="kw1">then</span>
    <span class="kw3">echo</span> <span class="st0">&quot;Enter numbers, press = for sum:&quot;</span>
    <span class="kw2">read</span> <span class="re5">-d</span> <span class="st0">&quot;=&quot;</span>
    <span class="re2">input</span>=<span class="re1">$REPLY</span>
    <span class="kw3">echo</span> <span class="st0">&quot;================&quot;</span>
  <span class="kw1">else</span>
    <span class="re2">input</span>=<span class="st0">&quot;$@&quot;</span>
  <span class="kw1">fi</span>
  <span class="re2">sum</span>=<span class="nu0">0</span>
  <span class="kw1">for</span> i <span class="kw1">in</span> <span class="re1">$input</span>; <span class="kw1">do</span> 
    <span class="re2">sum</span>=<span class="re1">$sum</span>+<span class="re1">$i</span>
  <span class="kw1">done</span>
  <span class="kw3">echo</span> <span class="re1">$sum</span><span class="sy0">|</span><span class="kw2">bc</span> <span class="re5">-l</span>
<span class="br0">&#125;</span></pre></div></div>


<p>And that, ladies and gentleman, is your dose of stupid Bash tricks for the evening. Good night.</p>
<p>Related posts:<ol>
<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-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>
<li><a href='http://brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2/' rel='bookmark' title='Grabbing a Mac app’s icon: advanced Bash usage'>Grabbing a Mac app’s icon: advanced Bash usage</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-calculations-in-bash/">Quick calculations in Bash</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-calculations-in-bash/feed/</wfw:commentRss>
		<slash:comments>0</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>
	</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/167 queries in 1.142 seconds using xcache
Object Caching 4433/4584 objects using xcache
Content Delivery Network via cdn2.brettterpstra.com

Served from: brettterpstra.com @ 2012-05-23 02:17:12 -->
