<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Eliot's Website</title>
	
	<link>http://www.eliotlash.com</link>
	<description />
	<lastBuildDate>Sat, 12 May 2012 04:41:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<feedburner:info uri="eliotlash" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://www.eliotlash.com/feed/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://www.eliotlash.com/feed/" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Fwww.eliotlash.com%2Ffeed%2F" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item>
		<title>Processing for Programmers</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/EbSG6hpaOMs/</link>
		<comments>http://www.eliotlash.com/2011/08/processing-for-programmers/#comments</comments>
		<pubDate>Sat, 27 Aug 2011 17:00:08 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Game Development]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[processing]]></category>
		<category><![CDATA[processing.org]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=498</guid>
		<description><![CDATA[Processing is a wonderful little language. It&#8217;s designed to be easy to pick up by artists who want to learn some programming, etc. However, it&#8217;s a real programming language. If you haven&#8217;t played with Processing, I&#8217;d recommend you go do that right now. They have a great series of tutorials, and of course the entire SDK is [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://processing.org/"><img class="alignright" title="Processing Logo" src="http://eliot.s3.amazonaws.com/eliotlash.com/processing_med.png" alt="" width="128" height="128" />Processing</a> is a wonderful little language. It&#8217;s designed to be easy to pick up by artists who want to learn some programming, etc. However, it&#8217;s a real programming language. If you haven&#8217;t played with Processing, I&#8217;d recommend you go do that right now. They have <a href="http://processing.org/learning/">a great series of tutorials</a>, and of course <a href="http://processing.org/download/">the entire SDK is free</a>.</p>
<p>This post is for people like me &#8211; programmers who want to take  advantage of Processing&#8217;s short iteration cycle, clear syntax, and <a href="http://processing.org/reference/">simple API</a> to use it as a prototyping environment.</p>
<p>First, here is what I think Processing excels at:</p>
<ul>
<li>Interactivity &#8211; It&#8217;s dead easy to get and use <a href="http://processing.org/reference/mouseClicked_.html">mouse</a> and <a href="http://processing.org/reference/keyPressed_.html">keyboard</a> input and define event handlers.</li>
<li>Graphics &#8211; &#8220;Hello world&#8221; in Processing is <a href="http://processing.org/learning/gettingstarted/">drawing a circle</a>. It has a simple but powerful graphics API. <a href="http://processing.org/learning/drawing/">2D is really simple</a>, and it has powerful features that can be used without any boilerplate such as <a href="http://processing.org/learning/3d/">3D rendering</a> and a <a href="http://processing.org/learning/transform2d/">matrix stack</a>.</li>
<li>Engineering flow &#8211; like I said above, the short iteration cycle, clear syntax, and <a href="http://processing.org/reference/">simple API</a> make it a breeze to get up and running quickly and iterating.</li>
<li>Fun &#8211; Because of all of that, it&#8217;s a lot of fun to write stuff in Processing, especially for smaller projects where you are just messing around.</li>
<li>Multiplatform &#8211; Out of the box, Processing 1.5 can build native applications for Windows, Mac, and Linux, <a href="http://wiki.processing.org/w/Android">native Android applications</a>, and web applets (yuck.) Via <a href="http://processingjs.org/">Proccessing.js</a> you can also supposedly get your sketches to run natively in web browsers.</li>
</ul>
<p>Here is what I think Processing is weak at:</p>
<ul>
<li>Large, complex programs (they tend to get a bit unwieldy since it&#8217;s impossible to organize your classes inside a folder structure.)</li>
<li>Programmer assistance (No out-of-the-box debugger. The preprocessor&#8217;s errors are often frustratingly non-specific, and can leave you blindly hunting for syntax errors across multiple files.)</li>
<li>Audio <del>(there is no out-of-the-box support, but there are <a href="http://processing.org/reference/libraries/">libraries available</a>)</del> Processing now includes the excellent <a href="http://code.compartmental.net/tools/minim/">Minim library</a>, but you have to explicitly import it. Audio still appears to be an afterthought in the documentation and tutorials.</li>
</ul>
<p><iframe width="500" height="281" src="http://www.youtube.com/embed/2Z99TtxGjds?fs=1&#038;feature=oembed" frameborder="0" allowfullscreen></iframe></p>
<p>I have been prototyping games and visualizers (including the one above) in Processing for several months now, and have learned some incredibly useful things that I think any programmer looking into it should know. Here they are:</p>
<p><span id="more-498"></span></p>
<h1>Processing is Java.</h1>
<p>This took me a really long time to realize. I mean, it <strong>really</strong> is just Java, with a slightly simpler syntax. When you hit &#8220;Run,&#8221; processing runs your .pde files through a preprocessor that converts them into one giant Java class. Your classes are all inner classes of your main class, which extends PApplet. This is how all of your custom objects can access &#8220;global&#8221; variables and functions defined in your main class, as well as all the Processing API methods. No magic.</p>
<p>What this means is that out-of-the-box, you can use tons of classes from the Java standard library. My absolute favorites here are Java&#8217;s generic collections&#8230; <a href="http://download.oracle.com/javase/1,5.0/docs/api/java/util/HashMap.html">HashMap&lt;K, V&gt;</a> and <a href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/ArrayList.html">ArrayList&lt;E&gt;</a>. In the Processing documentation, they have lots of examples using the non-generic versions of ArrayList and HashMap. This means that you have to manually unbox (cast) items coming out of those collections. What a pain. Don&#8217;t bother, just use generics!</p>
<p>You can also use Java&#8217;s for-each syntax to iterate through these collections rather than manually using the iterator as they describe in their documentation. For example, the following is perfectly valid in Processing, you don&#8217;t even need to import java.util (that&#8217;s part of the default Processing imports behind the scenes):</p>
<pre class="brush: java; title: ;">
HashMap&lt;String, String&gt; hm = new HashMap&lt;String,String&gt;();
hm.put(&quot;somekey&quot;,&quot;foo&quot;);
for(String item : hm.values() ){
     println(item);
}
</pre>
<p>A trivial example, but generic collections are extremely useful, since you can lean on the compiler to keep track of the types you&#8217;re using. It&#8217;s a bit more verbose to create these objects, but it&#8217;s much less verbose to use them.</p>
<h1>Processing is not Java.</h1>
<blockquote><p>Processing is based on Java, but because program elements in Processing are fairly simple, you can learn to use it even if you don&#8217;t know any Java. If you&#8217;re familiar with Java, it&#8217;s best to forget that Processing has anything to do with Java for a while, until you get the hang of how the API works. &#8211; <a href="http://processing.org/learning/overview/">Ben Fry</a></p></blockquote>
<p>It really <em>is</em> a good idea to try to discard your preconceptions about Java when first learning Processing. You don&#8217;t need to be quite as verbose as in Java, and there&#8217;s less technical overhead.</p>
<p>So, I&#8217;d recommend that you forget that Processing is Java when you are first learning it. But, if you are able, keep it in the back of your mind, so you can avoid some of the simplistic kludges put forward in the Processing documentation (the main thing that comes to mind for me is using generic collections and for-each loops.) Once you are familiar with Processing idioms, then it&#8217;s great to know what&#8217;s going on under the hood so you can leverage the more powerful Java stuff.</p>
<p>This also leads into the next most important thing on my list:</p>
<h1>You can use a real debugger.</h1>
<p>I have had many headaches trying to debug runtime errors in my sketches without the assistance of a modern interactive debugger. I had started getting used to print debugging to figure out what was going on, but in something as complicated as a game engine, I was really hurting for a real debugger. Then I discovered an awesome trick.</p>
<div>If you are only developing for desktop OSes, you might want to try out writing Processing inside of an IDE. Here&#8217;s an article on <a href="http://processing.org/learning/eclipse/">Processing in Eclipse</a>. However, as of Processing 1.5, it would be non-trivial to do this and take advantage of the low-friction Android support as well. I need my prototype to run on Android, so I choose to keep my sources in .pde files, which I can use to build for desktop OSes and Android from essentially the same code base. I figured out how to do that AND use a real debugger.</div>
<div>The first step is to export the Java version of your sketch:</div>
<div>
<p>Run and then quit your sketch to ensure your build products are up to date. Click on File -&gt; Export Application. Check only your development platform. Click export.</p>
<p>If you navigate to the export folder, you will find a .java file that&#8217;s named after your main class. This is the .java file that Processing creates from your .pde files and passes to the Java compiler. This is great news, because you can load this into a real Java debugger and hunt down nasty runtime bugs in style. And those incomprehensible line numbers in runtime exceptions will now map to actual locations in your code!</p>
<p>Here&#8217;s how I set up NetBeans as my Processing debugger (<a href="http://www.eclipse.org/downloads/">Eclipse</a> probably works just as well but I have not set that up.) This is a one-time deal for each sketch, afterwards all I need to do is re-export the sketch in order to update the code I&#8217;m debugging against.</p>
<ol>
<li><a href="http://netbeans.org/downloads/">Install NetBeans for Java SE</a> if you don&#8217;t have it already</li>
<li>File -&gt; New Project -&gt; Java -&gt; Java Project with Existing Sources, click Next</li>
<li>Name your project something meaningful and click Next</li>
<li>On the right of the list for &#8220;Source Package Folders&#8221;, click &#8220;Add Folder&#8230;&#8221;</li>
<li>Select the export folder inside your sketch folder that contains the .java file (application.YOUR-PLATFORM/source), click Next</li>
<li>Under includes, delete the text there, enter &#8220;*.java&#8221;, click Finish</li>
<li>File -&gt; Project Properties -&gt; Run, click &#8220;Browse&#8221; next to the &#8220;Working Directory&#8221; field. Select the main folder of your sketch and click &#8220;Open.&#8221;</li>
<li>Locate core.jar as described in step 3 of &#8220;<a href="http://processing.org/learning/eclipse/">Processing in Eclipse</a>.&#8221; If you&#8217;re on a Mac, you&#8217;re better off copying core.jar to some other location since the file picker is lame and won&#8217;t let you go inside an app bundle.</li>
<li>File -&gt; Project Properties -&gt; Libraries -&gt; Add JAR/Folder. Locate and select core.jar.</li>
<li>If you are using any Processing libraries, you should also locate their jar files and add them to the classpath.</li>
</ol>
<p>Phew! At least we only need to do that once. And now it should be all set up for your debugging pleasure.</p>
<div>Since the project is set up to load external sources, just re-run your sketch and re-export the sources from within the Processing Development Environment (PDE) to make them update instantly inside NetBeans. It&#8217;s awesome.</div>
<div>The Java source is similar enough to the Processing source that I always know what line to fix after I hunt down the bug. I then make the fix in the .pde version &#8211; the .java file will be overwritten by the Processing export the next time I need to debug.</div>
<div>Another neat thing I like is using the navigator to peruse my inner classes. Holding the Option/Alt key and clicking the top-level arrow, and then normal clicking it again gives a compact overview of all my inner classes that I can then selectively expand and click to jump to the appropriate field or method. This is helpful for locating places to set breakpoints and watches.</div>
</div>
<h1>You can use a real text editor.</h1>
<p>In the PDE, select Preferences -&gt; Use external editor. If you are like me and <a href="http://www.eliotlash.com/2011/08/searching-for-the-perfect-editor/">believe that mastering a powerful text editor is a worthwhile investment of your time</a>, you are free to use your favorite editor when making Processing sketches. The built-in editor in the PDE is okay, but very basic. I am using Vim with <a href="http://www.vim.org/scripts/script.php?script_id=2115">this ftplugin for Processing</a>. It supports syntax highlighting, indentation, and documentation lookup via shift+K. It is wonderful. I keep the PDE open in the margin of my screen to do the build and provide a place to display output, it still can be helpful sometimes in locating the line of a NullPointerException, etc.</p>
<p><a href="http://processing.org/discourse/yabb2/YaBB.pl?num=1227824942/6">Apparently</a> there is also a way to call the Processing build without using the PDE but I&#8217;m sure it&#8217;s not as well tested as that little Run button, so I decided not to muck around with it.</p>
<h1>Git is your friend.</h1>
<p>If you are comfortable using Git, this is a no brainer. Just &#8220;<strong>git init</strong>&#8221; your sketch folder, add your code, and commit. Git is really a helpful tool when working with Processing, especially because the preprocessor is so finicky and unhelpful. I like to stash or stage good versions of my code as I develop, so I always have a version to roll back to if I&#8217;m getting syntax errors from an unknown location and the code is clearly FUBAR. Making commits during logical stopping points on features is great, and much cleaner than making a bunch of copies of a sketch. Plus, it makes backing up your sketches stupid easy if you have a remote git repo such as <a href="http://github.com/">GitHub</a>. I recently have used git&#8217;s best debugging tool, <strong><a href="http://progit.org/book/ch6-5.html">git bisect</a></strong>, to hunt down a nasty bug. Git helped me do a binary search through my revision history and track down the commit that introduced the bug, which was a different commit than I had expected. I was able to immediately hunt down and fix the bug since bisect revealed that it was data-side (all I had committed was data,) so I knew where to look.</p>
<p>I also use Git to painlessly manage a master development branch, and an Android branch (since Java doesn&#8217;t have #ifdefs&#8230;) More on that later.</p>
<p>If you don&#8217;t know Git, why not start now? Next to my text editor, it&#8217;s my favorite programming tool. I&#8217;d recommend reading the first few chapters of <a href="http://hginit.com/">Hg Init</a> and <a href="http://progit.org/book/">Pro Git</a>, which are freely available online.</p>
<h1>Android development is frictionless.</h1>
<p>You do need to have the <a href="http://developer.android.com/sdk/index.html">Android SDK</a> installed and set up first - <a href="http://wiki.processing.org/w/Android">one-time setup instructions and more details are on the Processing wiki</a>. That can be a bit of an adventure if you&#8217;ve never done it before. <a href="http://developer.android.com/sdk/installing.html">Follow the SDK install docs carefully</a> along with the instructions on the Processing wiki and you should be okay.</p>
<p>After that is set up, if you&#8217;re not using any special libraries, it may be as easy as selecting &#8220;Android&#8221; from that drop-down menu in the PDE and clicking &#8220;Run.&#8221;</p>
<p>I was using the <a href="http://creativecomputing.cc/p5libs/proxml/">proxml library</a> in my sketch that I wanted to convert to Android, so I had to comment out all of the deserialization code that used proxml. Not a big deal, as that was just for saving levels, I was using processing.xml for loading levels, so loading still works.</p>
<p>I did this on a separate git branch, so all the Android-specific project files live on the Android branch only, along with Android-specific input code and a handful of display code (locking screen orientation, and not specifying an explicit window size.)</p>
<p>After getting everything set up as described above, I have achieved pretty much frictionless multi-platform development, using Git to manage my workflow. This is going really well so far&#8230; I do my development on master, and then merge master into my Android branch. Many times the merge is automatic. Occasionally there is a minor conflict that is easy to resolve. I close the sketch in the PDE before switching branches which doesn&#8217;t take too long and ensures that it loads my Android settings.</p>
<p>There are a few differences when developing for Android, but overall the development experience is pretty much frictionless, and the Processing APIs are nearly identical. Again, <a href="http://wiki.processing.org/w/Android">check out the Processing wiki</a> for more details.</p>
<h1>Processing helps you learn <a href="http://www.arduino.cc/">Arduino</a>.</h1>
<p>Another fun benefit of learning Processing is that it&#8217;s very similar to the <a href="http://arduino.cc/en/Reference/HomePage">Arduino programming language</a>. If you have ever wanted to mess around with writing software for a microcontroller that can be hooked up to all sorts of crazy electronic doodads and do really cool stuff, this is a great entry point into that whole world! It&#8217;s probably the friendliest microcontroller on the market right now and it&#8217;s pretty affordable too, well worth checking out if you have a bit of a tinkering instinct.</p>
<h1>That&#8217;s all, for now</h1>
<p>I hope you enjoyed this overview of advanced topics in Processing. I will continue to use Processing to prototype ideas &#8211; I like it even more now that I can use it like a modern programming language, and being able to iterate quickly on a game prototype that works on both PCs and smartphones is a boon. If I learn more, I&#8217;ll update this article or write a new one.</p>
<p>If you haven&#8217;t used Processing, I&#8217;m amazed you made it to the end of this article! Go check it out, learn it, and maybe come back and read this again in a few weeks when you will be more able to absorb it. Thanks, and let me know if you have any questions or comments! <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/EbSG6hpaOMs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/08/processing-for-programmers/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/08/processing-for-programmers/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=processing-for-programmers</feedburner:origLink></item>
		<item>
		<title>Searching for the perfect editor</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/diGDXFmvBfU/</link>
		<comments>http://www.eliotlash.com/2011/08/searching-for-the-perfect-editor/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 17:46:34 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[editor]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=383</guid>
		<description><![CDATA[Text editors. Yawn. Who cares? It&#8217;s just text! For many people, it really doesn&#8217;t make a difference. But I&#8217;m a programmer. I edit code for a living. My editor is the tool of my trade and I want to use the most efficient tool available. I&#8217;d be preaching to the choir if I was telling [...]]]></description>
			<content:encoded><![CDATA[<p>Text editors. Yawn. Who cares? It&#8217;s just text!</p>
<p>For many people, it really doesn&#8217;t make a difference. But I&#8217;m a programmer. I edit code for a living. My editor is the tool of my trade and I want to use the most efficient tool available.</p>
<p style="text-align: center;"><a href="http://tnerual.eriogerg.free.fr/0xBABAF000L/10_en.html"><img class="aligncenter" title="Emacs vs Vi, taken from 0xBABAF000L" src="http://eliot.s3.amazonaws.com/eliotlash.com/0010_en_vi-vs-emacs.png" alt="" width="800" height="254" /></a></p>
<p>I&#8217;d be preaching to the choir if I was telling programmers that they should use good text editors. But I&#8217;ve noticed some patterns in the history of text editors I&#8217;ve used that have made me come up with my own philosophy about choosing an editor. My goals and usage habits are certainly not the same as everyone else&#8217;s, but I hope that in sharing them I might get you to reflect on your own habits and see if they match up to your goals.</p>
<p><span id="more-383"></span></p>
<p>I have used many different text editors over the years, starting with the crappy built-in editor for <a href="http://en.wikipedia.org/wiki/IBM_BASICA">BASICA</a>. I&#8217;ve used <a href="http://en.wikipedia.org/wiki/Notepad_(software)">Notepad</a>, <a href="http://liquidninja.com/metapad/">Metapad</a>, <a href="http://en.wikipedia.org/wiki/Pico_(text_editor)">Pico</a>/<a href="http://www.nano-editor.org/">Nano</a>, <a href="http://en.wikipedia.org/wiki/TextEdit">TextEdit</a>, <a href="http://www.codingmonkeys.de/subethaedit/">SubEthaEdit</a>, <a href="http://www.barebones.com/products/bbedit/">BBEdit</a>/<a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a>, <a href="http://notepad-plus-plus.org/">Notepad++</a>, <a href="http://www.vim.org/">Vim</a>, <a href="http://www.microsoft.com/visualstudio/en-us">Visual Studio</a>, and <a href="http://netbeans.org/">NetBeans</a> to name a few. My reasons for switching (or using more than one editor) were various. I was moving to a different OS, or using multiple OSes. I found an editor with a cooler feature set than my current one and I wanted to check it out. The editor was recommended to me by a friend or teacher. I was learning a new programming language that was highly IDE-centric (like C# and Java) and it made sense to adopt a respective IDE.</p>
<p>I noticed something making all of these jumps between editors. There&#8217;s a friction that occurs when switching, a penalty. When I had been using my previous editor I was developing muscle memory from repeated use of certain keystrokes to perform a task. In my next editor I&#8217;d habitually hit whatever key I was using in my previous editor for find, find and replace, save, copy, etc. This annoyed me a bit as I had to spend a good amount of time re-training my reflexes to use different keys, to get back up to the speed and subconscious efficiency I had in my previous editor. I began realizing that it was counterproductive to my efficiency to keep switching editors every couple of years. It made sense to pick one editor as my main editor and stick to it so I could <strong>retain and build off my muscle memory, a valuable byproduct of using the same editor </strong>for a long time. Muscle memory is valuable because it allows our conscious mind to think of an action, but our reflexes to execute it instantly. It can only be acquired through repetitions of an action.</p>
<blockquote><p>&#8230; This phenomenon is sometimes called &#8220;muscle memory&#8221;, a phrase that tellingly gives credit to an organ other than the brain. The brain is really in charge, of course, but the term rings true because the actions seem to happen without conscious thought. This is the ultimate in efficiency, leaving the higher-functioning parts of the brain free to concentrate on the task, rather than on the operation of the tool required to complete the task.</p>
<p>-<a href="http://arstechnica.com/apple/reviews/2003/04/finder.ars/4">John Siracusa</a></p></blockquote>
<p>Somewhere along the line, somebody suggested I check out Vim, an improved version of the Vi editor. I ran my own Linux server so I was slightly familiar with Vi, as is any Unix user (it has a way of popping up from time to time since it&#8217;s the default editor.) I knew one command, how to quit it! I found this arcane, cryptic editor really off-putting and unnecessarily complicated. What was wrong with Nano for editing HTML pages on my server?</p>
<p>The guy eventually convinced me to try learning Vim using a program called <strong>vimtutor</strong>. I tried the tutorial. It still seemed arcane and cryptic, but as I worked through it more, I started seeing some crazy possibilities. Vim possesses a succinct and powerful syntax for editing text in a really unusual fashion. I saw the possibilites open up for navigating and manipulating text in powerful ways that had never even occurred to me before. I&#8217;ll spare you the details, but it was an eye-opening experience. My text editor could be a more powerful tool for accomplishing useful work than I had ever thought was possible.</p>
<p>I&#8217;m not here to preach Vim and get you to switch to it, or start yet another holy war with the Emacs crowd. It seems to me that Emacs is a perfectly valid alternative to Vim &#8211; I just don&#8217;t have the mental capacity to learn both editors at once.</p>
<p>But, I do recommend that you try out a powerful text editor &#8211; ANY powerful text editor! I think it&#8217;s an experience that every programmer should at least try. The best contenders right now in my mind are <a href="http://www.vim.org/">Vim</a>, <a href="http://www.gnu.org/software/emacs/">Emacs</a>, and <a href="http://macromates.com/">TextMate</a>.</p>
<p>There are a few reasons why I decided to commit to Vim as my editor of choice:</p>
<ul>
<li><strong>Vim is powerful.</strong> As I have increased my mastery over its complicated set of commands and modes, my efficiency in editing text has risen proportionally. This is great for me as a programmer &#8211; the less time it takes me to mechanically edit text, the more time I can spend thinking about and writing code.</li>
<li><strong>Vim is flexible.</strong> Once you speak it&#8217;s language, you can combine commands to create expressions that accomplish a very specific and complicated text editing tasks in a few keystrokes. Its interoperability with the shell is cool. For instance, it&#8217;s very easy to use Vim as a lightweight pseudo-IDE for any language that has a command-line compiler or interpreter. It has support for plugins and new syntax rules, which allows the community to contribute rules for all sorts of uncommon languages. If you know a language, there are probably Vim syntax highlighting rules for it!</li>
<li><strong>Vim is ubiquitous.</strong> It&#8217;s open source, and available on Mac, Linux, and Windows (and many other OSes including BSD!) In fact, any Unix system I&#8217;ve ever used, including Debian 0.91 from 2002 included some form of a Vi editor.</li>
<li><strong>Vim is lightweight.</strong> I think it typically weighs in at around 20 MB. Right now, MacVim is consuming 16.9 MB of memory on my computer and averages about 0-5% of my CPU. This is in contrast to a full-blown IDE like NetBeans, which is 154.8 MB in size, and can take up between 5-30% of my CPU when running and a whopping 329 MB of memory! NetBeans sometimes produces noticeable hangs on my machine.</li>
<li><strong>Vim is deep.</strong> I&#8217;ve never encountered another program with the same amount of commands, modes, etc. This put me off at first, but I&#8217;ve learned over time that each feature is present for a reason, and in mastering a new feature, I unlock new levels of efficiency in using the tool. It&#8217;s a slow burn &#8211; I&#8217;d expect that Vim has at least a 10-year, perhaps even a lifetime learning curve. (You can learn the basics of vanilla text editing in a few minutes &#8211; I&#8217;m talking about the learning curve to fully utilize the tool&#8217;s powerful features.) I can&#8217;t spend all my time learning Vim, I need to also focus on learning programming languages, new technologies, etc.</li>
</ul>
<p>I have been using Vim as my primary editor for something like 6 years now, and I am still learning new features every day. I find the time I&#8217;ve put in to learning the editor is really starting to pay off. Recently, a coworker who was watching me edit some HTML remarked, &#8220;<strong>Whoa, I thought people only went that fast in movies!</strong>&#8221;</p>
<p>Here&#8217;s what I find lacking in Vim:</p>
<ul>
<li>The learning curve is at times ridiculously steep which can be discouraging. It often takes me months to get enough use out of a feature to remember that it exists, how to use it, and finally how to use it effectively. I think, however, that this is part of the price of having a highly powerful and advanced tool for any sort of craft.</li>
<li>The documentation is dense and in many places seems to assume you are familiar with other aspects of Vim. Considering how massive the feature list of this editor is, that&#8217;s not always the case. Thankfully links are provided &#8211; but I don&#8217;t always feel like learning an entire new subsystem just to get one feature working! Google is my friend here as it&#8217;s often more clear to read somebody&#8217;s blog post than the actual Vim manual.</li>
<li>The scripting language seems clunky. I have no desire to learn yet another hacky Unix scripting language &#8211; bash is enough for me! That&#8217;s okay for now since the handful of Vim plugins I actually want have already been written by someone else.</li>
<li>Vim supports code completion, which is cool, but it&#8217;s a real pain in the ass to set up completion for your own code (i.e. getting a list of methods that I can call on an object of a certain class that I wrote, which is a nice feature that some IDEs provide.) I have yet to meet anyone in real life that has actually bothered to do this. It requires setting up a program called <a href="http://en.wikipedia.org/wiki/Ctags">ctags</a> (or <a href="http://ctags.sourceforge.net/">exuberant ctags</a>) and running that every time you want to update your completion rules, which analyzes your code and produces a &#8216;tags&#8217; file. Emacs has this exact same issue by the way, it also uses ctags! This is one area where bulky IDE&#8217;s actually provide enough of a service to warrant their rather poor behavior!</li>
</ul>
<p>With all of this in mind, I&#8217;d like to put forward my current list of qualities that an ideal code editor should have:</p>
<ol>
<li><strong>Powerful</strong> &#8211; A code editor should be able to manipulate text in powerful and context-sensitive ways.</li>
<li><strong>Assistive</strong> &#8211; A code editor should provide facilities for code completion and inline display of documentation relevant to the code being written.</li>
<li><strong>Multi-language</strong> &#8211; A code editor should not tie you to any particular programming language.</li>
<li><strong>Crossplatform</strong> &#8211; A code editor should not tie you to any particular operating system.</li>
<li><strong>Plugin architecture </strong>- A code editor should be easily extensible to work with new languages by its user base.</li>
<li><strong>Open source</strong> - A code editor should be easily extensible to work with new operating systems by its user base.</li>
</ol>
<p>How do some editors I know of rank against this rubric?*</p>
<table style="font-size: 11px;">
<tbody>
<tr>
<td></td>
<td>Powerful</td>
<td>Assistive</td>
<td>Multi-language</td>
<td>Crossplatform</td>
<td>Plugin architecture</td>
<td>Open source</td>
</tr>
<tr>
<td>Vim</td>
<td>Yes</td>
<td>Sort of</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Emacs</td>
<td>Yes</td>
<td>Sort of</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>NetBeans</td>
<td>Sort of</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Visual Studio</td>
<td>Sort of</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Xcode</td>
<td>Sort of</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>TextMate</td>
<td>Yes</td>
<td>Sort of</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>TextWrangler</td>
<td>Sort of</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Notepad++</td>
<td>Sort of</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>*This table is highly subjective. I tried to include some popular editors that I haven&#8217;t personally used much like TextMate and Emacs and assess them by reading about them and talking to people who use them. <a href="http://en.wikipedia.org/wiki/Comparison_of_text_editors">See Wikipedia for a more exhaustive comparison of text editor features</a>.</p>
<p>I was a bit hard on the IDE&#8217;s listed here. To be fair, most of them support a handful of different languages. However, I don&#8217;t think they meet the criteria of &#8220;should not tie you to any particular language&#8221; since a lot of their more useful features such as code completion would not be available in anything other than those languages even if you were to use them as a plain text editor.</p>
<p>There isn&#8217;t an editor that actually meets all 6 of my criteria. Vim and Emacs come the closest, but the fact that most human beings don&#8217;t actually have the patience to install and run ctags for code completion makes me rank them down in the &#8220;Assistive&#8221; category, whereas in the IDE&#8217;s this is automatic and built-in. I also ranked the IDE&#8217;s down for &#8220;Powerful&#8221; because the context-sensitive editing abilities in their default editors are tied to their particular languages, whereas these commands in Vim are generic and work in any language. Also, if you&#8217;ve used Vim, your definition of &#8216;powerful editing&#8217; changes and you realize that what are typically considered powerful editing features are weak sauce. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Emacs gets a pass since it has <a href="http://www.emacswiki.org/emacs/ProgrammingModes">a metric assload of modes</a> for a bunch of different languages.</p>
<p>Other editors such as TextMate seem appealing, but are not crossplatform or open-source. I am a generalist; I write games for Windows, backends for Linux, and utilities for Mac OS X, among other things. Mac is my primary platform at the moment, but I feel like it would be foolish for me to put all my eggs in one basket by tying myself to a text editor whose creators <a href="http://macromates.com/">openly proclaim it will never be ported to any other system</a>.</p>
<p>Another enticing option is the franken-editor&#8230; people have actually written plugins for various IDE&#8217;s that allow a simulated Vi editing mode (<a href="http://jvi.sourceforge.net/">jVi</a>, <a href="http://www.viemu.com/">ViEmu</a>) or in one case, <a href="http://eclim.org/">a real instance of Vim</a> to run inside of the IDE. This actually winds up providing a great mix of editing power and assistive support from the IDE. It&#8217;s a win for Vim ubiquity since I can re-use my exact same muscle memory for editing within multiple IDEs. However, this scenario is plagued by the same issues that make the IDE fall short of perfect, by tying you to specific languages supported by the base IDE.</p>
<p>To wrap up, I don&#8217;t think the ideal code editor exists. If you have the good fortune to be coding in a language supported by a decent IDE, that could be the ideal editor for that language, but not others, and you&#8217;ll pay a friction penalty switching between the IDE editor and whatever other editor you use, unless you&#8217;re doubly fortunate and there&#8217;s some sort of plugin to make the IDE work like your other editor or vice versa.</p>
<p>Vim and Emacs are pretty dang good, but fall short of perfect in my eyes since it&#8217;s such a pain in the ass to set up ctags. If either the Vim or Emacs community was able and willing to bundle this functionality up in a more automatic and integrated way (i.e. not making me compile the damn thing for OSX or force me to ask my sysadmin to install the exuberant ctags RPM in a shared environment,) they just might fit my criteria for perfect code editor. At least until I actually used them and thought up more features I&#8217;d want. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/diGDXFmvBfU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/08/searching-for-the-perfect-editor/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/08/searching-for-the-perfect-editor/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=searching-for-the-perfect-editor</feedburner:origLink></item>
		<item>
		<title>Tool tips: Find</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/zIttF8jlJ1g/</link>
		<comments>http://www.eliotlash.com/2011/08/tool-tips-find/#comments</comments>
		<pubDate>Tue, 16 Aug 2011 18:29:21 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[tool tips]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=320</guid>
		<description><![CDATA[The find utility is so useful for automation that it deserves a special mention on its own. I will not attempt to cover all of its features, only the ones that I use on a daily basis. I typically use find for two purposes: To create a list of files matching some search terms. To [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="margin: 0px;" title="Find is like a robot that you can program to find stuff and then do something to it :)" src="http://eliot.s3.amazonaws.com/eliotlash.com/robot_search_facingleft.png" alt="A robot searching" width="164" height="166" />The <strong>find</strong> utility is so useful for automation that it deserves a special mention on its own. I will not attempt to cover all of its features, only the ones that I use on a daily basis.</p>
<p>I typically use <strong>find</strong> for two purposes:</p>
<ol>
<li>To create a list of files matching some search terms.</li>
<li>To execute a batch operation on those files using the -exec argument.</li>
</ol>
<p>In <a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/">Shell Scripting: Becoming a Wizard</a>, I layed out a recipe for productive and useful bash scripts that uses a while loop over some sort of multi-line input. This construct is more powerful than <strong>find</strong>&#8216;s built in <strong>-exec</strong> flag, but that power is not always needed.</p>
<p>Here is how I use <strong>find</strong>:</p>
<p><span id="more-320"></span><span style="font-size: 20px; font-weight: bold;">Stage 1: Build up a list of files to operate on.</span></p>
<p>By default, <strong>find</strong> just prints the list of matching files, which is really useful because you can check the list of files you&#8217;ll be working with before you move on to actually doing something to them. It also makes <strong>find</strong> useful as a general purpose file searching tool that&#8217;s available on most Unix systems. Note that find does not inspect the <em>contents</em> of a file directly, only its external attributes. If you want to search through file contents from the command line, check out grep/fgrep or <a href="http://betterthangrep.com/">ack</a>. (fgrep -r searchterm file1 [file2 ...])</p>
<p>The general form for <strong>find</strong> looks something like this:</p>
<p><code>find directory argument1 [argument2 ...]</code></p>
<p>Typically, I want to run a recursive search from my current directory (which is &#8216;.&#8217; in bash convention.) I&#8217;ll include a bash prompt signified by the $ character, and example output from the <strong>find</strong> command to better illustrate what&#8217;s going on:</p>
<p><code>$ find .<br />
.<br />
./bar.jpg<br />
./baz.png<br />
./foo<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>This command (<strong>find .</strong>) is the simplest working invocation of <strong>find</strong>, and produces a full listing of every file and directory inside your current directory (including the current directory itself.) I rarely ever want this though, so I will begin by limiting my search. A common way I do this is by searching for filename matches. For instance:</p>
<p><code>$ find . -name '*.jpg'<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>Uses wildcard/glob syntax to search for only for files with names ending in .jpg. If we wanted to also include files ending in .JPG or any other case combinations, we could use the -iname (case insensitive name) expression instead.</p>
<p><code>$ find . -iname '*.jpg'<br />
./bar.JPG<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>This is working well so far. Supposing we wanted to limit our recursive search to directories of only a certain depth, we can do that using the <strong>-maxdepth</strong> flag. To search only the immediate children of the current directory, we use <strong>-maxdepth 1</strong>. To search only immediate children, and the children of immediate subdirectories, use <strong>-maxdepth 2</strong>, and so on:</p>
<p><code>$ find . -iname '*.jpg' -maxdepth 1<br />
./bar.JPG<br />
./foo.jpg<br />
</code></p>
<p>Let&#8217;s say for the sake of example that we wanted to search based off of partial filename instead, for files called &#8216;foo&#8217;:</p>
<p><code>$ find . -name '*foo*'<br />
./foo<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>Whoops! We don&#8217;t want any directories in this case, so let&#8217;s narrow our search criteria to files only and not directories:</p>
<p><code>$ find . -name '*foo*' -type f<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>Perfect! <strong>-type f</strong> selects files and <strong>-type d</strong> selects directories, respectively. In this example we could also use glob searching on the name for files such as <strong>-name &#8216;*foo*.jpg&#8217;</strong>. However, <strong>-type</strong> is still useful since Unix systems allow file &#8216;extensions&#8217; on directory names and allow files without extensions.</p>
<p>How about if we only want to find files in a certain subfolder? We can use <strong>-path</strong> :</p>
<p><code>$ find . -path '*foo/*.jpg'<br />
./foo/foo2.jpg<br />
</code></p>
<p>A trivial example, but this is really useful for searching large source code trees for a particular file, etc. For instance, if I know there&#8217;s a class that has Twitter in its filename and resides in some subfolder of Services, a search for <strong>-path &#8216;*Services*Twitter*&#8217;</strong> should turn it up. A case insensitive version of this flag is <strong>-iwholename</strong>.</p>
<p>What if we want to use some logic in our search? <strong>find</strong> supports that. For instance, we can search for all jpg files that do NOT contain &#8216;foo&#8217; in their name using the <strong>!</strong> operator:</p>
<p><code>$ find . -iname '*.jpg' ! -name '*foo*'<br />
./bar.JPG<br />
</code></p>
<p>How about if we want to find all jpg and png files? Use -o for logical or. It will be true if either the previous flag or the next flag is true (but not if both are):</p>
<p><code>find . -iname '*.jpg' -o -iname '*.png'<br />
./bar.JPG<br />
./baz.png<br />
./foo/foo2.jpg<br />
./foo.jpg</code></p>
<p>Tons of other functionality exists in <strong>find</strong>, although the above are all the commands I use on a daily basis. <strong>find</strong> can filter on modification/creation time, ownership, more unusual file types like FIFOs, and use other types of logic such as AND. Run <strong>man find</strong> for the full list.</p>
<p><span style="font-size: 20px; font-weight: bold;">Stage 2: Execute a command across all selected files.</span></p>
<p>Now that we have a list of files we want to use, we can take advantage of <strong>find</strong>&#8216;s most useful and powerful flag, <strong>-exec</strong>. The syntax for <strong>-exec</strong> seems cryptic at first, but comes to make sense with repeated use.</p>
<p>There are two forms I typically use when calling -exec:</p>
<p><code>-exec somecommand {} \;</code></p>
<p>and</p>
<p><code>-exec somecommand {} +</code></p>
<p>The former will execute some command once for each file in our search results. The latter will execute one command once (or as seldom as possible) and pass the files in as multiple arguments. For example:</p>
<p><code>$ find . -iname '*.jpg' -maxdepth 1 -exec echo file {} \;<br />
file ./bar.JPG<br />
file ./foo.jpg</code></p>
<p>The command <strong>echo file {} </strong>is being run for each result, with the path to the result being substituted where the <strong>{}</strong> is. <strong>\;</strong> is just a terminator character to let <strong>find</strong> know that that&#8217;s the end of the command we want to run. If we get rid of the echo (a debugging trick I use to preview a list of batch commands) the <a href="http://www.eliotlash.com/2011/02/tool-tips-file/"><strong>file</strong> command</a> will actually be run against all these files, printing out their true type for us:</p>
<p><code>$ find . -iname '*.jpg' -maxdepth 1 -exec file {} \;<br />
./bar.JPG: PNG image, 64 x 32, 8-bit/color RGBA, non-interlaced<br />
./foo.jpg: JPEG image data, EXIF standard</code></p>
<p>Good thing I checked &#8211; looks like bar.JPG is really a PNG with an incorrect extension!</p>
<p>The file utility is even kind enough to print out the file name of the file it&#8217;s talking about. It&#8217;s also spiffy enough to accept a space delimited list of files to parse (as do many command line utilities) so we can improve the performance of this batch operation by reducing the invocations of <strong>file</strong>:</p>
<p><code>$ find . -iname '*.jpg' -maxdepth 1 -exec echo file {} +<br />
file ./bar.JPG ./foo.jpg</code></p>
<p>Rather than file getting called twice (once for each result) it&#8217;s only called once, with each result being passed as an argument. In this trivial example this behaves the same. But if you need to run a batch operation over many files, it can make a difference in speed.</p>
<p>Also, if your batch operation involves something like gluing a bunch of files together (like with <strong>cat</strong> to concatenate files) or opening them all at once in one editor, the <strong>+</strong> style invocation is necessary. It basically serves the same function as <strong>xargs</strong>, so there&#8217;s no reason to pipe the output of <strong>find</strong> to <strong>xargs</strong>. Using <strong>-exec {} +</strong> is safer and faster. <strong>xargs</strong> is still useful when taking input from another source such as a text file, but be aware of paths with spaces in them, they need to be escaped properly.</p>
<p><span style="font-size: 20px; font-weight: bold;">Limitations</span></p>
<p><strong>find</strong>&#8216;s <strong>-exec</strong> flag is only designed to run one command at a time, and doesn&#8217;t support fancy bash tricks such as output substitution and piping. If you need those, use the bash while loop outlined in <a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/">Shell Scripting: Becoming a Wizard</a>. You can still use <strong>find</strong> to create the list of files you want to operate on, just pipe the output of find into the bash while loop.</p>
<p>Note that the <strong>-exec {} +</strong> style invocation may not be present in older versions of <strong>find</strong>. If that&#8217;s the case and you have no choice but to use <strong>xargs</strong>, avoid nasty escaping issues by telling both tools to use the null character as a filename delimiter instead of newlines using <strong>find -print0</strong> and <strong>xargs -0</strong>, like so:</p>
<p><code>find directory -print0 [argument2 ...] | xargs -0 somecommand</code></p>
<p><code></code><span style="font-size: 20px; font-weight: bold;">Conclusion</span></p>
<p>I hope you learned a thing or two about <strong>find</strong> today. Remember, practice! I always had to look up the <strong>-exec</strong> syntax the first several times I used it, or if I haven&#8217;t used it in a while (which is no longer likely since I now use it almost every day!)</p>
<p>After reading this article and experimenting a bit, you should now be able to <a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/#find_examples">understand the <strong>find</strong> examples for doing useful work</a> I mentioned in <a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/">my article on The Shell and Coreutils</a>. I hope this is enough to spark your imagination for the massively powerful automation techniques available by coupling <strong>find</strong> with other command line utilities.</p>
<p><span style="font-size: 20px; font-weight: bold;">Other resources</span></p>
<p>Here are some great resources to learn more:</p>
<ul>
<li><strong>man find</strong> &#8211; The find manpage on your system has a definitive list of valid expressions and operators.</li>
<li><a href="http://mywiki.wooledge.org/UsingFind">Greg&#8217;s Wiki &#8211; UsingFind</a> &#8211; This is where I learned most of what I know about find along with the man page.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/zIttF8jlJ1g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/08/tool-tips-find/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/08/tool-tips-find/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=tool-tips-find</feedburner:origLink></item>
		<item>
		<title>Tales From The Back Burner: Zero Gravity Movement Game Prototype</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/IgRZs_Jwgms/</link>
		<comments>http://www.eliotlash.com/2011/07/the-back-burner-zero-gravity-movement-game-prototype/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 09:13:58 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Game Design]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[back burner]]></category>
		<category><![CDATA[game design]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[udk]]></category>
		<category><![CDATA[zero gravity]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=287</guid>
		<description><![CDATA[I&#8217;d like to show off some projects of mine that are currently on the back burner, to avoid them from gathering too much dust. Here is a video of a game prototype I was working on in UDK. My idea is to express the feeling of being in zero gravity in a way that hasn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;d like to show off some projects of mine that are currently on the back burner, to avoid them from gathering too much dust. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><object width="500" height="400"><param name="movie" value="http://www.youtube.com/v/D-UT8Vfok1E?version=3"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/D-UT8Vfok1E?version=3" type="application/x-shockwave-flash" width="500" height="400" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Here is a video of a game prototype I was working on in UDK. My idea is to express the feeling of being in zero gravity in a way that hasn&#8217;t been done in games before (i.e. no jetpack.) You move by pushing yourself along surfaces and kicking off them towards other surfaces. Once airborne, you can&#8217;t alter your velocity without grabbing on or bumping in to something (or possibly throwing stuff out of your pockets.) I hope someday to make a real game from this concept.</p>
<p>I reflect on this prototype, why it went to the back burner, and what I learned after the jump.</p>
<p><span id="more-287"></span></p>
<p>Why it&#8217;s back-burnered: I got bogged down in a lot of difficult 3D math. Also, I&#8217;m finding it a pain to just figure out how to do what I want in UnrealScript due to lack of documentation. The last time I worked on this, I had just finished implementing a custom six degrees of freedom (6dof) camera that uses quaternions to represent rotation instead of the default euler angles. After jamming on this for several weekends, I sort of lost steam on the project.</p>
<p>I have inklings of a vision for a larger exploration/puzzle game in zero gravity, but I&#8217;m not quite sure how I want to proceed. Also, I think this idea of mine might be too ambitious in scope.</p>
<p>Actually building this prototype helped me immensely to understand the issues that would arise in designing this sort of game. I hit an issue with 6dof cameras that I have not seen solved yet by anyone who has attempted this. Notice that if you rotate the camera in small circles in any game with a 6dof camera (say, in <a href="http://www.gog.com/en/gamecard/descent_1_descent_2">Descent</a>, or<a href="http://store.steampowered.com/app/18110/"> Shattered Horizon</a> when you&#8217;re not walking on a surface) you&#8217;ll see it start to roll. The larger the circle, the more exaggerated the motion is. This means that if, for instance, you yaw left by 90 degrees (i.e. look along your left shoulder), then pitch up by 90 degrees (look straight up from there) and then yaw right by 90 degrees (move your head to the right) you will be looking forward again, but the world will have rolled by 90 degrees! This feels really unnatural in a 1st-person game where the mouse is supposed to control head movement. (Below is a diagram of roll, pitch, and yaw axes if you are unfamiliar with the terms.)</p>
<p style="text-align: center;"><a href="http://en.wikipedia.org/wiki/Flight_dynamics#Aircraft"><img class="aligncenter" title="Diagram of roll, pitch, and yaw" src="http://eliot.s3.amazonaws.com/eliotlash.com/300px-Rollpitchyawplain.png" alt="" width="300" height="196" /></a></p>
<p>The only alternative I can think of, that I was working on coding before I back-burnered this project, is a system where you can control the position of your body seperately from your head. In that case, you would be able to orient your body with six degrees of freedom, and could in fact do the rotation described above, and it would be OK since you are in zero gravity and deliberately re-orienting yourself. But to keep it so that the situation described above doesn&#8217;t happen when you are just casually looking around, the roll on your head would be locked, so if you did the rotation described above, your view would not roll (this is how regular FPS cameras work.) If anyone is interested, I can make some videos that illustrate the issue I am describing here.</p>
<p>Music: TiLT &#8211; Nova Lab Background Theme<br />
<a title="http://www.medievalfuture.com" dir="ltr" rel="nofollow" href="http://www.medievalfuture.com/" target="_blank">http://www.medievalfuture.com</a></p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/IgRZs_Jwgms" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/07/the-back-burner-zero-gravity-movement-game-prototype/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/07/the-back-burner-zero-gravity-movement-game-prototype/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=the-back-burner-zero-gravity-movement-game-prototype</feedburner:origLink></item>
		<item>
		<title>Nidhogg: First impressions</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/rlgzt1SmQv4/</link>
		<comments>http://www.eliotlash.com/2011/03/nidhogg-first-impressions/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 23:46:01 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Game Reviews]]></category>
		<category><![CDATA[game design]]></category>
		<category><![CDATA[messhoff]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=251</guid>
		<description><![CDATA[I was fortunate to get several chances to play Nidhogg at GDC 11. I&#8217;d like to share my first impressions of the game. Nidhogg is a brilliant fighting game for two players created by Messhoff (Mark Essen.) I suck at most fighting games, although I have a lot of respect for the people that play [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" title="Nidhogg Tournament @ GDC" src="http://eliot.s3.amazonaws.com/eliotlash.com/nidhogg_t1_crop.jpg" alt="" width="261" height="431" />I was fortunate to get several chances to play <a href="http://messhof.com/nidhogg/">Nidhogg</a> at GDC 11. I&#8217;d like to share my first impressions of the game.</p>
<p>Nidhogg is a brilliant fighting game for two players created by <a href="http://messhof.com/">Messhoff</a> (Mark Essen.)</p>
<p>I suck at most fighting games, although I have a lot of respect for the people that play them. Watching my old roomate Kilo play Super Smash Bros. Melee and BlazBlue and talking with him about it helped me to understand the deep nature of these games. So did the excellent documentary <a href="http://www.igotnextmovie.com/">I Got Next</a>. Key to these games is the idea of a metagame, and playing mindgames with your opponent, occurring on different layers of anticipating your opponent, called yomi. <a href="http://www.sirlin.net/articles/yomi-layer-3-knowing-the-mind-of-the-opponent.html">Check out David Sirlin&#8217;s excellent article for an explanation of the layers of yomi in mindgames</a>. The basic idea is that you have a certain set of moves, some of which can be used to counter others. Some provide a greater reward (more damage, a stun, etc.) but at higher risk. Some are lower reward but also lower risk (low damage, shielding, etc.) Effectively mindgaming your opponent relies on knowing what your opponent thinks you will do, and playing off those expectations. A noob will try to use his most powerful move at all times if he knows how good it is, but this move is risky, so a pro will know that and counter it. But if a pro is playing another pro, he might also use the powerful move, precisely because the other player wouldn&#8217;t expect him to since it&#8217;s typically too risky.</p>
<p>Sirlin&#8217;s game <a href="http://www.kongregate.com/games/Kongregate/kongai">Kongai</a> did an excellent job of bringing these mindgames to a wider audience by removing the need for the millisecond reflexes that pro fighting game players must have, following in the vein of stuff like the battle game from Pokemon.</p>
<p>Nidhogg has accomplished something fantastic, in that it retains the real-time thrill of a classic fighting game, but provides a relatively small amount of actions that the player can take, which makes the game easier to pick up and play for the average gamer without having to learn a bunch of different combos for each character. However, the design is elegant, as these moves are more than enough to create interesting mindgames.</p>
<p>More about my thoughts on Nidhogg after the jump.</p>
<p><span id="more-251"></span></p>
<p>The objective of the game is to get past your opponent. You need to go several screens in one direction, and your opponent needs to go several screens in the other direction to win. When you kill your opponent or pass them onto the next screen, they respawn pretty quickly, a bit of a ways in front of you. The only difference between the two players is that one is orange and one is yellow&#8211;their abilities are identical.</p>
<p><iframe frameborder="0" src="http://www.youtube.com/embed/VxPvFFagQD0" height="390" width="480" title="YouTube video player"></iframe></p>
<p>You can run, jump, duck. If you duck while running, you do sort of a duck-slide. When you are walking with a sword and near your opponent, you automatically take a fencing stance. You can position the height of your sword, move backwards and forwards, and do a short jab with your sword at whatever height it&#8217;s at. If you are running and try to jab your sword, you will throw it. A thrown sword can be deflected if you are holding a sword out and facing it. If you don&#8217;t have a sword, you can do hand-to-hand kicks and punches, although these are closer range and do a lot less damage, whereas a sword kills in one hit.</p>
<p>That&#8217;s pretty much it for controls, as far as I can remember. Just a directional control and two buttons. I was able to play the game equally well on an Xbox 360 controller and an NES gamepad.</p>
<p>The most interesting part of the game, of course, is the mindgames that arise. Throwing your sword is a risky, but awesome move. If it hits, you kill your opponent, have a few seconds to run and pick up your sword again, and advance in the game. If your opponent dodges or deflects the thrown sword, you just made a huge mistake. An opponent with a sword can easily overpower one without a sword, so if you are standing in the way of the other player you&#8217;ll likely need to try dodging them when they come in to stab you or throw their sword at your squishy unprotected body, or try to find another sword lying around to defend yourself with.</p>
<p>A great move in the game is the duck-slide (that&#8217;s what I&#8217;m calling it, anyway.) If an opponent holds his sword at waist height, you can slide right under it and get past him quickly. But if he holds his sword low to the ground, you get skewered. Also, I think if he holds his sword to the ground, he leaves himself open for an attack by a thrown sword. So when one armed opponent is running at another, it&#8217;s always thrilling to see the outcome. You can also approach each other slowly like fencers, trying to jab/block your opponent.</p>
<p>The game lends itself to many tense, unexpected, and hilarious situations. Playing it at a packed GDC party really added to the excitement and atmosphere. It was awesome to see a player execute a duck-slide under his opponent&#8217;s sword and run all the way to the end of the hall, only to be cut down at the very last second by a sword thrown hail mary style from halfway across the room, to the cheers and laughs of the crowd. Or two guys brawling it out over a sheer drop, one guy kicking the other guy off the ledge, and trying to jump over but missing it and tumbling down himself. The fast pace of the game and constant respawning means the tide can be turned at any moment. From moment to moment, both players can experience swings between what you might call epic win and epic fail.</p>
<p>I don&#8217;t know how Nidhogg will be received by the fighting game community, or if most people there will even hear about it. Perhaps the mindgames won&#8217;t be deep enough. Without being a fighting game player myself and only having played a handful of rounds, I don&#8217;t know the answer. But the potential is there, and it&#8217;s palpable. Undeniably, Nidhogg is a wonderfully entertaining party game &#8211; watching two people who have never played before duke it out is just as entertaining as watching players who seem to have a better idea of what they&#8217;re doing.</p>
<p>It looks as if Nidhogg might have a single-player mode as well, but I didn&#8217;t get a chance to see it.</p>
<p>I got a chance to chat with Messhoff briefly about the game. I asked the perennial question, when is Nidhogg coming out? He said he had been hoping to release it at GDC, but that it just isn&#8217;t ready yet. But hopefully, it will be released &#8220;soon.&#8221; It goes without saying, but I&#8217;m brimming with anticipation. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/rlgzt1SmQv4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/03/nidhogg-first-impressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/03/nidhogg-first-impressions/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=nidhogg-first-impressions</feedburner:origLink></item>
		<item>
		<title>Tool tips: Tee (and standard streams)</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/hvl4CzqCZQE/</link>
		<comments>http://www.eliotlash.com/2011/02/tool-tips-tee-and-standard-streams/#comments</comments>
		<pubDate>Sun, 27 Feb 2011 23:07:05 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[tool tips]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=238</guid>
		<description><![CDATA[Tee is a wonderful but often-overlooked core utility. It&#8217;s purpose is to intercept a pipeline, write the output to a file, and pass the output along the pipe. It can be used to easily add output logging to any command pipeline or script. To get the most out of tee, it pays to read up [...]]]></description>
			<content:encoded><![CDATA[<p><strong><img class="alignright" title="PVC Tee" src="http://eliot.s3.amazonaws.com/eliotlash.com/tee.jpg" alt="A physical tee for pipes made from PVC" width="275" height="229" /></strong></p>
<p><strong>Tee</strong> is a wonderful but often-overlooked core utility. It&#8217;s purpose is to intercept a pipeline, write the output to a file, and pass the output along the pipe. It can be used to easily add output logging to any command pipeline or script.</p>
<p>To get the most out of <strong>tee</strong>, it pays to read up on how input, output, and errors are handled by the shell. (As a byproduct, a good understanding of bash I/O redirection will make you a more efficient bash user and scripter!)</p>
<p>There are three <a href="http://en.wikipedia.org/wiki/Standard_streams">standard streams</a> that can be used by any unix program: stdin, stdout, and stderr. Each of these can be thought of as a file. By default, all unix programs read from stdin, write normal output to stdout, and write error messages to stderr.  The shell&#8217;s job is to take things being read or written to one of the standard streams and redirect them through pipes that you specify. By default, the shell will take the characters you type into the terminal while a program is running and pass them to that program&#8217;s stdin. It will take the characters written by the program to stderr and stdout and print them to your terminal.</p>
<p>If you instead insert a pipe, like so:</p>
<p><code>command1 | command2</code></p>
<p>the shell will redirect the characters written to command1&#8242;s stdout to command2&#8242;s stdin via a pipe. Command1&#8242;s stderr will still get written to your terminal.</p>
<p>Bash has syntax for specifying custom redirections. For instance, you can redirect stdout to a file instead of your terminal:</p>
<p><code>command1 &gt; file</code></p>
<p>This is where <strong>tee</strong> comes in. If we want to both log something to a file and pass it along a pipe, or just have it written to the terminal (by leaving tee as the last command in the pipe,) we can insert tee into our pipe:</p>
<p><code>command1 | tee file | command2</code></p>
<p>If you want to do something other than use tee to log just stdout, you should read more about bash I/O redirection. Here are some resources:</p>
<ul>
<li><a href="http://tldp.org/LDP/abs/html/ioredirintro.html">Advanced Bash-Scripting Guide: A Detailed Introduction to I/O and I/O Redirection</a></li>
<li><a href="http://tldp.org/LDP/abs/html/io-redirection.html">Advanced Bash-scripting guide: I/O Redirection</a></li>
<li><a href="http://mywiki.wooledge.org/BashFAQ/047">Greg&#8217;s Wiki: How can I redirect stderr to a pipe?</a></li>
<li><a href="http://mywiki.wooledge.org/BashFAQ/014">Greg&#8217;s Wiki: How can I redirect the output of multiple commands at once?</a></li>
</ul>
<p>Typical invocation:</p>
<p><code>some command that produces output | tee file</code></p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/hvl4CzqCZQE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/02/tool-tips-tee-and-standard-streams/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/02/tool-tips-tee-and-standard-streams/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=tool-tips-tee-and-standard-streams</feedburner:origLink></item>
		<item>
		<title>Tool tips: File</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/BBMobmjg1g8/</link>
		<comments>http://www.eliotlash.com/2011/02/tool-tips-file/#comments</comments>
		<pubDate>Sun, 27 Feb 2011 00:37:47 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[tool tips]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=233</guid>
		<description><![CDATA[Today, I would like to highlight the usefulness of the file utility. It is a command-line utility that is common on Unix systems. File will take one or more files and try to determine what type of file they are by examining their contents. It&#8217;s the most accurate general-purpose tool of its type that I [...]]]></description>
			<content:encoded><![CDATA[<p>Today, I would like to highlight the usefulness of the <strong>file</strong> utility. It is a command-line utility that is common on Unix systems. <strong>File</strong> will take one or more files and try to determine what type of file they are by examining their contents. It&#8217;s the most accurate general-purpose tool of its type that I have used. It can be very helpful in identifying file types when there is no extension in the file name. Since it works off of the file contents rather than just the extension, file can tell you, for instance, that the a file called &#8220;picture.jpg&#8221; is actually a PNG with an incorrect file extension.</p>
<p>Invocation:</p>
<p><span style="font-family: monospace;">file file1 [file2 file3 ...]</span></p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/BBMobmjg1g8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/02/tool-tips-file/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/02/tool-tips-file/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=tool-tips-file</feedburner:origLink></item>
		<item>
		<title>Better living through automation, pt. 3: Shell Scripting: Becoming a Wizard</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/CTkubAwUhOQ/</link>
		<comments>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 05:28:24 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=103</guid>
		<description><![CDATA[Using just the shell and the coreutils, it is possible to write commands which wrangle massive amounts of files, translate data into the format you want, etc. But what if you want to take things to the next level? This is where scripting comes in. You can write scripts which are capable of performing a [...]]]></description>
			<content:encoded><![CDATA[<p>Using just the shell and the coreutils, it is possible to write commands which wrangle massive amounts of files, translate data into the format you want, etc. But what if you want to take things to the next level?</p>
<p>This is where scripting comes in. You can write scripts which are capable of performing a lengthy and detailed series of operations in order. Your computer can do these tasks over and over and over, very quickly. Unlike you, your computer doesn&#8217;t need to sleep or eat. It will perform just as well at 3am as it will at noon. All you need to do to take advantage of this amazing machine is to learn a language that it understands so you can instruct it on what you want it to do.</p>
<p>The awesome thing is, if you&#8217;ve been using your shell, <em>you already know a scripting language</em>. Every command you type at the command line can be thought of as a shell script.</p>
<p>I provide an overview of my favorite bash scripting facilities after the jump.</p>
<p><span id="more-103"></span></p>
<p>I will use bash as my example here since I am most familiar with it, and it&#8217;s likely to be the shell you are using as well. Instead of typing commands into the terminal, we will save them to a file. I recommend a text editor such as the free <a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a>. You can use TextEdit in plain text mode, but beware that it can sometimes behave poorly and cause unforeseen consequences due to how it handles formatting of line endings. Mac OS X (and almost every other Unix system) ships with a variant of an editor called <strong>vi</strong> which runs in the terminal and is incredibly powerful. <strong>vim </strong>is a <strong>vi</strong> variant and my editor of choice. However, the learning curve for <strong>vi</strong> is really steep, so I wouldn&#8217;t recommend it for beginners, unless you need to do a lot of work on a remote Unix webserver, are an efficiency freak, or simply want nerd street cred like me. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So, open up a file in your text editor. Type in some commands. Each line of the file represents one command, or command pipeline. So we might type:</p>
<pre class="brush: bash; title: ;">
echo &quot;Hello world! Here are your files:&quot;
ls
</pre>
<p>If we save this file to our home directory as &#8220;myscript.sh&#8221; and then open Terminal and type the following:</p>
<pre>bash ~/myscript.sh</pre>
<p>We should see the script run! It should print &#8220;Hello world! Here are your files:&#8221;, and then a list of files in the current directory.</p>
<p>This is nice. Just using this method, we can consolidate several separate commands into a single script which will run them all in sequence.</p>
<p>However, bash provides us with many language features that allow us to give our computer much more flexible instructions. We can tell it to repeat a segment of instructions an arbitrary number of times (a &#8216;for loop&#8217; or &#8216;while loop.&#8217;) We can give it logic to determine what to do in a number of different situations (by using &#8216;if statements.&#8217;) We can even have our scripts take flags and arguments from the shell itself, like any other command line utility! In effect, we can complement the coreutils by writing our own utilities in bash. Ultimately, this allows us to make our computer &#8216;smart&#8217; enough to accomplish large and tedious tasks that would otherwise require an intelligent person like you!</p>
<p>Now, I am going to give you some <span style="color: #993300;">magic sauce</span>. Remember this later, once you have become more familiar with bash scripting. This little template for a bash script has proven more useful to me recently than anything else. It&#8217;s in pseudo-code so you&#8217;ll need to swap out a few things to make it work.</p>
<pre class="brush: bash; gutter: false; title: ;">
something that produces output | while read index
do
  some command on $index
done
</pre>
<p>This can also be written on one line. It&#8217;s less readable, but can be useful since you can test it out directly in the shell without having to save it to a file:</p>
<pre class="brush: bash; gutter: false; title: ;"> something that produces output | while read index; do some command on $index; done </pre>
<p>This is the key to <span style="color: #993300;"><a href="http://www.realultimatepower.net/">real ultimate power</a></span>. Why? Two reasons:</p>
<ol>
<li>The input can come from ANY command or pipeline of commands. It can come from a file. It doesn&#8217;t matter. Our script will go over the input line by line and do something related to it.</li>
<li>The current line of input we&#8217;re on is stored as a variable, here I&#8217;ve called it index. A variable is just a container for some value, in this case, the contents of the current input line. This allows us to run the same block of code on many different lines of input, munge them around in some way, and execute the result as a command!</li>
</ol>
<p>Here is a specific example of a script written using the above template.</p>
<pre class="brush: bash; gutter: false; title: ;">
find . -name '*.jpg' | while read index
do
	echo mv $index ~/photos/PHOTO_`basename $index`
done
</pre>
<p>What this script will do is create a list of commands to move all the files ending in .jpg in the current directory or any subdirectories to the folder ~/photos, and prefix PHOTO_ to the file name. It&#8217;s &#8220;nerfed&#8221; in the sense that it won&#8217;t actually execute this set of commands, I did this just in case you wanted to copy this onto your machine so it wouldn&#8217;t mess up your files. <img src='http://www.eliotlash.com/mainsite/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>It&#8217;s easy to &#8220;un-nerf&#8221; this script &#8211; either delete the &#8220;echo&#8221; &#8211; so that the command being run is <strong>mv</strong>, not <strong>echo</strong> (which was just printing the <strong>mv</strong> command.) You could also pipe the output of this script into a new shell, like so. The second instance of &#8220;bash&#8221; will read the input line by line and execute it.</p>
<pre>bash script.sh | bash</pre>
<p>This script also takes advantage of another powerful bash feature called command substitution. You will notice a command enclosed in `bacticks` (that&#8217;s what happens when you press the tilde/~ key without pressing shift.) This tells bash to take the output of whatever is inside the backticks, and use that in the final command. So in our example, we&#8217;re calling the basename utility, which in our example gives us the base name of the file path stored in $index (just the file name without any path information.) Since it&#8217;s enclosed in backticks, the output of the command will get added to the echo mv command. So in effect, each time the while loop runs, it  will execute a command that&#8217;s  something like &#8220;echo mv /path/to/file.jpg ~/photos/PHOTO_file.jpg&#8221;.</p>
<p>Perhaps not a super exciting example, but it demonstrates the additional flexibility we have with this method over just using utilities such as <strong>find</strong> and <strong>xargs</strong>. With those tools, it gets rather convoluted if you want to do something like move and rename a file based on a pattern. The beauty of this method is that since we, the scripter, control the logic entirely, we can make <span style="color: #993300;">anything</span> happen inside this loop. We can iterate over a list of file name fragments, with each line becoming the next index variable, and then call <strong>find</strong> from within the loop to try and locate files which match the fragment, and do something to them.</p>
<p>A corollary to the above is the bash for loop, which can loop over the contents of a directory.</p>
<p>Here are some examples of scripts that I have written entirely in bash:</p>
<ul>
<li>Do a mass search-and-replace in ALL the files in a directory</li>
<li>Zip up a series of directories one-by-one, and submit the zips to a web application along with a bunch of data gleaned from reading the files in the folder</li>
<li>Search through my server logs, count accesses to a certain resource, and give me a daily count</li>
<li>Read in a list of folder name fragments, and do an svn-move of matching folders to a different location in the svn repository.</li>
<li>Use <strong>sed</strong> to batch-replace a value in a file with something else, and bash file I/O and the <strong>mv</strong> command to replace the original files</li>
</ul>
<p>Here are some resources for learning more about bash scripting:</p>
<ul>
<li><a href="http://linuxcommand.org/writing_shell_scripts.php">Linuxcommand.org &#8211; Writing Shell Scripts</a></li>
<li><a href="http://www.tldp.org/LDP/abs/html/">Advanced Bash Scripting Guide</a></li>
<li><a href="http://www.davidpashley.com/articles/writing-robust-shell-scripts.html">Writing Robust Shell Scripts</a> &#8211; A must-read once you&#8217;ve finished making toy scripts and want to move on to things more powerful, and therefore dangerous.</li>
<li><strong>man </strong>- Many of bash&#8217;s functions and syntax are documented in man pages. Check &#8221;man bash&#8221; and &#8220;man test&#8221; for starters.</li>
<li><a href="http://www.google.com/">Google</a> &#8211; As always, if you&#8217;re stuck, google it!</li>
</ul>
<p><span style="color: #993300;"><strong>A word of warning</strong></span>: I find bash an excellent scripting language for tasks of low to moderate complexity.  However, the syntax is a bit rigid and opaque compared to recent higher-level languages suitable for scripting, such as PHP and Ruby. After taking an upload script I had written in bash and adding all sorts of features such as command-line flags, error and output logging, etc, I soon regretted it as the 100+ line script became unwieldy. I rewrote the script completely in PHP to make it cleaner. I plan on writing a brief introduction to scripting in high-level languages soon.</p>
<p>It&#8217;s certainly possible to write clean and modular bash programs for larger applications, but I find the syntax of other languages more comfortable when I need complex control logic, data parsing, etc.</p>
<p>However, the ease of converting a shell command into a simple bash script, and the brevity of its syntax still makes bash my language of choice for relatively simple scripts.</p>
<p>Up Next:</p>
<ul>
<li>Curl: Internet Magic Sauce</li>
<li>Scripting in high-level languages</li>
</ul>
<p>Previously in this series:</p>
<ul>
<li><a href="http://www.eliotlash.com/2011/02/better-living-thru-automation/">Better living through automation, pt. 1 (Automator)</a></li>
<li><a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/">The Shell and Coreutils</a></li>
</ul>
<p><strong> </strong></p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/CTkubAwUhOQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard</feedburner:origLink></item>
		<item>
		<title>Better living through automation, pt. 2: The Shell and Coreutils</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/CjEUOdSHuLM/</link>
		<comments>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 22:00:48 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=100</guid>
		<description><![CDATA[From here on out, I&#8217;m going to assume that you have access to a Unix environment. If you use Windows, I suggest that you install Cygwin to get a Unix environment on your machine if you want to follow along. The default Windows terminal is also pretty crappy so I recommend installing the rxvt-native terminal from within [...]]]></description>
			<content:encoded><![CDATA[<p><em>From here on out, I&#8217;m going to assume that you have access to a Unix environment. If you use Windows, I suggest that you install <a href="http://www.cygwin.com/">Cygwin</a> to get a Unix environment on your machine if you want to follow along. The default Windows terminal is also pretty crappy so I recommend installing the rxvt-native terminal from within Cygwin.</em></p>
<p>Every operating system in the Unix family (including Mac OS X) ships with a set of core utilities, or coreutils. These are small, fast programs which are invoked via the command line. The coreutils are truly the holy grail of automation.</p>
<p>By design, each utility is very, very good at one specific thing. For instance, <strong>cut</strong> will print out one or several slices of the text you pass into it, as determined by a &#8220;delimiter character&#8221; that you specify. <strong>paste</strong>, on the other hand, will join two files together line-by-line. Together, these programs can be used, for example, to combine reports from multiple files and format the output how you want.</p>
<p>This design is known as the Unix &#8220;toolbox&#8221; philosophy. The analogy is that a swiss army knife is supposed to be good at everything. But you can&#8217;t build a house with a swiss army knife. Professional contractors have a toolbox full of highly specialized tools that can only do one thing, but are extremely good at that one thing. The same goes for each of the core utilities. Some software tries to be a swiss army knife and often winds up as the &#8220;jack of all trades, master of none.&#8221; The core utilities are like the contractor&#8217;s toolbox. By using several specialized tools in combination, you can achieve quick and powerful results.</p>
<p>The glue for the coreutils that allows you to use them together is called the shell. The shell is what you are interacting with when you start your &#8220;terminal&#8221; program, such as the one provided by Mac OS X located under /Applications/Utilities/Terminal.app. Bash is the most popular shell today, and is the default shell on most modern systems including recent versions of Mac OS X.</p>
<p>The shell interprets commands that you type into it to construct a pipeline between the different programs you are using. So, if I type:</p>
<pre>ls</pre>
<p>The <strong>ls</strong> program lists the files in the current directory and returns them to the shell, which prints them to the screen. But now, if I type</p>
<pre>ls | grep "MyFile"</pre>
<p>the shell is taking the output of <strong>ls</strong>, and instead of printing it out, it passes it to another program called <strong>grep</strong>. <strong>grep </strong>searches through the output of <strong>ls</strong> for the text &#8220;MyFile&#8221;, and sends only the lines that contain it back to the shell. The shell prints those lines to the screen.</p>
<p>Where we really get cooking is when we start using output from one command as instructions for another command. The <strong>find</strong> utility is great for this, as is the <strong>xargs</strong> utility. Find will search recursively in the folder you specify for a set of files which match the parameters you give it. Then, using the -exec flag, you can tell find to execute any command on each one of those files. <strong>xargs</strong> does something similar, but it can take any text as an input (typically, file names) and provide them as arguments to another program. <strong>find</strong> / <strong>xargs </strong>are designed to control other programs, and can be used for tasks such as a<strong> </strong>batch move, batch rename, batch conversion, etc.</p>
<p>so in keeping with our current example:</p>
<pre>ls | grep "MyFile" | xargs open</pre>
<p>The output of <strong>grep</strong>, those files or folders containing the word &#8220;MyFile&#8221;, is passed by the shell to <strong>xargs</strong>. <strong>xargs</strong> passes them to the <strong>open</strong> command, a Mac OS X utility that will try to use Finder to open each file. Simple functionality like this can be more elegantly achieved using only the find command. <a href="http://www.eliotlash.com/2011/08/tool-tips-find/">See my tutorial on using find to learn more about this incredible tool</a>.</p>
<p>Also worth mentioning are <strong>sed</strong> and <strong>awk</strong>. These programs are used to perform manipulation of text inside a pipeline.</p>
<p>There is a learning curve here, but the more I learned about how to effectively use the command line and the coreutils, the more my productivity increased.</p>
<p>Mastery of your shell&#8217;s syntax is crucial in becoming effective. Using the shell, you can construct complicated pipes which branch and merge data and execute commands to do practically anything on a massive scale.</p>
<p>To become a master of using the shell to automate things, I recommend that you practice doing more and more things from the shell instead of from a GUI. You need to understand what the most common utilities do, and the common arguments/flags that you can pass them in order to get their full range of functionality. If/when you move on to writing scripts, this knowledge will help you take advantage of built-in functionality instead of trying to implement it yourself. It becomes easier to practice shell skills if you run a website, since you often have to log in via ssh to a webserver in order to install software and make configuration changes on the webserver. I picked up most of my basic shell skills through running my personal website.</p>
<p><strong><span style="color: #993300;">A word of warning</span></strong>: Make sure you are familiar with using a command normally before invoking it with <strong>find</strong> or <strong>xargs</strong>. This type of usage requires knowledge of how the shell and different programs handle spaces, etc. You can cause damage or data loss if you don&#8217;t know what you&#8217;re doing. So learn the basics first. Test out your batch commands by adding <strong>echo</strong> in front of the command, so it will print instead of execute and you can inspect it. Test out your execution on one or two files before you execute the whole batch.</p>
<p>Here are some resources for learning more about the command line:</p>
<ul>
<li><a href="http://linuxcommand.org/index.php">LinuxCommand.org</a> &#8211; Excellent in-depth overview of the command line, suitable for total beginners</li>
<li><a href="http://mywiki.wooledge.org/BashGuide">Bash Guide on Greg&#8217;s Wiki</a></li>
<li><a href="http://mywiki.wooledge.org/BashGuide"></a><strong>man </strong>- Take advantage of the built-in manuals for each command on your system by typing &#8220;man somecommand&#8221;. Type q to exit.</li>
<li>Built-in help: Many programs have built-in help. This is usually available by invoking the program with the -h or &#8211;help flag, such as &#8220;mv &#8211;help&#8221;.</li>
<li><a href="http://www.google.com/">Google</a> &#8211; I can&#8217;t stress enough how useful it is to just look something up on Google when you&#8217;re stuck. Chances are, somebody else was having this exact same problem and found a solution!</li>
</ul>
<p><a name="find_examples"></a><br />
Here are some examples of tasks and automation that I frequently perform using the shell and some utilities. These are provided not as a tutorial, but an example of the kind of powerful automation you can achieve from a well-crafted command.</p>
<p>I&#8217;ve added echo statements to all the examples that will cause a change so they will print the commands they would execute instead of actually executing them. I&#8217;m worried about people randomly pasting commands into their terminal and running them. Here&#8217;s a hint: DON&#8217;T DO THAT! With great power comes great responsibility. Make sure you understand what a command does before you execute it on your system so you don&#8217;t get owned! Note that find (and other) syntax can vary from system to system and shell to shell so these may not all work in your environment.</p>
<p>Move a bunch of files matching my search term to a different location using <strong>find:</strong></p>
<pre>find . -name 'test*' -exec echo mv {} ../foodir \;</pre>
<p>Batch-convert a bunch of files matching my search term using <strong>find</strong> and a converter program (imagemagick in this example):</p>
<pre>find . -name '*.jpg' -exec echo convert {} {}.png \;</pre>
<p>Tidy up the output of a monitoring program like <strong>ps</strong> to only contain the information i&#8217;m interested in, using <strong>head</strong>, <strong>grep, cat,</strong> and bash input substitution syntax:</p>
<pre>cat &lt;(ps|head -1) &lt;(ps|grep bash)</pre>
<p>Use <strong>diff</strong>, <strong>comm, </strong>and other programs to find the differences between two files/directories, or perform set theory operations</p>
<p><a href="http://www.catonmat.net/blog/set-operations-in-unix-shell/">There&#8217;s a whole in-depth article on this!</a></p>
<p>I hope I have whetted your appetite a bit to go learn more about using the command line. With practice, you can accomplish in a few keystrokes what could take tons of clicking and dragging in a GUI.</p>
<p>Up next:</p>
<ul>
<li><a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/">Shell Scripting: Becoming a Wizard</a></li>
<li>Curl: Internet Magic Sauce</li>
</ul>
<p>Previously in this series:</p>
<ul>
<li><a href="http://www.eliotlash.com/2011/02/better-living-thru-automation/">Better living through automation, pt. 1 (Automator)</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/CjEUOdSHuLM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=better-living-through-automation-pt-2-the-shell-and-coreutils</feedburner:origLink></item>
		<item>
		<title>Better living through automation, pt. 1</title>
		<link>http://feedproxy.google.com/~r/eliotlash/~3/puJPLZKcDik/</link>
		<comments>http://www.eliotlash.com/2011/02/better-living-thru-automation/#comments</comments>
		<pubDate>Sat, 19 Feb 2011 09:17:09 +0000</pubDate>
		<dc:creator>eliot</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[automation]]></category>

		<guid isPermaLink="false">http://www.eliotlash.com/?p=32</guid>
		<description><![CDATA[Anything that&#8217;s tedious is repeatable; anything that&#8217;s repeatable should be done by a computer. -Robert Muller I spend a lot of time working on my computer every day. Many of the tasks that I need to perform on a computer can be incredibly tedious. Copying and pasting text from a website into a spreadsheet. Renaming [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Anything that&#8217;s tedious is repeatable; anything that&#8217;s repeatable should be done by a computer.</p>
<p>-Robert Muller</p></blockquote>
<p>I spend a <em>lot</em> of time working on my computer every day. Many of the tasks that I need to perform on a computer can be incredibly tedious. Copying and pasting text from a website into a spreadsheet. Renaming a bunch of files and moving them to a new location. Zipping a bunch of directories and uploading them to a website one by one. From an early age, I was always frustrated at these kinds of tasks. It&#8217;s a tragic waste that we have commodity PC&#8217;s capable of performing billions of calculations a second, but are still left doing the same tedious crap that we were doing 10 years ago.</p>
<p>Clearly, there&#8217;s no lack of machine &#8216;brainpower.&#8217; What most people lack is the knowledge required to effectively leverage their personal computers to automatically perform tedious tasks for them. I have successfully automated all of the tedious tasks I mentioned above in my own workflow, and many more.</p>
<p>My mission with this series of articles is to provide a high-level overview of the most effective technologies for automation that I have used, and share some pointers that have been key to my success. There are already many great tutorials that go in depth into how to use these particular technologies. I will try to provide links where appropriate, but a quick Google search is usually sufficient to turn up lots of great resources on any particular technology or program. If a technology I describe sounds useful and interesting to you, I encourage you to go try it! Monkey around with it, Google when you get stuck, and try to solve at least a small part of a real problem you are having that could use some automation. That&#8217;s how I learned everything that I know now.</p>
<p>If there&#8217;s anything you&#8217;d like me to explain in more depth, please leave a comment and let me know what it is. I will try to help, or at least point you to where you can find more information.</p>
<p>I&#8217;d like to talk a little bit about Mac OS X. At this time of writing, Mac OS X is my favorite desktop operating system. Here&#8217;s why:</p>
<ol>
<li>By default, everything works pretty much how I want it to.</li>
<li>Because Mac OS X is built on top of Unix, there&#8217;s a ton of flexibility built in. At any time, I can drop down to the command line to accomplish what I need to.</li>
</ol>
<p>Granted, Mac OS X is nowhere near as configurable and customizable as a modern desktop GNU/Linux system. However, even with the advent of fairly easy-to-use Linux distributions like Ubuntu, I think the barrier to entry might still be a little bit too high for the average user. We&#8217;ll get there eventually.</p>
<h1><span style="font-weight: normal;">Automator</span></h1>
<p><img class="alignright" title="Automator Icon" src="http://eliot.s3.amazonaws.com/eliotlash.com/Automator_Icon.png" alt="Automator Robot Icon" width="297" height="297" /></p>
<p>From an automation standpoint, Mac OS X is at the top of its game. Included with the OS is a really slick application called <a href="http://en.wikipedia.org/wiki/Automator_(software)">Automator</a>. Automator allows you to &#8220;snap together&#8221; instructions from a library of parts to create a workflow describing what you want the computer to do. Essentially, it allows you to create your own scripts without writing a line of code. You can even save them as application bundles and send them to other people. This is a great place for someone who wants to dive in to the world of automation without any prior experience. The ability to <a href="http://www.google.com/search?q=automator+actions">install custom &#8220;actions&#8221;</a> created by others, and write your own actions in <a href="http://www.macosxautomation.com/applescript/">AppleScript</a>, allows room to expand the capabilities of Automator. Some tasks I have used Automator for include:</p>
<ul>
<li>Re-sizing, renaming, or moving batches of photos (I recommend the <a href="http://automatorworld.com/archives/propper-cropper/">Proper Cropper</a> action for cropping instead of Apple&#8217;s default.)</li>
<li>Performing a series of repetitive keystrokes in an application to load files in by the batch (this made use of a custom AppleScript module to simulate key presses)</li>
</ul>
<p>One of the reasons I <em>don&#8217;t</em> like Automator and don&#8217;t use it more often is the fact that, as far as I can tell, you <em>have</em> to write your custom code in AppleScript. (<strong>Edit</strong>: I recently discovered that Python and Ruby are available as alternatives, see my comment below.) AppleScript tries to appear like natural language, but it&#8217;s just a trick. It&#8217;s just as rigid as any other programming language, but the syntax is just kind of weird and occasionally ambiguous. You are also limited to whatever actions ship with Automator, or whatever ones you can find online or write yourself using AppleScript. In the end, I found Automator a great way to interface specifically with Mac OS X GUI applications and do certain common tasks, but that I had to turn elsewhere for <span style="color: #993300;"><a href="http://www.realultimatepower.net/">real ultimate power</a></span>.</p>
<p>Up next:</p>
<ul>
<li><a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-2-the-shell-and-coreutils/">The Shell and Coreutils</a></li>
<li><a href="http://www.eliotlash.com/2011/02/better-living-through-automation-pt-3-shell-scripting-becoming-a-wizard/">Shell Scripting: Becoming a Wizard</a></li>
<li>Curl: Internet Magic Sauce</li>
</ul>
<p>Stay tuned!</p>
<img src="http://feeds.feedburner.com/~r/eliotlash/~4/puJPLZKcDik" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.eliotlash.com/2011/02/better-living-thru-automation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.eliotlash.com/2011/02/better-living-thru-automation/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=better-living-thru-automation</feedburner:origLink></item>
	</channel>
</rss>

