<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8872817900941149635</id><updated>2011-10-08T01:34:05.957-06:00</updated><title type='text'>See Jeff Run</title><subtitle type='html'>geek stuff, writ fast</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default?start-index=101&amp;max-results=100'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>245</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5037221027040392629</id><published>2011-05-20T14:14:00.002-06:00</published><updated>2011-05-20T14:36:06.252-06:00</updated><title type='text'>Seeing My DNA</title><content type='html'>There's a photomicrograph of my chromosomes on my living-room wall. I made it myself in a Human Cytogenetics course. When folks ask, I say it's a self-portrait.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been thinking about subscribing to &lt;a href="http://23andme.com"&gt;23andme&lt;/a&gt;, which analyzes your DNA, for several years, but the price was always too high. I knew it would drop over time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Two things kicked me over the edge. One was posts by &lt;a href="http://www.fdablog.org/2011/03/controversy-grows-around-fdas-shuren.html"&gt;folks like Razib Khan&lt;/a&gt; about recent moves by the FDA to shut down or hyperregulate 23andme.  The second was a trip to the &lt;a href="http://meetup.boulderandroid.com/"&gt;Boulder Android Meetup&lt;/a&gt;, where I met &lt;a href="http://blog.bespokesystems.net/"&gt;G. Hussain Chinoy&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Chuck Coughlin and I went over to recruit an Android developer or two for a project we're working on, and Hussain sent me email saying he was interested. He wasn't a great fit for the particular slots we were trying to fill -- it happens -- but I told him I was very interested to see that he was a 23andme customer. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A few days later, Hussain dropped me a quick note to say that 23andme was having a "free day."  Normally, the base price had been $199, but for that day, it was free.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That did it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm now a happy customer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I should say more about 23andme, but this post's long enough for now.  Go look for yourself.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://aircell.com"&gt;My company's still hiring&lt;/a&gt;, by the way -- contract and full-time positions.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5037221027040392629?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5037221027040392629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5037221027040392629' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5037221027040392629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5037221027040392629'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/05/seeing-my-dna.html' title='Seeing My DNA'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8465936553657789247</id><published>2011-05-15T21:00:00.002-06:00</published><updated>2011-05-15T21:20:51.796-06:00</updated><title type='text'>Audiobooks, Sort Of</title><content type='html'>I began looking for mp3 audiobooks to put in my Amazon Cloud Storage, so I could play them on my Android tablet, and ended up somewhere I hadn't guessed.&lt;br /&gt;&lt;br /&gt;I've read that folks use their phones as MP3 players.  Mine has its battery run down so fast when I use it as a phone that I can't imagine doing that. Perhaps I'm missing something.&lt;br /&gt;&lt;br /&gt;But my NookieTab is a toy I'm exploring the boundaries of, so I bought some music, put it up in Amazon's free, Cloud Storage service, and tried playing it with their Cloud Player. Works fine. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Great.&lt;br /&gt;&lt;br /&gt;How about an audiobook? Amazon doesn't sell many audiobooks in its MP3 store, because of DRM, but I saw &lt;i&gt;&lt;u&gt;Indian Tales,&lt;/u&gt; &lt;/i&gt;by Kipling and bought it.  Kipling spins great yarns -- very listen-able.&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then I tried it.  The book is machine-read.  The synthesized voice has a British accent, which is a nice touch.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I went back and saw a book on Italian.  This time, I sampled it before buying.  Yup! It's lessons in synthesized English on how to speak Italian.  &lt;a href="http://www.amazon.com/gp/search/ref=sr_kk_2?rh=i%3Adigital-music%2Ck%3Aitalian+language+learn&amp;amp;keywords=italian+language+learn&amp;amp;ie=UTF8&amp;amp;qid=1305514685"&gt;Hearing is believing.&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8465936553657789247?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8465936553657789247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8465936553657789247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8465936553657789247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8465936553657789247'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/05/audiobooks-sort-of.html' title='Audiobooks, Sort Of'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5047412672818318483</id><published>2011-05-14T06:52:00.005-06:00</published><updated>2011-05-14T09:06:55.350-06:00</updated><title type='text'>My Nookie Tablet</title><content type='html'>The Web is filled with instructions on how to root and re-flash the Nook Color. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It has much richer hardware than, say, a Kindle, so although it's sold as a locked-down, e-book reader, a chunk of its market is folks turning it into something else.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Think &lt;a href="http://plugapps.com/index.php5?title=Main_Page"&gt;pogoplug&lt;/a&gt;.  Think &lt;a href="http://en.wikipedia.org/wiki/DD-WRT"&gt;LinkSys WRT54G&lt;/a&gt;.  Think &lt;a href="http://en.wikipedia.org/wiki/Unix"&gt;DEC PDP-7&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;BestBuy had stacks of Kindles, but the shelf under the Nook was cleaned out. The salesman had to go to the stockroom to find me a box.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It comes as a locked-down reader, but the base OS is Android so you have two choices: root or re-flash.  They'll both void your warranty, so it's a matter of personal taste.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you re-flash it, there's plenty to choose from.  Google will find you instructions for putting on anything from vanilla Froyo to Ubuntu. Someone probably has a port of Windows CE.  To each, his own.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I opted for my usual route: I asked the nearest beautiful woman, "Could you help me turn this into an Android Tablet?" &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;She said, "Sure.  It'll take about five minutes, unless you want to back it up first."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Five minutes was not hyperbole.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;She had a micro-SD chip with the necessary files on her -- the OS, the Google Android apps, and an over-clocker.  We sliced off the Nook's shrink wrap, took it out, popped open the SD port, slipped in her card, brought it up, reformatted the disk and loaded on the new software, and re-booted.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Never even un-boxed the instructions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"Don't we need to charge it first?" I asked.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"I'm sure it comes with plenty of power," she said.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We looked after it was back up.  The battery was 97% full.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It found someone's near-by, open WAP easily, so I configured it to use my Google account, checked my email, and downloaded a couple of apps from the Android marketplace.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;I'm running &lt;a href="http://www.cyanogenmod.com/"&gt;Cyanogenmod&lt;/a&gt;'s Gingerbread port (Android 2.3.4, with a 2.6.29 kernel).  &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The display is beautiful, but before I could watch a free movie, from Amazon Instant Video, I had to download Flash Player from the Android Marketplace.  Their service does whine that I'm using an unsupported device, and the video's a little jerky, but I don't know whether that's the tablet or the format and bandwidth.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The rest is fiddling.  For example, making the terminal usable meant using the menu key (it's all soft keys) to make the fonts bigger.  Pairing with a blue-tooth headset required figuring out how to turn the blue-tooth headset on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The earphone jack works. There's no built-in camera or microphone, and I don't think the hardware's there to turn it into a standard cellphone, but it seems like I should be able to make VOIP calls with the blue-tooth headset.  I've poked at that one a little, but not succeeded.  Yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd wiped out the Barnes &amp;amp; Noble book reader, so no Nook e-books for me; instead, Amazon's free, Kindle-for-Android app lets me download and read the books I buy for my Kindle.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I suppose this is a great time to plug the Kindle.  Want a tablet computer?  Lots of choices, including the Color Nook.  Want an e-book reader? Buy a Kindle.&lt;/div&gt;&lt;div&gt;Sturdy, simple, beautiful, easy-to-read, dirt cheap. Connects free everywhere. Electronic paper that's as foolproof and power-thrifty as an Etch-a-Sketch. Unbeatable selection of books. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is the &lt;a href="http://en.wikipedia.org/wiki/C-47#Operational_history"&gt;C-47&lt;/a&gt; of e-book readers.  Jeremy Hinegardner tells me his grandpa's on his second one.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5047412672818318483?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5047412672818318483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5047412672818318483' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5047412672818318483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5047412672818318483'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/05/my-nookie-tablet.html' title='My Nookie Tablet'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-621598437426947492</id><published>2011-05-14T05:32:00.000-06:00</published><updated>2011-05-14T06:51:51.820-06:00</updated><title type='text'>Toys</title><content type='html'>&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; "&gt;Jealous of Steve Ballmer's buying Skype, I drove to Best Buy, Thursday afternoon, and bought a &lt;a href="http://www.barnesandnoble.com/nookcolor/index.asp"&gt;Color Nook&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The salesman offered me a protection package for $99.  I said, "I'm going to void the warranty on this so fast it'll make your head spin."&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The board has roughly the same chip set as the phone we're building &lt;a href="http://aircell.com/"&gt;at work&lt;/a&gt;. As a Nook, it was a locked-down, single-purpose reader. So far as I know, B&amp;amp;N won't even let you &lt;i&gt;get&lt;/i&gt; to some of its hardware, like the bluetooth. Reflashed, I can now even load on whatever we write for our phone and play with it. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;He said, "Next few hours?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I said, "I'd guess the warranty on this will be void fifteen minutes after I leave the store."&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wasn't wrong.  I now own a $250 Android tablet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Before I went to bed, I slammed on Amazon's Kindle for Android app.  Heh.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm waiting to see what Skype looks like after Ballmer re-flashes it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-621598437426947492?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/621598437426947492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=621598437426947492' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/621598437426947492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/621598437426947492'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/05/toys.html' title='Toys'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7799023727611353987</id><published>2011-04-22T18:57:00.001-06:00</published><updated>2011-04-22T18:59:15.918-06:00</updated><title type='text'>RMBB!</title><content type='html'>&lt;a href="http://billllsidlemind.blogspot.com/2011/04/rocky-mountain-blogger-bash.html"&gt;RMBB!&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;'bout time.  See you there.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7799023727611353987?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7799023727611353987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7799023727611353987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7799023727611353987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7799023727611353987'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/04/rmbb.html' title='RMBB!'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8139439828177964188</id><published>2011-04-14T08:46:00.002-06:00</published><updated>2011-04-14T08:50:50.321-06:00</updated><title type='text'>Free AWS Book Chapters</title><content type='html'>In my email this morning, from Amazon:&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; "&gt;&lt;blockquote style="font-family: arial, sans-serif; font-size: 13px; "&gt;*Free AWS Book Chapters*&lt;br /&gt;Download a free PDF copy of the first three chapters of AWS Evangelist Jeff Barr's book, Host Your Website in the Cloud at &lt;a href="http://www.sitepoint.com/books/cloud1/samplechapters.php" target="_blank" style="color: rgb(0, 0, 204); "&gt;http://www.sitepoint.com/&lt;wbr&gt;books/cloud1/samplechapters.&lt;wbr&gt;php&lt;/a&gt;. Jeff's book covers principal AWS services including EC2, S3, SimpleDB, CloudWatch, and RDS. The book makes use of the AWS SDK for PHP and includes plenty of working examples. Find the book on Amazon.com: &lt;a href="http://www.amazon.com/Host-Your-Web-Site-Cloud/dp/0980576830" target="_blank" style="color: rgb(0, 0, 204); "&gt;http://www.amazon.com/Host-&lt;wbr&gt;Your-Web-Site-Cloud/dp/&lt;wbr&gt;0980576830&lt;/a&gt;&lt;/blockquote&gt;&lt;span class="Apple-style-span"&gt;If you went to BLUG's &lt;a href="http://lug.boulder.co.us/special_events.html"&gt;AWS-Installfest-in-the-Cloud&lt;/a&gt; event, this ties right in.  Good book, too.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8139439828177964188?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8139439828177964188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8139439828177964188' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8139439828177964188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8139439828177964188'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/04/free-aws-book-chapters.html' title='Free AWS Book Chapters'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-893731129661761160</id><published>2011-04-11T08:31:00.002-06:00</published><updated>2011-04-11T08:33:17.341-06:00</updated><title type='text'>Sort of Balkan Dancers</title><content type='html'>&lt;a href="http://www.i-programmer.info/news/150-training-a-education/2255-sorting-algorithms-as-dances.html"&gt;Another forehead-smacking episode of "Why didn't I think of that?"&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;HT: Chuck Hipschman&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-893731129661761160?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/893731129661761160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=893731129661761160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/893731129661761160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/893731129661761160'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/04/another-forehead-smacking-episode-of.html' title='Sort of Balkan Dancers'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-316180989922665835</id><published>2011-04-11T08:13:00.002-06:00</published><updated>2011-04-11T08:23:26.935-06:00</updated><title type='text'>23-and-me one-day sale</title><content type='html'>&lt;div&gt;&lt;a href="https://www.23andme.com/"&gt;23-and-me gives you information about your own DNA&lt;/a&gt;.  I just became a customer.  They're running a sale.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Normally, it's $199, plus a $9 a month subscription to updates for a year (after which you can continue to subscribe or cancel).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Today only: you still have to subscribe, but the $199 is waived, so it's about $100 instead of about $300.  I'll find out whether the subscriptions are worth it over the next year.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Note that &lt;a href="http://mengbomin.wordpress.com/2011/03/09/beware-genetic-paternalism/"&gt;Federal bureaucrats want to shut them down&lt;/a&gt; because they think your DNA is something that only an M.D. should explain to you.  Even without that, though, I'd have still bought it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-316180989922665835?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/316180989922665835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=316180989922665835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/316180989922665835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/316180989922665835'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2011/04/23-and-me-one-day-sale.html' title='23-and-me one-day sale'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4811793246417339173</id><published>2010-12-24T10:38:00.005-07:00</published><updated>2010-12-24T11:11:59.835-07:00</updated><title type='text'>Handling Failure</title><content type='html'>Here are two coding styles for handling failure.  I read a lot of code that uses the first. I always use the second.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(1)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-something;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;if (success) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-this;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-that;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;[many lines of stuff]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-some-other-thing;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;else&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;print-error-message-and-exit;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;(2)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-something;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;if (failure) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;print-error-message-and-exit;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-this;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-that;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;[many lines of stuff]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-some-other-thing;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I could go on at length to try to justify my strong preference, but I won't. In the end, it's just taste.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No, I take it back, I will rationalize a little. Here are some reasons I prefer #2.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;It's shorter overall.&lt;/li&gt;&lt;li&gt;The short alternative comes first, so you don't overlook it in the noise.&lt;/li&gt;&lt;li&gt;There's one fewer nesting level to puzzle through.  This also occasionally permits longer lines without word-wrap.&lt;/li&gt;&lt;li&gt;It feels more like exception handling, and saying what I mean: A problem? Let's bail.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;In Perl, the solution is even more stereotyped and easy-to-read:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;do-something OR die "it didn't work";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;In bash, I use &lt;a href="http://seejeffrun.blogspot.com/2008/08/error-handling-again.html"&gt;a shell function, &lt;/a&gt;&lt;span class="Apple-style-span" &gt;&lt;a href="http://seejeffrun.blogspot.com/2008/08/error-handling-again.html"&gt;die()&lt;/a&gt;&lt;/span&gt;, which I wrote to let me code in the same style:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;blockquote&gt;do-something || die "It didn't work"&lt;/blockquote&gt;&lt;blockquote&gt;...&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4811793246417339173?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4811793246417339173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4811793246417339173' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4811793246417339173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4811793246417339173'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/12/handling-failure.html' title='Handling Failure'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4893889187238887398</id><published>2010-11-29T19:54:00.003-07:00</published><updated>2010-11-29T20:17:09.913-07:00</updated><title type='text'>Process Whack-a-Mole: An Alternative Approach</title><content type='html'>&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Gosh. I haven't blogged in, like, forever.  Inspired, as is so often the case, by Hal Pomeranz and friends, here's something.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Over at his Command-Line Kung Fu blog, Hal has posted a solution to the problem of writing a &lt;a href="http://blog.commandlinekungfu.com/2010/11/episode-122-more-whacking-of-moles.html"&gt;process-whack-a-mole command, that watches for any new process and kills it.&lt;/a&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial; font-size: small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: arial; font-size: small; "&gt;(Hal's self-imposed constraint is always that his solutions really be command lines -- they can't be full-blown scripts -- and that they not use Perl, or other languages that are powerful enough that their use would feel like cheating.)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://blog.commandlinekungfu.com/2010/11/episode-122-more-whacking-of-moles.html"&gt;&lt;/a&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Nothing wrong with his approach at all, but here's another. (I mailed it to Hal, who said, "Post it somewhere, Dude.")&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; border-collapse: collapse; font-size: 13px; "&gt;&lt;blockquote style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;$ ps -e o pid,ppid,cmd | grep -v $$ &gt; baseline; while : ; do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span &gt;&gt; sleep 5&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span &gt;&gt; ps -e o pid,ppid,cmd | grep -v $$ &gt; now&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span &gt;&gt; join -v 2 baseline now &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span &gt;done&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;This is, at least, a single command line. :-)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It shows off a couple of things:&lt;div&gt;&lt;ol&gt;&lt;li style="margin-left: 15px; "&gt;&lt;b&gt;&lt;span &gt;join -v&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;li style="margin-left: 15px; "&gt;the output of &lt;b&gt;&lt;span &gt;ps&lt;/span&gt;&lt;/b&gt; is pre-sorted by process-number&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;The didactic downside? It doesn't show off arrays or "[[" .  (I spent a minute in philosophical reverie, contemplating the elevated virtue of using files to store data for shell scripts, but then realized this is engineering and snapped out of it.)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, and I completely love Hal's "| grep -v $$", which I never would have thought of.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On reflection, the only thing the join would normally see is the ps itself, which is gone by the time of the join, so for the real deal, this can be pared down a titch.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;# ps -e o pid,cmd &gt; baseline; while : ; do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;&gt; sleep 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;&gt; ps -e o pid,cmd &gt; now&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;&gt; kill -9 $(join -v2 -o2.1 baseline now)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;done 2&gt;/dev/null &amp;amp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;span &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Just kill everything new and ignore the error message from not being able to kill the ps:  &lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;    "Kill them all and let The Kernel sort them out."&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4893889187238887398?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4893889187238887398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4893889187238887398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4893889187238887398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4893889187238887398'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/11/process-whack-mole-alternative-approach.html' title='Process Whack-a-Mole: An Alternative Approach'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5591942804296711067</id><published>2010-06-16T12:00:00.003-06:00</published><updated>2010-06-16T12:09:42.761-06:00</updated><title type='text'>Just in case</title><content type='html'>I just learned something new about shell syntax -- specifically, about the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;case&lt;/span&gt; statement.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The shell's big enough that I expect I'll be able to keep learning things about it for a long time, even though I've been writing shell scripts for ... lessee ... about 30 years.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's today's:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm used to writing this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;case $key in&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    whatever) do-something ;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    *) some-default-behavior ;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;I just read a Fedora system script that looks like this, instead:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;case $key in&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    (whatever) do-something ;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    (*) some-default-behavior ;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;The leading paren is optional, but legal.  And not just for &lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bash&lt;/span&gt;&lt;/b&gt;, but for any POSIX shell.  Amazing.  Also, the last item doesn't have to have the semis, so it could even be this:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;case $key in&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;    (whatever) do-something ;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;    (*) some-default-behavior&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5591942804296711067?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5591942804296711067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5591942804296711067' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5591942804296711067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5591942804296711067'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/06/just-in-case.html' title='Just in case'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8484283685257443573</id><published>2010-05-26T14:12:00.007-06:00</published><updated>2010-05-26T14:52:55.622-06:00</updated><title type='text'>Back Off Man, I'm a Scientist</title><content type='html'>&lt;div&gt;&lt;i&gt;  "I have no faith in anything short of actual measurement &amp;amp; the Rule of Three"&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;       -- Charles Darwin&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;In an interminable thread about recycling computer parts, on the &lt;a href="http://lug.boulder.co.us/"&gt;Boulder Linux Users' Group&lt;/a&gt; mailing list, Davide Del Vento injects a completely unsubstantiated and largely dubious claim:&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:arial, sans-serif;font-size:small;"&gt;&lt;i&gt;&lt;blockquote&gt;The point of the discussion is what we agree is ok to "kill" or "destroy", and what is not. Is it ok to kill a cow to feed my kids? Most people would say "yes". Is it ok to kill Jeffrey Haemer to feed my kids? Most people would say  "no".&lt;/blockquote&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Doing science means collecting data.  The polls in the left sidebar test his claim.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:arial, sans-serif;font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:arial, sans-serif;font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;We shall see, eh?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8484283685257443573?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8484283685257443573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8484283685257443573' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8484283685257443573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8484283685257443573'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/05/back-off-man-im-scientist.html' title='Back Off Man, I&apos;m a Scientist'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2753773249596542422</id><published>2010-05-14T11:04:00.003-06:00</published><updated>2010-05-14T11:17:34.940-06:00</updated><title type='text'>NCAR Software Manufacturing Presentation, the Movie</title><content type='html'>Courtesy of Davide Del Vento, &lt;a href="http://sea.ucar.edu/event/using-software-toilet-plungers"&gt;here's the video&lt;/a&gt; in H.264.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2753773249596542422?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2753773249596542422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2753773249596542422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2753773249596542422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2753773249596542422'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/05/ncar-software-manufacturing.html' title='NCAR Software Manufacturing Presentation, the Movie'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-510874511283258729</id><published>2010-04-28T18:07:00.004-06:00</published><updated>2010-04-28T18:09:26.149-06:00</updated><title type='text'>NCAR Manufacturing Presentation</title><content type='html'>&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style=" color: rgb(102, 102, 102); font-family:georgia;"&gt;&lt;i&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_228fmrnzpdv"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;What I'll Say&lt;/span&gt;&lt;/a&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_228fmrnzpdv" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_229grbz4xc6"&gt;How I'll Say It&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_229grbz4xc6" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_232c3sgzgcb"&gt;Having The Exact Code You Need&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_232c3sgzgcb" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_223gd89nhhq"&gt;Building What You Have&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_223gd89nhhq" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_227fbbqh2fr"&gt;Testing What You've Built&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_227fbbqh2fr" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_224d9f7kv4k"&gt;Looking Closely at What You Tested&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_224d9f7kv4k" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_226pb9kqpcg"&gt;Sharing It After You've Looked At It Long Enough&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_226pb9kqpcg" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_231hhg6brcz"&gt;"What Was He Talking About?"&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_231hhg6brcz" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="color:#666666;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;a href="http://docs.google.com/present/view?id=aq2tnf2qg9t_234dwhqbggd"&gt;"Who Was That Masked Man?"&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;iframe src="http://docs.google.com/present/embed?id=aq2tnf2qg9t_234dwhqbggd" frameborder="0" width="410" height="342"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-510874511283258729?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/510874511283258729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=510874511283258729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/510874511283258729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/510874511283258729'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/04/ncar-manufacturing-presentation.html' title='NCAR Manufacturing Presentation'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3461982879303402854</id><published>2010-04-08T08:52:00.012-06:00</published><updated>2010-04-08T10:37:29.989-06:00</updated><title type='text'>Performance Tuning Shell Scripts?  Why, yes.</title><content type='html'>&lt;div&gt;Can I write a command-line that lists open TCP ports as quickly as &lt;b&gt;nmap&lt;/b&gt;?  No way.  But can I make one that's fast?  Yes, indeedy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The trick is to do it all in a single shell command.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I always read Hal Pomeranz's weekly, &lt;a href="http://blog.commandlinekungfu.com/"&gt;Command Line Kung Fu blog&lt;/a&gt;.  Inevitably, either I learn something because he tells me, or I learn something because it gets me thinking about how I might do what he's done differently.  (That's not an exclusive-or.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This week, Hal writes a command-line that looks for open TCP ports.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's his command.  (For a dramatic reading,&lt;a href="http://blog.commandlinekungfu.com/2010/04/episode-89-lets-scan-us-some-ports.html"&gt; see his post&lt;/a&gt;.)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;for ((i=1; i&amp;lt;65535; i++)) ( echo &gt; /dev/tcp/localhost/$i ) 2&gt;/dev/null &amp;amp;&amp;amp; echo $i; done&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;It isn't fast, and he ends with, "But really, if speed were a factor you'd be using nmap instead."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But &lt;i&gt;can&lt;/i&gt; I get it to run faster?  At least a little?  Why, yes I can.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Replacing this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;for (( i=1; i&amp;lt;65535; i++ ))&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;by this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;for i in {1..65535}&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;and this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;echo &gt; /dev/tcp/localhost/$i&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;by this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;&gt; /dev/tcp/local/host/$i  &lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;or even&lt;/span&gt;&lt;/span&gt; &amp;lt; /dev/tcp/localhost/$i&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt; &lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;make minor improvements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But a bigger win comes from getting rid of subshells.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The parens around the &lt;b&gt;echo&lt;/b&gt; create a subshell, which requires a &lt;b&gt;fork()&lt;/b&gt; and an &lt;b&gt;exec()&lt;/b&gt;, each time through the loop.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By getting rid of those, and discarding error messages at the end of the loop, all the work takes place right in the parent shell.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How much does that improve things?  A lot.  Here are the numbers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;time nmap -p1-65535 --open localhost&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;real  0m1.366s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;user  0m0.280s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sys   0m0.850s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;time for (( i=1; i&amp;lt;65535; i++ )) ( echo &gt; /dev/tcp/localhost/$i ) 2&gt;/dev/null &amp;amp;&amp;amp; echo $i; done&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;real  1m55.727s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;user  0m12.640s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sys   1m28.200s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;time for i in {1..65536} ; do &gt;/dev/tcp/localhost/$i &amp;amp;&amp;amp; echo $i; done 2&gt;/dev/null&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;real  0m6.203s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;user  0m3.290s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;sys   0m2.780s&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tom Christiansen claims he can usually write Perl scripts that run within a factor of&lt;a href="http://en.wikipedia.org/wiki/E_(mathematical_constant)"&gt; 'e' (2.718281828...)&lt;/a&gt; of the equivalent C program.  Here, I'm only doing half that well, but that's not bad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even in the shell, sometimes a little tweak makes a big difference.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;I'd offer extra points to the reader who knows an attribution for the quote "Make it work, then make it fast," but that would require readers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It was, however, Frank Zappa who said, "Speed will turn you into your parents."&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3461982879303402854?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3461982879303402854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3461982879303402854' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3461982879303402854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3461982879303402854'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/04/performance-tuning-shell-scripts-why.html' title='Performance Tuning Shell Scripts?  Why, yes.'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8635302961428469780</id><published>2010-03-29T17:24:00.008-06:00</published><updated>2010-03-29T18:02:46.511-06:00</updated><title type='text'>There's a Lesson Here, but I Can't Remember What</title><content type='html'>&lt;span class="Apple-style-span"   style="  border-collapse: collapse; font-family:arial, sans-serif;font-size:15px;"&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Perhaps you are graced with a mind like a steel trap.  I have always had a mind like a steel colander.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;I frequently read stuff I wrote, and think, "That's clever.  Too bad I can't remember ever knowing that, much less writing about it."&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Just now, I was reading an RHCE-prep guide that was explaining &lt;/span&gt;&lt;/span&gt;&lt;a href="http://linux.about.com/library/cmd/blcmdl1_pr.htm"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;pr&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;.  I thought, "&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;pr?&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;  Geez.  There's some ancient history.  Next they'll be explaining &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ibiblio.org/pub/languages/fortran/ch2-14.html"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;FORTRAN line-printer-carriage-control codes&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;."&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;This starts me reminiscing. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;"There was an old, &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.lbl.gov/Science-Articles/Archive/software-award.html"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Software Tools&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; filter, in &lt;/span&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/RATFOR"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;RATFOR&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;, that would interpret those codes, called &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;asa&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; (a reference to the American Standards Association, &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ansi.org/about_ansi/introduction/history.aspx?menuid=1"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;a progenitor of ANSI's&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;).  At some point, it was ported to C/Unix.  I should see if it's on my Ubuntu desktop."&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;(As an aside, and before I forget to say it, Kernighan and Plauger's &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.amazon.com/Software-Tools-Brian-W-Kernighan/dp/020103669X/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1269905429&amp;amp;sr=8-1"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Software Tools&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; is the best book ever written about software engineering.)&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;It's not there.  I think, "Well, okay, I'll install it.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;I try apt-cache search and don't find it.  Rats.  &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;I google for an Ubuntu version.  Nothing.  A Linux version?  Nothing.   Humph.  &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Well, surely it was in UNIX Version 7.  I remember some work Tom Christiansen put in, collecting Perl implementations of old, V7 commands.  Maybe he found an implementation of &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;asa(1)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; that I can just port.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Except I can't remember what he called his collection.  I go back to googling, this time for Tom's collection.  After a bunch of failed tries, I finally get a hit.  You guessed it: a column by Jeff Copeland and, um, me -- &lt;/span&gt;&lt;/span&gt;&lt;a href="http://alumnus.caltech.edu/~copeland/work/ppt.html"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Software Ptools&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; -- which I have no recollection of ever having written.  How embarrassing.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;I should have given up right there, while I was behind, but Noooo ....   ("What would you pay?  But wait!  There's less!")&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Had we provided the name of Tom's project?  Sho 'nuff: "Perl Power Tools."  Maddeningly, the link in our column has gone dead.  The universe hates me and there's no beer in the fridge.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;I scroll down, hoping for another link.  Ooh!  Look!  There's code!  We &lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;implement&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; a V7 command, right there in the column, to contribute to PPT ourselves.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;We implement &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;asa(1)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;Oh, ow.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;(I've now learned that the entire Perl Power Tools project has been moved &lt;/span&gt;&lt;/span&gt;&lt;a href="http://search.cpan.org/~CWEST/ppt/"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;to the CPAN&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt; by Casey West.)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="im" style="color: rgb(80, 0, 80); "&gt;&lt;/div&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8635302961428469780?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8635302961428469780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8635302961428469780' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8635302961428469780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8635302961428469780'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/theres-lesson-here-but-i-cant-remember.html' title='There&apos;s a Lesson Here, but I Can&apos;t Remember What'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5057919042660687686</id><published>2010-03-14T14:01:00.003-06:00</published><updated>2010-03-14T14:46:43.320-06:00</updated><title type='text'>Estimating: The Envelope, Please.</title><content type='html'>&lt;div&gt;How much does it cost Amazon to ship me a Kindle book?  About a nickel.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How much did it cost us to get letters saying we're going to get census forms?  About $50 million.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How do I get these?  Back-of-the-envelope calculations.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back-of-the-envelope calculations are the quick calculations we do, from simple assumptions, to give us a sense of rough sizes.  They may not let us tell whether the answer is 5 or 9, but they can let us see the answer isn't 5 billion -- a 5 followed by 9 zeros.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My sister, Jo, the Tattooed Lady, wondered out loud, this week, "... just how many millions of dollars it cost The US Commerce Dept (read 'us, the taxpayers'), to send everybody in the US a letter this week that says that they will be sending us a census report to fill out.  'Ooooooo. Look out!!!! Here it comes!!!' "&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's do a back-of-the-envelope calculation. (No pun intended.) It's not hard.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How much does it cost to send a letter?  A first-class stamp costs $0.44. The USPS loses money, which is why they want to cut back to 5-day-a-week delivery. So the real cost of processing and delivering a letter is something like $0.50.  Could it be $0.30?  Or $0.72?  Maybe.  But it's less than five bucks and more than a farthing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What's the cost of producing each letter -- printing, stuffing, and so on? At Kinko's, they'd charge you somewhere between a nickel and a dime.  Ditto for the public library.   Real money, but we're still talking a total cost of around half a buck per letter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;They sent one to each household, and America has over 100 million of those.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We paid at least fifty million bucks for those letters. $50,000,000 .  As Jo says, "Here it comes."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But what did we pay to draft the letter, translate it into a bunch of other languages, and get all that approved and processed through our Federal bureaucracy?  Probably not even an extra fifty million. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a second example: What sort of profit is Amazon making on Kindle books?  I wondered this last year when I bought my Kindle.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's see .... Once they've payed the publisher for the book, they probably get a machine-readable version for next-to-nothing -- maybe free.  Converting to the Kindle data format is probably done by a piece of software that they wrote once, and amortize across all their books, which means that probably doesn't contribute much either.  Amazon's big cost is probably delivery -- what they pay Sprint to get it to us.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So how much is that?  Hand me that envelope.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;They'll sell me a subscription to a blog for about $2/month.  The content is free if I have a browser, and I can't imagine they're trying to make a lot of money from these, either.   The $2 is probably Amazon's delivery cost.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The kind of person who reads a blog on his Kindle is a junkie who, I'll guess, might read it three times a day.  That's 30*3 = 90, or about a hundred deliveries a month: two cents a day.  Books are bigger, but they come over so fast that I bet connection-set-up and -tear-down costs dominate the price.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Amazon's sells new releases at $9.99.  This calculation says almost all of that is profit.  Their delivery cost, I guessed, was under a nickel a copy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How close did I come?  &lt;a href="http://techcrunch.com/2010/01/20/amazon-royalty-kindle-dtp/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+Techcrunch+%28TechCrunch%29"&gt;In a January press release&lt;/a&gt;, Amazon revealed it was "less than six cents."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When the government can send us useless letters by Kindle (or email), they'll cost us far less.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; "But what could the government do with its vast inventory of surplus envelopes?" the politicians will ask.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Two suggestions come to mind.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5057919042660687686?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5057919042660687686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5057919042660687686' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5057919042660687686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5057919042660687686'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/estimating-envelope-please.html' title='Estimating: The Envelope, Please.'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6060018514256287654</id><published>2010-03-11T14:00:00.002-07:00</published><updated>2010-03-11T14:06:00.882-07:00</updated><title type='text'>Collatz Conjecture</title><content type='html'>I like &lt;a href="http://xkyle.com/2010/03/04/xkcds-collatz-conjecture/"&gt;this shell script&lt;/a&gt;, by Kyle Anderson.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I found out about it because Paul Hummer's created a &lt;a href="http://planet.nclug.org/"&gt;Northern Colorado Linux Blog aggregator.&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks, Paul!  And Kyle.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6060018514256287654?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6060018514256287654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6060018514256287654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6060018514256287654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6060018514256287654'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/collatz-conjecture.html' title='Collatz Conjecture'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1368576272547754065</id><published>2010-03-09T17:30:00.007-07:00</published><updated>2010-03-09T17:41:42.733-07:00</updated><title type='text'>Generating Arbitrary Numbers</title><content type='html'>&lt;div&gt;Sometimes, "arbitrary" and "random" aren't synonyms.  Here's an example of how to generate the former without their being the latter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One nice thing about knowing people who make me think is that it gives me things to post about.  For example, Hal Pomeranz, Ed Skoudis, Tim Medin, and Paul Asadoorian have a weekly blog, called &lt;a href="http://blog.commandlinekungfu.com"&gt;Command Line Kung Fu&lt;/a&gt;, that compares and contrasts command-line tricks for different operating systems.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I only every use Linux, so I read Hal's stuff and skip the Windows and DOS stuff.  Even with this, every week or two Hal's post makes me think, "Wait!  Here's something he didn't mention!" (typically because it's slightly off-topic).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In &lt;a href="http://blog.commandlinekungfu.com/2010/03/episode-85-coincidence-randomness.html"&gt;this week's column&lt;/a&gt; they generate random time intervals. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's Hal's punchline:&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;i&gt;  [...] in larger enterprises you might have hundreds or thousands of machines that all need to do the same task at a regular interval. Often this task involves accessing some central server-- grabbing a config file or downloading virus updates for example. If a thousand machines all hit the server at exactly the same moment, you've got a big problem. So staggering the start times of these jobs across your enterprise by introducing a random delay is helpful. You could create a little shell script that just sleeps for a random time and then introduce it at the front of all your cron jobs like so:&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;  0 * * * * /usr/local/bin/randsleeper; /path/to/regular/cronjob&lt;/i&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;(The column sketches how to implement 'randsleeper'.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yep.  This works fine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But as it stands, the cronjob could kick off one job at 9:59, and the next one at 10:00.  What if I want to spread my machines across the hour, but want each machine to use a fixed timeslot, so the elapsed time between runs is a full hour for any given machine?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's one way:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Pick an arbitrary machine-specific number, like the IPV6 address, or the MAC address of the ethernet card,&lt;/li&gt;&lt;li&gt;Convert it to an integer.&lt;/li&gt;&lt;li&gt;Take it mod the time interval.&lt;/li&gt;&lt;li&gt;Use that number for the time to start the job.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;Here's code to do that, which, as always, I grow, bit-by-bit, on the command line, by getting a little piece right, recalling that piece, and adding another step.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Step 1:&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Get a unique, but arbitrary, machine-specific identifier (the MAC address of the first NIC).&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;ifconfig | awk '/HWaddr/ {print $NF; exit 0}'&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;00:1e:c9:3d:c0:0c&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Step 2:&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Strip the colons&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;ifconfig | awk '/HWaddr/ {print $NF; exit 0}' | sed 's/://g'&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;001ec93dc00c&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;And interpret the result as a hex number.  (The shell requires hex numbers begin with "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;0x&lt;/span&gt;", so I'll just tack that on.)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;b&gt; echo $(( 0x$(ifconfig | awk '/HWaddr/ {print $NF; exit 0}' | sed 's/://g') ))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;132225286156&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Step 3:&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Mod it by the number of seconds in an hour, to get an arbitrary second.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;echo $(( 0x$(ifconfig | awk '/HWaddr/ {print $NF; exit 0}' | sed 's/://g') % (60*60) ))&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;556&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Step 4:&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Always sleep until that many seconds after the hour, then kick off the job.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;crontab -l &gt; Cronjobs&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;echo "0 * * * * sleep \$(( 0x\$(ifconfig | awk '/HWaddr/ {print \$NF; exit 0}' | sed 's/://g') % (60*60) )); /path/to/regular/cronjob" &gt;&gt; Cronjobs&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;crontab Cronjobs&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Ta-da.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(For step four, I'd probably actually kick off &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cron -e&lt;/span&gt; and paste the line in; otherwise there are just too many ugly backslashes to get wrong.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Warning: This will not work if your machines' MAC addresses cluster around the same value, mod 556. :-)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1368576272547754065?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1368576272547754065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1368576272547754065' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1368576272547754065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1368576272547754065'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/generating-arbitrary-numbers.html' title='Generating Arbitrary Numbers'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2707949276406241875</id><published>2010-03-02T14:30:00.008-07:00</published><updated>2010-03-02T15:25:21.221-07:00</updated><title type='text'>Better Safe Than Sorry: Writing Code that Writes Safer Code</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;I write code that writes code.  A lot.  On the command line.  It's safer.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Hal Pomeranz and co-conspirators have &lt;/span&gt;&lt;a href="http://blog.commandlinekungfu.com/2010/03/episode-84-fixing-filenames.html"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;another fine post up about command-line programming&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;.  In it, they write a clever loop to rename a list of numbered attachments.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Here's Hal's code:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cat id-to-filename.txt | while read id file; do mv attachment.$id "$file"; done&lt;/span&gt;&lt;id-to-filename.txt&gt;&lt;/id-to-filename.txt&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;(His input file is a two-column list, like this:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cat id-to-filename.txt&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;43567  sekrit plans.doc&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;44211  pizza-costs.xls&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;And, actually, Hal takes the list from stdin, with a less-than sign.   Blogger whines and eats my posts when I use those -- it thinks I'm opening an unclosed HTML tag.  What a pain.)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;The quotes are there because without them the code tries to do this:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv attachment.43567 sekrit plans.doc&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;which gets the mysterious message back&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv: target `plans.doc' is not a directory&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="  ;font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Uh-oh.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;When this happens, I usually don't know what the message means.  Figuring it out eats time. Plus, with my luck, some files have been moved but others haven't.  Recovering from that eats even more time.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Here's what I type instead:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;First step: I write code that says what I'd like to do.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cat id-to-filename.txt | while read id file; do echo "mv attachment.$id $file"; done&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv attachment.43567  sekrit plans.doc&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv attachment.44211  pizza-costs.xls&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Often, when I do this, I scan the output, notice something's going to go wrong, and fix it.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;"Oh.  Oops.  I need quotes.  I'm an idiot."&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Note that&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt; no files were moved&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;; my code's only echoing commands.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Next step: I recall my command-line, with an up-arrow, and add fixes.  I keep doing that until the commands I see are the ones I actually want.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; cat id-to-filename.txt | &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;while read id file; do echo "mv attachment.$id '$file' "; done&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv attachment.43567  'sekrit plans.doc'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;mv attachment.44211  'pizza-costs.xls'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Look okay?  Yep.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Last step: I recall the previous command, one final time, and pipe it to a subshell, which executes the commands my code writes.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; cat id-to-filename.txt | while read id file; do echo "mv attachment.$id '$file' "; done | bash&lt;id-to-filename.txt&gt;&lt;/id-to-filename.txt&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;When I'm nervous about what I'm doing, I even try out the first line by itself, like this:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"   style="font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; cat id-to-filename.txt | while read id file; do echo "mv attachment.$id '$file' "; done&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; | head -1 | bash &lt;id-to-filename.txt&gt;&lt;/id-to-filename.txt&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style=" ;font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;I check the result, and if I've done the right thing I go ahead and run the rest.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span"   style="font-family:'courier new';font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cat id-to-filename.txt | while read id file; do echo "mv attachment.$id '$file' "; done | sed 1d | bash&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;"Never write code on the command line when you can write code that writes code on the command line,"&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt; I always say.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2707949276406241875?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2707949276406241875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2707949276406241875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2707949276406241875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2707949276406241875'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/better-safe-than-sorry-writing-code.html' title='Better Safe Than Sorry: Writing Code that Writes Safer Code'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5900911782209651796</id><published>2010-03-01T15:51:00.003-07:00</published><updated>2010-03-01T15:59:19.974-07:00</updated><title type='text'>NFS Made Easier</title><content type='html'>&lt;div&gt;Automounting disks is magic.  Autodetecting what to automount is magic-er.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Last weekend I set up my pogoplug as an NFS server, and installed and configured &lt;i&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;autofs&lt;/span&gt;&lt;/i&gt; to look for specific directories on the pogoplug.  This weekend, I revisited that configuration and learned I was working too hard.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/auto.master&lt;/span&gt;, the entry "&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/net -hosts&lt;/span&gt;" says, "When I type '&lt;i&gt;ls /net/foo&lt;/i&gt;', do these steps:"&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;look for a host named '&lt;i&gt;foo.com&lt;/i&gt;' , &lt;/li&gt;&lt;li&gt;ask &lt;i&gt;foo.com&lt;/i&gt; what filesystems it's exporting&lt;/li&gt;&lt;li&gt;mount them under &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/net/foo.com&lt;/span&gt;&lt;/li&gt;&lt;li&gt;now do the '&lt;i&gt;ls&lt;/i&gt;'&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;No modifying &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/auto.misc&lt;/span&gt; every time you want to automount a new machine: the machine just appears.  There is an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/auto.net&lt;/span&gt;, but it's a script that &lt;i&gt;autofs&lt;/i&gt; uses to ask a remote host what it's exporting.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Using remote filesystems could be even easier and more transparent (I could, for example, imagine having &lt;i&gt;upstart&lt;/i&gt; manage the whole process, and having&lt;i&gt; autofs&lt;/i&gt; be installed by default) but not much.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5900911782209651796?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5900911782209651796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5900911782209651796' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5900911782209651796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5900911782209651796'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/03/nfs-made-easier.html' title='NFS Made Easier'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2309231819745361549</id><published>2010-02-23T05:48:00.002-07:00</published><updated>2010-02-23T06:24:40.511-07:00</updated><title type='text'>The Magic SysRq Key</title><content type='html'>My netbook hangs about once a day.  I can now reboot it more easily, thanks to the magic SysRq key.&lt;br /&gt;&lt;br /&gt;I'm not sure why it hangs, and I'm not very worried about it.  Netbook releases are new, and I remember the same kinds of problems when Linux notebooks were new.  I had one laptop that worked perfectly except for sound, the mouse, and networking.  :-)  The next release fixed all those.  (Even now, I have a pair of old notebooks running Jaunty Jackalope because Karmic Koala won't run their fans.  They overheat and shut themselves off within minutes.)&lt;br /&gt;&lt;blockquote&gt;I even remember the problems when Unix PCs were new.  I was in Dave Barach's living room, in 1983, when he got a call from our Maryland office, which had just received the editor Dave had sent them for our as-yet-unreleased PC/IX product, done under contract to IBM, which was to run on stock IBM PC/XTs.&lt;/blockquote&gt;&lt;blockquote&gt;I could only hear Dave's side of the conversation.&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;What do you mean, "The color's wrong"?  What do you mean, "color"?  &lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;We'd never seen a PC with a color monitor.  Weren't all displays monochromatic?  Once we found out how they worked, Dave fixed the problem.&lt;br /&gt;&lt;/blockquote&gt;I am, however, discomfitted by having to power-cycle a box -- I worry about unsynced disks and stuff.   Luckily, some neuron fired and I remembered the &lt;a href="http://en.wikipedia.org/wiki/Magic_SysRq_key"&gt;magic SysRq key&lt;/a&gt;.  I have had to use it so little, over the years, that I didn't remember any details, but Wikipedia came to my rescue.  It does the trick, and lets me do a soft re-boot from my keyboard. &lt;br /&gt;&lt;br /&gt;(My keyboard doesn't actually have a key labelled "SysRq," but Alt-"Print Scrn"-k works just as well.)&lt;br /&gt;&lt;br /&gt;No muss, no fuss, no bad blocks.  Magic.&lt;br /&gt;&lt;br /&gt;&lt;a style="font-style: italic;" href="http://www.youtube.com/watch?v=bl9bvuAV-Ao"&gt;Thrupence and sixpence every day.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2309231819745361549?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2309231819745361549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2309231819745361549' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2309231819745361549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2309231819745361549'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/02/magic-sysrq-key.html' title='The Magic SysRq Key'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6588285774202178429</id><published>2010-02-23T05:33:00.003-07:00</published><updated>2010-02-23T05:47:06.964-07:00</updated><title type='text'>Space, The Final Frontier</title><content type='html'>Last night, I gave &lt;a href="http://seejeffrun.blogspot.com/2010/02/wheres-my-jet-pack.html"&gt;my Dell netbook&lt;/a&gt; a terabyte drive.&lt;br /&gt;&lt;br /&gt;A few weeks ago, Scott Mann talked me into buying a &lt;a href="http://pogoplug.com/"&gt;Pogoplug&lt;/a&gt;, an embedded-Linux device, about the size of my palm, with an ethernet port and four USB ports to hang external disks off of.  Plug it in, plug in a drive (or four), and you're done: no muss, no fuss.  Kristina gave me a terabyte drive for Christmas, so they're now up and running in one corner of a bookshelf.&lt;br /&gt;&lt;br /&gt;Unfortunately, it's built to serve disks up through a web interface, so each byte goes out the door, off to their servers in San Jose or Boca Raton or Minneapolis or wherever they are, and back down to whereever it's wanted.&lt;br /&gt;&lt;br /&gt;But wait!  It's a Linux box.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://openpogo.com/"&gt;OpenPogo&lt;/a&gt; community has a repository of downloadable packages that you can use to customize it in a variety of ways.  (It's a Debian-based distro, and the package manager is ipkg.)  I turned it into an NFS server by installing unfs3, exported the disk, and it was instantly visible locally.&lt;br /&gt;&lt;br /&gt;On my netbook, I then installed an automounter, autofs, and -- ta-daa! -- now the disk's there &lt;a href="http://en.wikipedia.org/wiki/Antigonish_%28poem%29"&gt;whenever I look at it.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Space.  The final frontier.  [ Cue &lt;a href="http://www.youtube.com/watch?v=nHhePr0TKfc"&gt;Star Trek theme.&lt;/a&gt; ]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6588285774202178429?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6588285774202178429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6588285774202178429' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6588285774202178429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6588285774202178429'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/02/space-final-frontier.html' title='Space, The Final Frontier'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-641794906285046621</id><published>2010-02-16T06:28:00.001-07:00</published><updated>2010-02-16T06:29:49.402-07:00</updated><title type='text'>Where's My Jet Pack?</title><content type='html'>At some point, I'll outgrow the wonder of new technology, but I hadn't by this weekend.&lt;br /&gt;&lt;br /&gt;My bedside computer is a Dell mini-10 netbook.  I've had it a week.  Two gig of memory, 160 gig of hard disk, three pounds.  The 6-cell battery lasts for hours.  Whoof.&lt;br /&gt;&lt;br /&gt;I bought it, on-line, from Wal-Mart, who delivered it in three days.  Same week.  I installed three different OS's on it, and settled on Ubuntu 9.10 (Karmic Koala). &lt;br /&gt;&lt;br /&gt;Ubuntu is a lineal descendent of Unix, which I first installed on an IBM PC/XT, of which this Dell is, itself, a lineal descendent.  The XT had an Intel 8088 processor, 256Kb of memory, and a 10Mb hard disk with another 10Mb expansion chassis to give it enough space to host multiple users.  Those, and its cathode-ray-tube screen, took up a big chunk of a desk.&lt;br /&gt;&lt;br /&gt;A megabyte, for those who don't rememeber them, is a milli-gig.  A kilobyte is a milli-meg.  "You had ones *and* zeroes?"&lt;br /&gt;&lt;br /&gt;Kristina doubled the netbook's memory with a kit, also from Wal-Mart, helped by a call to a friendly Dell tech support guy, in Chennai, India.&lt;br /&gt;&lt;br /&gt;Let me just pause to say that again: a phone call to Chennai, India.  My mother's childhood phone number was 1. They had the first phone in Haynesville, Louisiana.  To call my grandmother, we talked to operators.  "I think Stella's down 't the beauty parlor.  I'll ring down there."&lt;br /&gt;&lt;br /&gt;This weekend, on my computer, I watched Spartacus, in bed.  I downloaded and read a Kindle book, bought on-line from Amazon.com, with "Kindle for PC."  I made a Skype video call to my sister, Jo, in Oregon.  I did a software release at work from my living room while I was arranging for a barbershop quartet, from the Boulder Timberliners, to come seranade Kristina for Valentine's Day, at a restaurant I took her to.&lt;br /&gt;&lt;br /&gt;I arranged it on my cell phone -- you know, the phone I carry in my pocket?  The one running Linux?  With the videocamera in it?  That I get email on?  That could give me turn-by-turn, voice directions to get to the restaurant?  Which it could do by knowing where I was from the signals it was getting from the GPS satellite, in outer space?&lt;br /&gt;&lt;br /&gt;My father helped open Vandenberg A.F.B., America's first operational missle base.  He had computers with big cabinets that held tape drives with 7" reels.  The computers and drives and disks took up big rooms and had their own air conditioning.  They had bugs, too.  We watched the first Atlas ICBMs launch, go astray, and then blow up.  Made for cool sunsets.&lt;br /&gt;&lt;br /&gt;Of course, we drove to the Valentine's Day dinner in a car.  When he was a kid, my father's little sister was run over and killed, in Brooklyn, by a horse cart.&lt;br /&gt;&lt;br /&gt;Time to get up and shower, so I can find out what new things I'll see today. &lt;br /&gt;&lt;br /&gt;I feel like Duck Dodgers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-641794906285046621?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/641794906285046621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=641794906285046621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/641794906285046621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/641794906285046621'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2010/02/wheres-my-jet-pack.html' title='Where&apos;s My Jet Pack?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-516177653088619794</id><published>2009-12-18T14:24:00.002-07:00</published><updated>2009-12-18T14:30:17.378-07:00</updated><title type='text'>Tar Wars</title><content type='html'>&lt;div&gt;Here's a little, galactic-history lesson.  When you finish it, you'll know both a new command and a portable way to copy directory hierarchies.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A long time ago, in a galaxy far, far away, there was a great struggle over which archiving tool the POSIX standard would choose: BSD's &lt;i&gt;tar&lt;/i&gt; or AT&amp;amp;T's &lt;i&gt;cpio&lt;/i&gt;.  Who would rule the Empire?  TAR2-D2 or 3Cpio?  This mouse-and-frog battle was dubbed &lt;i&gt;Tar Wars&lt;/i&gt;.  (Cue John Williams' score.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The winner was us.  AT&amp;amp;T's Glenn Fowler, with Joerg Schilling, designed and implemented &lt;i&gt;pax&lt;/i&gt; (Posix Archive eXchange), to supplant both.  &lt;i&gt;Pax&lt;/i&gt; would read and write either format, and is now on every POSIX-conforming system.  Better still, on mine it's 30% smaller than &lt;i&gt;tar&lt;/i&gt;, and less than a third the size of &lt;i&gt;cpio&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Peace through unity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A little-known-by-me feature of &lt;i&gt;pax&lt;/i&gt; is that it will even copy directory hierarchies.  Me, I use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cp -a&lt;/span&gt; to do this job, but that's a GNU-specific idiom.  Other versions of&lt;i&gt; cp&lt;/i&gt; may lack the&lt;i&gt; -a&lt;/i&gt; flag.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This portable command will copy olddir into newdir (newdir must exist), preserving ownerships and permissions:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;$ sudo pax -pewr olddir newdir&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Mnemonic: the copy is pure ("pewr").&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-516177653088619794?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/516177653088619794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=516177653088619794' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/516177653088619794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/516177653088619794'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/12/tar-wars.html' title='Tar Wars'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8388302767921645422</id><published>2009-12-09T09:28:00.003-07:00</published><updated>2009-12-09T09:46:07.637-07:00</updated><title type='text'>Octal NUL</title><content type='html'>&lt;div&gt;&lt;i&gt;"Well, here's another nice mess you've gotten me into."&lt;/i&gt; -- Oliver Hardy&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's disappointing, but not surprising, to see edge cases behave differently in different programs.  It is surprising when they're inconsistent within one program: &lt;b&gt;bash&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, the behaviors are standards-conforming and well-documented.  Still, watch this, keeping in mind that &lt;b&gt;printf&lt;/b&gt; and &lt;b&gt;echo&lt;/b&gt; are shell built-ins:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;# within single quotes, the shell doesn't expand metacharacters&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;echo 'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a   \   0   0   0   0   b  \n&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000010&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;# but echo -e interprets \n, \nn, \nnn, and \nnnn as octal characters&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;echo -e 'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a   \0   b  \n&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;# printf, however, only takes \n,\nn, and \nnn as octal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;printf 'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a  \0   0   b&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;# but $'...' is interpreted as a C string,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;# and in C, \0 terminates a string&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;echo -e $'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a  \n&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;In the last case, it's the shell interpreting the octal string before it even gets to echo.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Want proof?&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;cat &lt;&lt;&lt; 'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a   \   0   0   0   0   b  \n&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000010&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;cat &lt;&lt;&lt; $'a\0000b' | od -c&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000000   a  \n&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;0000002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Note also that much of this quirkiness only appears when you start using four-digit, octal representations and mess around with NUL (\0).  Try keeping all &lt;i&gt;those&lt;/i&gt; details in your head, bucko!  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Me, I can't.  Or won't.  Good thing it's all documented in the man page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;"A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines."&lt;/i&gt; -- Emerson&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hat Tip: I started looking at this after puzzling over a line in Hal Pomeranz's &lt;a href="http://blog.commandlinekungfu.com/2009/12/episode-72-that-special-time-of-year.html"&gt;latest Command-Line Kung Fu column.&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8388302767921645422?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8388302767921645422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8388302767921645422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8388302767921645422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8388302767921645422'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/12/octal-nul.html' title='Octal NUL'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3295143016661099312</id><published>2009-12-04T10:59:00.002-07:00</published><updated>2009-12-04T11:18:00.688-07:00</updated><title type='text'>Joinery</title><content type='html'>&lt;div&gt;The &lt;b&gt;join&lt;/b&gt; command has some useful options.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hal Pomeranz has a nice example of using join to combine the output of two different commands  in &lt;a href="http://blog.commandlinekungfu.com/2009/12/episode-71-joining-up.html"&gt;this week's Command-Line Kung Fu column&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After some discussion, he ends up with this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px; border-collapse: collapse; "&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; $&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; join -1 1 -2 2 &lt;(openssl sha1 * | sed -r 's/SHA1\((.*)\)= (.*)/\1 \2/') &lt;(wc -c *) \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;           | awk '{print $2 " " $1 " " $3}'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-size: 16px;"&gt;One reason he uses &lt;b&gt;openssl&lt;/b&gt; is to help teach that in process substitution, the contents of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;( ) &lt;/span&gt;can be pipeline.  If you relax his didactic requirement, &lt;b&gt;join&lt;/b&gt;'s options let you do the job with a lot less typing.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-size: 16px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-size: 16px;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px; border-collapse: collapse; "&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;b&gt; $&lt;/b&gt; join -j2 -o 1.1,0,2.1 &lt;(sha1sum *) &lt;(wc -c *)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-size: 16px;"&gt;&lt;span class="Apple-style-span"   style="font-family:'courier new';font-size:100%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-family: Georgia, serif; font-size: 16px; "&gt;Note that &lt;b&gt;sha1sum&lt;/b&gt; has the same output format as &lt;b&gt;wc -c&lt;/b&gt;, which makes the join easier.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-family: Georgia, serif; font-size: 16px; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-family: Georgia, serif; font-size: 16px; "&gt;Non-Linux boxes might not have &lt;a href="http://en.wikipedia.org/wiki/Sha1sum"&gt;sha1sum&lt;/a&gt;, but if I didn't have it, I'd see if I had &lt;a href="http://en.wikipedia.org/wiki/Md5sum"&gt;md5sum&lt;/a&gt;, which has the same output format.  Their Wikipedia entries say these commands are widely available on lots of non-Linux OSs.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; font-size: 16px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3295143016661099312?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3295143016661099312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3295143016661099312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3295143016661099312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3295143016661099312'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/12/joinery.html' title='Joinery'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3399828222471629559</id><published>2009-11-24T08:38:00.002-07:00</published><updated>2009-11-24T09:08:53.036-07:00</updated><title type='text'>My Phone Starts Giving Me Things I Never Had</title><content type='html'>This morning, my Android phone used &lt;a href="http://www.readwriteweb.com/archives/google_brings_its_turn-by-turn_navigation_app_to_o.php"&gt;Google's Turn-by-Turn navigation&lt;/a&gt; to coach me into work.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd wanted to play with voice navigation every since I got my Android phone, a few months ago, but all the available apps were pay services, so I waited.   A few weeks ago, Google announced they'd provide it with Android 2.0, but my &lt;a href="http://en.wikipedia.org/wiki/MyTouch"&gt;HTC Magic&lt;/a&gt; (T-Mobile myTouch) was still running 1.6.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Picture me, tapping my toe impatiently.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yesterday, they back-ported the functionality to 1.6 and put it in the app store, and I grabbed it.  This morning, I put in my destination, sat it in my lap, and set out.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hearing it tell me directions as I drive is startling.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;In one-quarter mile, turn right onto on-ramp, Highway 157, North.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Turn right onto on-ramp, Highway 157, North.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My father's &lt;a href="http://www.arctos.com/dial/"&gt;Bell model 500&lt;/a&gt; sits on my desk.  When I got my first cell phone, I couldn't believe I was carrying a telephone in my pocket.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I shut off my land-line service, and jumped in with both feet.  I quickly discovered I also had my watch, my alarm clock, and my pager in my pocket.  My old pager was long gone, but I donated my alarm clock to the Salvation Army.  My watch, a gift from an old girlfriend, went in a drawer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The myTouch put my email reader in my pocket, too.  To underscore this, Qwest, my DSL provider, had a service outage a week or so after I got it.  No computer, but I could still read my email.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Having both persuaded me that I should take my Google Contacts seriously, so it now really does store all my email addresses &lt;i&gt;and&lt;/i&gt; my phone numbers.   The app that stores my library-card, my grocery-card, and other bar codes was also useful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But all that was extensions to things I already had.  The bubble level app was cute, but not important.  Google Sky Maps was very, very cute, but not important.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other stuff?  Nice, if not quite ready for prime-time.  Browser?  Slooooow.  Calendar?  Too small to be useful.  eBook reader?  I'll let you know once there's a Kindle app.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Amazon Marketplace showed me the future of retail, but it's still mostly an "Oooh!"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The turn-by-turn directions though?  Important.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have a notebook full of maps I've printed to get places -- my own, personal atlas.  No more.  From now on, my phone can just tell me how to get where I want to go.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The phone in my pocket has replaced the GPS that I never owned.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3399828222471629559?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3399828222471629559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3399828222471629559' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3399828222471629559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3399828222471629559'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/11/my-phone-starts-giving-me-things-i.html' title='My Phone Starts Giving Me Things I Never Had'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4169676845918953335</id><published>2009-11-17T12:46:00.002-07:00</published><updated>2009-11-17T12:50:15.981-07:00</updated><title type='text'>Translate-As-You-Type</title><content type='html'>I'm interested in translation tools.  Google Translate now does &lt;a href="http://www.youtube.com/watch?v=FijOWfO3Frk&amp;amp;feature=player_embedded"&gt;translate-as-you-type&lt;/a&gt;, instead of waiting for  you to finish typing and submitting the result.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's claimed that it will also do phonetic translation of non-Roman scripts, but I'm not seeing that with Yiddish.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4169676845918953335?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4169676845918953335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4169676845918953335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4169676845918953335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4169676845918953335'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/11/translate-as-you-type.html' title='Translate-As-You-Type'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7182142374998654498</id><published>2009-11-12T13:39:00.002-07:00</published><updated>2009-11-12T14:19:43.782-07:00</updated><title type='text'>The "help" Command, And Other Aids</title><content type='html'>In &lt;a href="http://blog.commandlinekungfu.com/2009/11/episode-68-help-fu.html"&gt;his latest Command-Line Kung Fu post&lt;/a&gt;, Hal Pomeranz talks about places to get help on Unix systems and their kin.  (Technically, that's "their latest post," but his co-conspirators write about Microsoft stuff, which I don't care about.)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hal concentrates on &lt;b&gt;man(1)&lt;/b&gt;, &lt;b&gt;info(1)&lt;/b&gt;, and &lt;b&gt;apropos(1), &lt;/b&gt;and the &lt;b&gt;--help&lt;/b&gt; flag.&lt;b&gt;  &lt;/b&gt;Good places to start, but there are other things worth mentioning.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I will.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;locate(1) &lt;/b&gt;is quite handy.  I often find myself hunting for commands that don't have man entries of any kind, and are installed someplace bizarre.  Once I find them, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/path/to/command --help&lt;/span&gt; often tells me enough.  If not, but they're in some special directory, there's sometimes a README or examples that do the trick.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another frequent stop is the web.  If &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command --help&lt;/span&gt; doesn't tell me what I want to know, the web's more likely to have a man page than my machine is.  I'll now usually go there first.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If it's not an executable?  How about&lt;b&gt; type&lt;/b&gt;?&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;type ls&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ls is aliased to `ls --color=auto'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;type cdjob&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cdjob is a function&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;cdjob () &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;{ &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    local d;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    : ${1:?"usage $FUNCNAME %N"};&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    d=$(jobs $1 | perl -lane 'print "cd $1" if m/.*\(wd: (.*)\).*/');&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    test "$d" &amp;amp;&amp;amp; eval $d&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;And what's &lt;b&gt;type&lt;/b&gt;?&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;type type&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;type is a shell builtin&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;For information about&lt;b&gt; type&lt;/b&gt;, do we have to pour through the zillion-page, bash man page?  On-line?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nope.  Watch:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;man type&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;No manual entry for type&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;type type&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;type is a shell builtin&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;help type&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;type: type [-afptP] name [name ...]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Display information about command type.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    For each NAME, indicate how it would be interpreted if used as a&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    command name.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Options:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      -a&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;display all locations containing an executable named NAME;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;includes aliases, builtins, and functions, if and only if&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;the `-p' option is not also used&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      -f&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;suppress shell function lookup&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      -P&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;force a PATH search for each NAME, even if it is an alias,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;builtin, or function, and returns the name of the disk file&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;that would be executed&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      -p&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;returns either the name of the disk file that would be executed,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;or nothing if `type -t NAME' would not return `file'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      -t&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;output a single word which is one of `alias', `keyword',&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;`function', `builtin', `file' or `', if NAME is an alias, shell&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;reserved word, shell function, shell builtin, disk file, or not&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;found, respectively&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Arguments:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;      NAME&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Command name to be interpreted.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Exit Status:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Returns success if all of the NAMEs are found; fails if any are not found.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;typeset: typeset [-aAfFilrtux] [-p] name[=value] ...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Set variable values and attributes.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;    Obsolete.  See `help declare'.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Yes, there's really a &lt;b&gt;help&lt;/b&gt; command.  It gives help about shell builtins.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If I don't even have the command?  (If, for example, it's part of someone else's script I've pulled down from somewhere?)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what I get out of bash when I invoke als(1) on my Ubuntu box.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small; "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;als&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;The program 'als' is currently not installed.  You can install it by typing:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;sudo apt-get install atool&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;als: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Not help with the command, okay, but help getting it so I can then get help with it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What would you pay?  But wait.  There's more.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If I guess at a command but mis-type it?&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ &lt;b&gt;las&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;No command 'las' found, did you mean:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'als' from package 'atool' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'ls' from package 'coreutils' (main)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'lfs' from package 'lustre-utils' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'lms' from package 'lms' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'les' from package 'atm-tools' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'last' from package 'sysvinit-utils' (main)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'laps' from package 'epix1' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'lvs' from package 'lvm2' (main)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'cas' from package 'amule-adunanza-utils' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'cas' from package 'amule-utils' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'as' from package 'binutils' (main)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'ras' from package 'ras' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'kas' from package 'openafs-kpasswd' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Command 'lat' from package 'lat' (universe)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;las: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;I think that's nice.  And I can use&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; apt-cache show&lt;/span&gt; to tell me what each package is.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7182142374998654498?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7182142374998654498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7182142374998654498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7182142374998654498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7182142374998654498'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/11/help-command-and-other-aids.html' title='The &quot;help&quot; Command, And Other Aids'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3243487774679056192</id><published>2009-11-11T06:03:00.005-07:00</published><updated>2009-11-11T09:20:44.341-07:00</updated><title type='text'>Valour-IT Fundraiser</title><content type='html'>&lt;img style="visibility: hidden; width: 0px; height: 0px;" src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bHQ9MTI1Nzk*NDE1MTA*MyZwdD*xMjU3OTQ*NjMwMjg*JnA9ODk1ODQxJmQ9Jm49YmxvZ2dlciZnPTEmbz*2MWY2YWRhNjM2NzI*OTY3OTNiNjQ4MWE2OTI1YzJkOSZvZj*w.gif" border="0" height="0" width="0" /&gt;&lt;div&gt;&lt;a href="http://soldiersangels.org/index.php?page=project-valour-it"&gt;Semper Fi&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;object id="gauge" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" height="240" width="150" align=""&gt;&lt;param value="http://soldiersangels.org/gauge.swf?stage_width=150&amp;amp;stage_height=240&amp;amp;xml_source=http://soldiersangels.org/thermsmtall.php%3Ftime%3D0.26440600+1128349620" name="movie"&gt;&lt;param value="high" name="quality"&gt;&lt;param value="" name="bgcolor"&gt;&lt;embed pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" name="gauge" bgcolor="" quality="high" src="http://soldiersangels.org/gauge.swf?stage_width=150&amp;amp;stage_height=240&amp;amp;xml_source=http://soldiersangels.org/thermsmtall.php%3Ftime%3D0.26440600+1128349620" height="240" width="150" align=""&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;If you're geeky enough to be reading this blog, you're geeky enough to appreciate the idea of a project that provides computers to wounded vets.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3243487774679056192?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3243487774679056192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3243487774679056192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3243487774679056192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3243487774679056192'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/11/valour-it-fundraiser.html' title='Valour-IT Fundraiser'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1938765848964892449</id><published>2009-11-09T10:17:00.002-07:00</published><updated>2009-11-09T10:31:53.384-07:00</updated><title type='text'>Checking Scripts for Syntax Errors</title><content type='html'>If I'm maintaining a lot of shell scripts in a directory, I usually want to syntax-check them before I check them in.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The&lt;b&gt; file(1)&lt;/b&gt; command will mark most of them as shell scripts.  The rest are, typically, libraries of shell functions that I name with .sh suffixes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All shell scripts that file can find:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$ file * | awk -F: '/shell/{print $1}'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;plus the libraries&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$ file * | awk -F: '/shell/{print $1}'  ; echo *.sh&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;now syntax check them&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; $ for i in $(file * | awk -F: '/shell/{print $1}' ; echo *.sh); do bash -n $i || echo $i fails; done&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Just with command-line recall and editing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1938765848964892449?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1938765848964892449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1938765848964892449' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1938765848964892449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1938765848964892449'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/11/checking-scripts-for-syntax-errors.html' title='Checking Scripts for Syntax Errors'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7744074773892061687</id><published>2009-10-23T11:15:00.004-06:00</published><updated>2009-10-23T11:39:20.665-06:00</updated><title type='text'>Google's Bulgarian Picture Dictionary</title><content type='html'>&lt;div&gt;Language translation is serious business, but &lt;a href="http://alumnus.caltech.edu/~copeland/work/babel.html"&gt;playing with automatic translation tools is just fun.&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I use &lt;a href="http://translate.google.com/?hl=en#"&gt;Google Translate&lt;/a&gt; a lot, along with their &lt;a href="http://googletalk.blogspot.com/2008/06/more-translation-bots.html"&gt;translation bots&lt;/a&gt;.  I've played with the &lt;a href="http://www.google.com/ig/directory?type=gadgets&amp;amp;url=wordmonkey.info/word.xml"&gt;Word Monkey gadget&lt;/a&gt; for iGoogle.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've even built spreadsheets to do translation with Google's &lt;a href="http://googledocs.blogspot.com/2009/10/translation-functions-in-spreadsheets.html"&gt;spreadsheet functions&lt;/a&gt;; I'd bet even beginning corpus-linguistics students could do some cool experiments with these.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Today, my pal, Kevin Cohen, put up this Google Chat status message: &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style=" border-collapse: collapse; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:arial, sans-serif;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;i&gt;&lt;blockquote&gt;My favorite Bulgarian word is хляб.  What's yours?&lt;/blockquote&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I put it into Google Image Search, to see what would happen, &lt;a href="http://images.google.com/images?sourceid=chrome&amp;amp;q=%D1%85%D0%BB%D1%8F%D0%B1&amp;amp;um=1&amp;amp;ie=UTF-8&amp;amp;sa=N&amp;amp;hl=en&amp;amp;tab=wi"&gt;and got this.&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think I can guess what &lt;span class="Apple-style-span"   style="  border-collapse: collapse; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:arial, sans-serif;font-size:medium;"&gt;&lt;i&gt;хляб &lt;span class="Apple-style-span"   style="border-collapse: separate;  font-style: normal; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px;  font-family:Georgia, serif;font-size:16px;"&gt;means.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7744074773892061687?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7744074773892061687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7744074773892061687' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7744074773892061687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7744074773892061687'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/10/googlepicture-dictionary.html' title='Google&apos;s Bulgarian Picture Dictionary'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5577820924023284989</id><published>2009-10-22T09:11:00.004-06:00</published><updated>2009-10-22T09:29:17.598-06:00</updated><title type='text'>A GUI Replacement for sshfs</title><content type='html'>I've been using &lt;b&gt;sshfs&lt;/b&gt; to remote-mount my home machine onto my work machine.  Now, I've stumbled on an alternative that feels better integrated with my Gnome desktop: &lt;b&gt;gvfs&lt;/b&gt; (gnome virtual file system) in Nautilus.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The short version:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ nautilus sftp://test.com&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;brings up a file-browser window with test.com in it, which I can then browse and click around in.  Also, test.com is mounted as &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;~/.gvfs/sftp on test.com/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yes, it has all those blanks.  Oh well.  You can still get to it on the command line and in scripts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you already have a file-browser window up, just use the URI &lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp://test.com&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you need to go in through a different port from 22, say 666, you'll first need to add a pair of lines to your &lt;b&gt;.ssh/config&lt;/b&gt; file that look like like this:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Host test.com&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;   Port 666&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;You can test whether they work or not by using &lt;b&gt;ssh&lt;/b&gt; by hand.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;$ ssh test.com&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5577820924023284989?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5577820924023284989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5577820924023284989' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5577820924023284989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5577820924023284989'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/10/gui-replacement-for-sshfs.html' title='A GUI Replacement for sshfs'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1470559175221785205</id><published>2009-10-19T06:15:00.002-06:00</published><updated>2009-10-19T06:41:03.638-06:00</updated><title type='text'>Bugs</title><content type='html'>All programs have bugs.  A "mature program" is a program with more obscure bugs.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I first started programming, I was convinced that half my programs had uncovered bugs in the compiler.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;They never were.  "Oh.  '&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Missing semicolon on line 71&lt;/span&gt;' goes away if I put a semicolon in."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because compilers are more mature than my code, the probability is higher that bugs are mine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When a shell script I wrote last week failed, I began carving it down to see what I'd done wrong.  This is usually fast and easy--chop pieces out of the script until you can get a very simplified statement that doesn't do what I thought it should do, then go back to read the man page to see why.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the simplified test case I ended up with:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;set -x                      # this is required&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;PS4='$(true)$ '  # must be a command  in the prompt, but any command will do&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;false || A=3         # first expression must fail,  second must be a variable assignment&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;echo $?                # Should be 0, but isn't.  Odd.&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Much to my surprise, it's bug in bash, both versions 3 and 4.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Obscure?  Sure.  You have to have a lot of special things going on, and the symptom is a bad exit code.  I reported it and used a workaround (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if .. fi&lt;/span&gt; instead of the shortcut logical or).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Always remember: every program has bugs.  They're only &lt;i&gt;almost&lt;/i&gt; always yours.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1470559175221785205?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1470559175221785205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1470559175221785205' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1470559175221785205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1470559175221785205'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/10/bugs.html' title='Bugs'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3317363674543136902</id><published>2009-10-03T08:23:00.001-06:00</published><updated>2009-10-03T14:48:46.265-06:00</updated><title type='text'>Hello, World Again</title><content type='html'>&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;I'd like to try saying "We sometimes take the shell too much for granted," another way.&lt;br /&gt;&lt;br /&gt;Advice from masters is often good advice.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's my favorite chunk of the greatest of all programming texts, Kernighan and Ritchie's &lt;i&gt;The C Programming Language&lt;/i&gt; (Prentice-Hall, 1978).&lt;/div&gt;&lt;div&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;1.1 Getting Started &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;The only way to learn a new programming language is by writing programs in it. The first program to write is the same for all languages: &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;Print the words &lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;    &lt;/span&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;hello, world &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;This is the basic hurdle; to leap over it you have to be able to create the program text somewhere, compile it successfully, load it, run it, and find out where your output went. With these mechanical details mastered, everything else is comparatively easy. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;In C, the program to print "hello, world" is &lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;#include &lt;stdio.h&gt;&lt;/stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;main()&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;printf("hello, world\n");&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;Just how to run this program depends on the system you are using. As a specific example, on the UNIX operating system you must create the program in a file whose name ends in ".c", such as &lt;i&gt;hello.c&lt;/i&gt;, then compile it with the command &lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span style="font-size:85%;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"&gt;cc hello.c &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;If you haven't botched anything, such as omitting a character or misspelling something, the compilation will proceed silently, and make an executable file called a.out. Running that by the command &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;i&gt;&lt;span class="Apple-style-span"&gt;a.out &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;will produce &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style=";font-family:'courier new';font-size:85%;"  &gt;&lt;span class="Apple-style-span"&gt;hello, world&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;as its output.  On other systems, the rules will be different; check with a local expert.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;Exercise 1-1.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:85%;"&gt; Run this program on your system.  Experiment with leaving out parts of the program, to see what error messages you get.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fine advice.  Let's do exercise 1-1, but in the shell.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Run the analogous program?  Okay.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;echo hello, world&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;hello, world&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Leave out parts?  Let's leave out a part of the string.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;echo hell, world&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;hell, world&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Or part of the command.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;eco hello, world&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;bash: eco: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;How about whitespace?  It's okay to leave it out of the string,&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;echo hello,world&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;hello,world&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;but you need some between a command and its arguments.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;echohello, world&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;bash: echohello,: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;My point: Programing in the shell is quick and easy.  You just type.  There's no editing, no special naming, no compiling, no &lt;i&gt;a.out&lt;/i&gt; file, no loading and running, no need to consult a local expert.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you type something incomprehensible, the shell gives you an error message and lets you try again, right away.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3317363674543136902?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3317363674543136902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3317363674543136902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3317363674543136902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3317363674543136902'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/10/advice-from-masters-is-often-good.html' title='Hello, World Again'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2837949861088891761</id><published>2009-10-01T08:31:00.003-06:00</published><updated>2009-10-01T08:44:57.755-06:00</updated><title type='text'>The Shell Enters a Beauty Contest</title><content type='html'>&lt;div&gt;I'd never tout the shell as the be-all and end-all of programming languages, but it gets less attention and respect than it deserves.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example, folks will remark, casually, that shell syntax is ugly.  Who would design a language that doesn't even let you put spaces around the '=' in an assignment?&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;x=3&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;y = 3&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;-bash: y: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;z= 5&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;-bash: 5: command not found&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Eeew.  Real programs are in C.  Or Perl.  Or Python.  Or Haskell.  Or ...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yep, the shell syntax has some design flaws all right.  But let's run another beauty contest.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, contestant #1:&lt;br /&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span style="border: 1px solid #FF0000"&gt;#&lt;/span&gt;include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;&lt;span style="border: 1px solid #FF0000"&gt;#&lt;/span&gt;include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#B00040;"&gt;int&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;main&lt;/span&gt;(&lt;span style=" font-weight: bold;color:#008000;"&gt;void&lt;/span&gt;)&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#B00040;"&gt;int&lt;/span&gt;     fd[&lt;span style="color:#666666;"&gt;2&lt;/span&gt;], nbytes;&lt;br /&gt;pid_t   pid;&lt;br /&gt;&lt;br /&gt;pipe(fd);&lt;br /&gt;&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;if&lt;/span&gt; ((pid = fork()) == &lt;span style="color:#666666;"&gt;0&lt;/span&gt;) &lt;span style=" font-weight: bold;color:#008000;"&gt;{&lt;/span&gt;&lt;br /&gt;  dup2(fd[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;], &lt;span style="color:#666666;"&gt;0&lt;/span&gt;);&lt;br /&gt;  close(fd[&lt;span style="color:#666666;"&gt;1&lt;/span&gt;]);&lt;br /&gt;  execlp(&lt;span style="color:#BA2121;"&gt;"/bin/grep"&lt;/span&gt;, &lt;span style="color:#BA2121;"&gt;"/bin/grep"&lt;/span&gt;, &lt;span style="color:#BA2121;"&gt;"^z"&lt;/span&gt;, NULL);&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;}&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008000;"&gt;else&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008000;"&gt;{&lt;/span&gt;&lt;br /&gt;  dup2(fd[&lt;span style="color:#666666;"&gt;1&lt;/span&gt;], &lt;span style="color:#666666;"&gt;1&lt;/span&gt;);&lt;br /&gt;  close(fd[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;]);&lt;br /&gt;  execlp(&lt;span style="color:#BA2121;"&gt;"/bin/ls"&lt;/span&gt;, &lt;span style="color:#BA2121;"&gt;"/bin/ls"&lt;/span&gt;, &lt;span style="color:#BA2121;"&gt;"-1"&lt;/span&gt;, &lt;span style="color:#BA2121;"&gt;"/bin"&lt;/span&gt;, NULL);&lt;br /&gt;  wait(NULL);&lt;br /&gt;  exit(&lt;span style="color:#666666;"&gt;0&lt;/span&gt;);&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;return&lt;/span&gt;(&lt;span style="color:#666666;"&gt;0&lt;/span&gt;);&lt;br /&gt;&lt;span style=" font-weight: bold;color:#008000;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-family:Georgia, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Next, contestant #2:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;ls /bin | grep ^z&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;And contestant #1 doesn't even have normal error checking, which would make it much longer, uglier, and hard-to-follow.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Programmers get so used to the shell that they focus on its flaws, but take its virtues for granted.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;i&gt;Don't it always seem to go that you don't know what you've got till it's gone? -- Joni Mitchell&lt;/i&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;What tastes of paradise does the shell offer besides pipes?  I/O redirection. Ease of process creation.  Multi-process programming.  Parallelism.  Command-line editing.  For that matter, the entire idea of a CLI, a "command-line interface."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once I start listing things, it's hard to stop.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All this in a language you can use in scripts, or just by doing nothing harder than typing at a prompt.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2837949861088891761?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2837949861088891761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2837949861088891761' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2837949861088891761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2837949861088891761'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/10/id-never-tout-shell-as-be-all-and-end.html' title='The Shell Enters a Beauty Contest'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4304808873268375190</id><published>2009-09-30T06:54:00.004-06:00</published><updated>2009-09-30T07:20:39.589-06:00</updated><title type='text'>Grobycs: Cyborgs in Reverse</title><content type='html'>We've read about &lt;a href="http://en.wikipedia.org/wiki/Cyborg"&gt;cyborgs,&lt;/a&gt; computer-enhanced humans, for decades.  Misdirection?  We should have been thinking about &lt;span style="font-weight: bold; font-style: italic;"&gt;grobycs&lt;/span&gt;: human-enhanced computers.  Cyborgs in reverse.&lt;br /&gt;&lt;br /&gt;Consider these:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.techcrunch.com/2009/09/29/facebook-spreads-its-crowdsourced-translations-across-the-web-and-the-world/"&gt;Facebook offers crowdsourced translations &lt;/a&gt;as an alternative to &lt;a href="http://translate.google.com/translate_t#"&gt;Google Translate&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://googleblog.blogspot.com/2009/08/bright-side-of-sitting-in-traffic.html"&gt;Google gives me real-time traffic data&lt;/a&gt; collected from folks using their GPS-enabled smartphones to look at maps: in fact, at traffic data.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/feature.html?ie=UTF8&amp;amp;docId=1000291661"&gt;I can send Amazon a barcode scan&lt;/a&gt; , using my phone's camera.  If they don't stock the item, they let me send a picture, from the same camera, and nearly instantly, offer me &lt;span style="font-style: italic;"&gt;similar&lt;/span&gt; products.  How?  &lt;a href="https://www.mturk.com/mturk/welcome"&gt;Amazon Mechanical Turk&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.schneier.com/blog/archives/2007/11/spammers_using.html"&gt;Spammers break into captcha-guarded sites &lt;/a&gt;by running a porn site.  Every time they hit a captcha, they pass it through to the porn-site registration side.  The next human who visits the site decodes it.&lt;/li&gt;&lt;/ul&gt;All use people as a piece of a collection of software.  They're cyborgs in reverse: Grobycs.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Lee_Majors#The_Six_Million_Dollar_Man"&gt;The Six-Million-Dollar Man&lt;/a&gt; wanted her:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/en/8/89/Farrah_Fawcett_iconic_pinup_1976.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 194px; height: 300px;" src="http://upload.wikimedia.org/wikipedia/en/8/89/Farrah_Fawcett_iconic_pinup_1976.jpg" alt="" border="0" /&gt;&lt;/a&gt;What do you think grobycs will lust after?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4304808873268375190?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4304808873268375190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4304808873268375190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4304808873268375190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4304808873268375190'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/grobycs-cyborgs-in-reverse.html' title='Grobycs: Cyborgs in Reverse'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1635626728240841850</id><published>2009-09-23T18:40:00.002-06:00</published><updated>2009-09-23T18:49:57.177-06:00</updated><title type='text'>Variables Without Values</title><content type='html'>&lt;div&gt;Often, you only want to do something if a variable is unset.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I see code to handle such conditions that looks like this.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;if [ "A$foo" = "A" ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;take-some-action&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;It's either old code or code by old programmers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The test is how you used to have to ask whether a variable was empty.  Here's a newer idiom.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;[ "$foo" ] || take-some-action&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;test&lt;/span&gt; operator, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;[ ]&lt;/span&gt;, comes in many flavors.  For example &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;[ -d $X ] &lt;/b&gt;&lt;/span&gt;asks "Does &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$X&lt;/span&gt; name a directory?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; In its simplest form, though,&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;[ $X ]&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;asks "Is &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$X&lt;/span&gt; empty?"  The test returns true if &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$X&lt;/span&gt; has something in it, false if it doesn't. The new code does the same thing as the old, but it's shorter and, arguably, easier to read.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But why not this?&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;[ $foo ] || take-some-action&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Ah.  Because if &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;foo='1 2 3'&lt;/span&gt;, then test complains that you've given it too many arguments.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;[: 2: unary operator expected&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;One more trick: what if you're running with "set -u", which complains whenever it stumbles on an unset variable, with complaints like this&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;line 3: foo: unbound variable&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Write the test like this:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;["${foo-}" ] || take some action&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;If &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$foo&lt;/span&gt; is unset, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${foo-}&lt;/span&gt; has a null value.  "Null" is a value; "unset" really means the variable was never set.  So, with &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;"${foo-}"&lt;/span&gt; the shell won't complain about an unset variable, but the test will still fail.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is still shorter than the example we started with, but it's only more readable once you can read the idiom &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${foo-}&lt;/span&gt; without stumbling.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the other hand, the first example will also choke if &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$foo&lt;/span&gt; is unset, so it would also have to be modified like this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;if [ "A${foo-}" = "A" ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;take-some-action&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1635626728240841850?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1635626728240841850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1635626728240841850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1635626728240841850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1635626728240841850'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/variables-without-values.html' title='Variables Without Values'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1346753083524858271</id><published>2009-09-23T12:51:00.004-06:00</published><updated>2009-09-23T13:47:42.540-06:00</updated><title type='text'>More Include Guards</title><content type='html'>&lt;a href="http://seejeffrun.blogspot.com/2009/08/include-guards-in-sourced-files.html"&gt;I've already written&lt;/a&gt; about how to make include guards for "shell libraries" (files full of shell functions or variables to be sourced).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is the basic form of the statement, which requires tailoring for each library:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;if [ ${_gripe_version:-0} -gt 0 ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;return 0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;_gripe_version=1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Here's a more generic statement that you can put at the top of a file to achieve the same goal:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;[ "${_libs/${BASH_SOURCE[0]}}" = "${_libs=}" ] ||&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  return 0 &amp;amp;&amp;amp; _libs+=" ${BASH_SOURCE[0]}"&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;A dramatic reading of this off-putting code is left as an exercise to the reader.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It has the added attraction that you can, at any point, find out which libraries you've already sourced with &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;echo $_libs&lt;/b&gt;&lt;/span&gt; .&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It has the added detraction that you'll have to cut-and-paste it.  There's no way you'll ever keep it in your head and type it correctly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As a good test, first try this infinite recursion without include guards. (You'll have to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;^C&lt;/b&gt;&lt;/span&gt; out quickly, or you'll get stuck in a source-a-thon.)  &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ echo 'source foo.sh' &gt; foo.sh&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ chmod +x foo.sh&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$ ./foo.sh  # don't wait long to ^C&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Next, edit &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;foo.sh&lt;/b&gt;&lt;/span&gt; to add an include guard at the top and re-run it.  This time, it will return immediately, without help.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1346753083524858271?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1346753083524858271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1346753083524858271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1346753083524858271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1346753083524858271'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/more-include-guards.html' title='More Include Guards'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7120388697350144303</id><published>2009-09-18T15:04:00.003-06:00</published><updated>2009-09-18T15:32:32.622-06:00</updated><title type='text'>Simplifying Loopy Code</title><content type='html'>&lt;div&gt;&lt;i&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;The determined Real Programmer can write FORTRAN programs in any language.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;-- Ed Post, &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Real_Programmers_Don't_Use_Pascal"&gt;Real Programmers Don't Use PASCAL.&lt;/a&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;I just read through a friend's shell script.  He doesn't program in the shell much, but he's a superb C programmer, so his script has loops that look like this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;file[0]=foo&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;file[1]=bar&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;file[2]=mumble&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;suffix[0]=.c&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;suffix[1]=.h&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;suffix[2]=.txt&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;nfiles=${#file[@]}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;nsuffixes=${#suffix[@]}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;i=0while [ $i -lt $nfiles ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;j=0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;while [ $j -lt $nsuffixes ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;process ${file[$i]}${suffix[$j]}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;(( j = j + 1 ))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;(( i = i + 1 ))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Yep.  That'll work.  But this will, too.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;for filename in {foo,bar,mumble}.{c,h,txt}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;process $filename&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Bash sees filenames as strings, and most shell commands accept space-separated lists of filenames.   The shell handles anything that expands to a list of filenames, like globs or brace expansions, with real ease.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Use the Shell, Luke.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7120388697350144303?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7120388697350144303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7120388697350144303' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7120388697350144303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7120388697350144303'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/simplifying-loopy-code.html' title='Simplifying Loopy Code'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-770561545780852748</id><published>2009-09-16T08:36:00.003-06:00</published><updated>2009-09-16T08:45:43.378-06:00</updated><title type='text'>Call Me Now</title><content type='html'>Click on the Google &lt;span style="font-family: lucida grande; font-weight: bold; font-style: italic;"&gt;Call Me&lt;/span&gt; button, below, fill in your own name and phone number, and then click &lt;span style="font-family:lucida grande;"&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Connect&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You'll be connected to me immediately.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object type="application/x-shockwave-flash" data="https://clients4.google.com/voice/embed/webCallButton" width="230" height="85"&gt;&lt;br /&gt;&lt;param name="movie" value="https://clients4.google.com/voice/embed/webCallButton"&gt;&lt;param name="wmode" value="transparent"&gt;&lt;param name="FlashVars" value="id=4cc6926fbc618eb8528271d324d3e1c68eea4d73&amp;amp;style=0"&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-770561545780852748?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/770561545780852748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=770561545780852748' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/770561545780852748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/770561545780852748'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/call-me-now.html' title='Call Me Now'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1843624187326283527</id><published>2009-09-05T09:58:00.003-06:00</published><updated>2009-09-05T11:26:36.980-06:00</updated><title type='text'>But *How* Random Is It?</title><content type='html'>&lt;div&gt;Folks use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/dev/urandom&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$RANDOM&lt;/span&gt; to generate uniformly-distributed random numbers. Are they random?  Yes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's test.  Here's how.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Surprise!  The easiest way to start is to ask a more general question: Suppose you have a couple of sets of numbers.  Are they from the same distribution?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example, if you have a couple of batches of 10,000, 8-digit numbers, from the two different distributions, are they really spread out from 0 to 9999 the same way, or do they have clumps in different places?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are ways to attack this, even if you don't know (or care) what the original distribution was. Here's a step-by-step walkthrough:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Sort them together, smallest to biggest, coloring the first set red and the second, green.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Put your finger on the middle of a line--zero on the number line--and begin reading off colors.  If the number's red, move your finger left.  If it's green, move it right.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;See how far away from the origin you wander.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Half the numbers are red, half green, so you'll end up back where you started.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How far away might you get along the way?  Depends on the distribution of the reds and greens.  If all the reds are smaller than all the greens, you'll go left to ten thousand, then turn around and come right back.  If they're all bigger, then you'll get ten thousand away to the right before you snap back like a yo-yo.  And except for these cases, you won't go as far before you return.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If the numbers are from the same distribution, then whether they're red or green is a coin-toss.   T&lt;i&gt;he distance I expect to get from the the origin goes up as the square-root of the size of my collections.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;(That's on average -- any single pair of batches could end up almost anywhere.  &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; "... &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;the 'one chance in a million' will undoubtedly occur, with no less and no more than its appropriate frequency, however surprised we may be ...."&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'Comic Sans MS';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; --&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:Georgia, serif;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; &lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;a href="http://en.wikipedia.org/wiki/Ronald_Fisher"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;R. A. Fisher&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are lots of ways to get this result: &lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Binomial_distribution#Variance"&gt;from the standard deviation of a binomial with p=0.5&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test#Two-sample_Kolmogorov.E2.80.93Smirnov_test"&gt;from a two-sample Kolmogorov-Smirnov statistic with equal sample sizes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;from looking at it as Brownian motion, using the root-mean-square (RMS) argument attributed to Einstein, in&lt;a href="http://www.amazon.com/Feynman-Lectures-Physics-set-Set/dp/0201021153"&gt; Feynman, volume 1, chapter 6&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;All roads lead to Rome.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;b&gt;Note&lt;/b&gt;: nothing I've said, so far, depends on the numbers being random--this just tests whether the red and green  numbers come from the same distribution.  In what follows, though, I'm going to ask whether batches spit out by random-number generators are uniformly-distributed.&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Let's write code.  And, since all code roads lead to Rome, too, I'll do it in the shell.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Start with two, random-number-generators, &lt;b&gt;R1&lt;/b&gt; and &lt;b&gt;R2  &lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;that generate some fixed-size batch of random numbers.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Check that each one spits out the same sized batch.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$ R1 | wc -l ; R2 | wc -l&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Mark each output with a second field, saying which way each number will move my finger&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ R1 | awk '$2=1'; R2 | awk '$2=-1'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Sort the two together, on the first column&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ sort -n &lt;(R1 | awk '$2=1') &lt;(R2 | awk '$2=-1')&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Run through the output, keeping track, at each step, of how far I've gotten away from the origin&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ sort -n &lt;(R1 | awk '$2=1') &lt;(R2 | awk '$2=-1') | awk 'pos+=$2; d = ( pos &lt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Notice how I'm just recalling the last command and editing it.  All this is on the command line, where I can watch the effect of each step.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Print just the the biggest distance I get from the origin, for the whole trip&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;$ sort -n &lt;(R1 | awk '$2=1') &lt;(R2 | awk '$2=-1') | awk 'pos+=$2; d = ( pos &gt; 0 ) ? -pos : pos; print d' | sort -n | tail -1&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Easy enough.  I'll try it first with a script that uses the &lt;i&gt;&lt;a href="http://seejeffrun.blogspot.com/2009/09/another-random-post.html"&gt;Halgorithm&lt;/a&gt;:&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;head -10000 /dev/urandom | tr -dc 0-9 | perl -pe 's/(.{8})/\1\n/g' | head -${1:-10000}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Whatever argument I give it on the command line tells it how many eight-digit integers to generate. [Default: 10,000]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Two runs should produce different batches, but the same distribution.  I bring back the earlier command and do half a dozen runs with 100 numbers from each batch.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;$&lt;/span&gt; for i in {1..6}; do sort -n &lt;(R1 100 | awk '$2=1') &lt;(R1 100 | awk '$2=-1') | awk 'pos+=$2; d = ( pos &gt; 0 ) ? -pos : pos; print d' | sort -n | tail -1 ; done&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;13&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;20&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;6&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;7&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;10&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;10&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;The average?  10.6 .  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Careful!  I'm comparing the batch produced by one run of the generator with the run produced by a different batch.  It tells me what to expect for different batches from the &lt;i&gt;same&lt;/i&gt; distribution.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;More runs, a hundred instead of a dozen, just gives a more accurate average: 12.2&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If it varies with the square of the size of the batches, batches of 10,000 should give numbers nearer to 120.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ &lt;b&gt;for i in {1..6}; do sort -n &lt;(R1 | awk '"&gt;=1') &lt;(R1 | awk '"&gt;=-1') | awk 'pos+="&gt;; &lt;span class="Apple-style-span"  style=" font-weight: normal; font-family:Georgia, serif;"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;d = ( pos &gt; 0 ) ? -pos : pos; print d' | sort -n | tail -1 ; done&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;90&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;97&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;71&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;91&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;105&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;127&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;b&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Good.  The average value, over 100 paired runs, is about 125.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;This, finally, lets me &lt;/span&gt;&lt;a href="http://seejeffrun.blogspot.com/2009/09/another-challenge-from-hal-ed-random.html"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;compare Hal's method with the shell-only method&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; from an earlier post, which uses &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;$RANDOM&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;?  Does &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;$RANDOM&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; have a different distribution from &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;/dev/urandom&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Nope.  The average distance is, again, about 125.  If they're non-uniform, they're non-uniform in the same way.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;But maybe neither is random.  What if I compare them with&lt;/span&gt;&lt;a href="http://www.random.org/integers/?mode=advanced"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; a batch of uniformly-distributed, true random integers, downloaded from the web&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;?  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;About 135.  A little higher, but not high enough to set off a panic alarm.  &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;$RANDOM&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; and &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;/dev/urandom&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt; both give pseudo-random-numbers that are, roughly, uniformly distributed.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1843624187326283527?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1843624187326283527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1843624187326283527' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1843624187326283527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1843624187326283527'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/but-how-random-is-it.html' title='But *How* Random Is It?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-9006890572344516302</id><published>2009-09-03T06:28:00.004-06:00</published><updated>2009-09-05T11:28:02.922-06:00</updated><title type='text'>Another Random Post</title><content type='html'>&lt;div&gt;&lt;span style="font-family: georgia;font-family:'courier new', monospace;"&gt;Hal Pomeranz suggests this one-liner&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family: georgia;font-family:'courier new', monospace;"&gt;&lt;/span&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;span style="font-family:courier new;"&gt;head /dev/urandom | tr -dc 0-9 | sed -r 's/(.{8})/\1\n/g'&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;span style="font-family:georgia;"&gt;for generating big batches of random numbers.  It's a winner: reasonable performance and easy-to-type.  Timing information follows:&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;#!/bin/bash&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;echo == Shell arithmetic&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;(( R = 2**15-1, T = 10**8-1, C = T/R ))&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;readonly R T C&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;time for i in {0..10000}&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;  printf "%8.8u\n" $(( RANDOM*C + ( RANDOM%C ) ))&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;done &gt; /dev/null&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;echo; echo == Pipeline&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;time head -10000 /dev/urandom | tr -dc 0-9 | sed -r 's/(.{8})/\1\n/g' | head -10000 &gt; /dev/null&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Here's the numbers:&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;== Shell arithmetic&lt;/span&gt;&lt;div&gt; &lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;real 0m0.262s&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;user 0m0.256s&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;sys 0m0.004s&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;== Pipeline&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;real 0m0.421s&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;user 0m0.028s&lt;/span&gt;&lt;/div&gt; &lt;div&gt;&lt;span style="font-family:'courier new', monospace;font-size:85%;"&gt;sys 0m0.392s&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span style="font-family:'courier new', monospace;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Okay, the pipe's a little slower, but it's the same order of magnitude, and way easier to type.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-9006890572344516302?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/9006890572344516302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=9006890572344516302' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/9006890572344516302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/9006890572344516302'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/another-random-post.html' title='Another Random Post'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6601556113309597821</id><published>2009-09-02T16:45:00.000-06:00</published><updated>2009-09-02T16:46:55.264-06:00</updated><title type='text'>The International Slide Rule Museum</title><content type='html'>From Mike Rosenlof:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;They have (who am I kidding! HE has..)  an exhibit at the Louisville Public Library.&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;a style="font-style: italic;" href="http://sliderulemuseum.com/" target="_blank"&gt;http://sliderulemuseum.com/&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="color:#888888;"&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6601556113309597821?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6601556113309597821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6601556113309597821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6601556113309597821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6601556113309597821'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/international-slide-rule-museum.html' title='The International Slide Rule Museum'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8110096991564872966</id><published>2009-09-01T17:37:00.008-06:00</published><updated>2009-09-02T07:16:23.307-06:00</updated><title type='text'>Another Challenge From Hal &amp; Ed: Random Numbers In the Shell</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;Hal Pomeranz and Ed Skoudis have a weekly blog, &lt;a href="http://blog.commandlinekungfu.com/"&gt;Command Line Kung Fu&lt;/a&gt;, where they set and solve interesting problems in both the Unix/Linux shell and Windows's CLI, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;COMMAND.COM&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;This week's was how to generate random 8-digit integers.&lt;br /&gt;&lt;i&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Obligatory pedantic sidebar, which you can skip:&lt;/span&gt;&lt;/blockquote&gt;&lt;/i&gt;&lt;blockquote&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;"Random" can mean a lot of things.  If I flip a coin, and announce either "00000000" or "00000001", that's an 8-digit, random number.  Ho hum.  What I'm looking for here is integers uniformly distributed in the interval 0000000..99999999.  I'll write this as &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;U(0,10^8-1).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;The problem is trickier than you might think.  For example, the shell's random-number generator, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$RANDOM, &lt;/span&gt;is &lt;span class="Apple-style-span"  style="font-size:small;"&gt;U(0,2^15-1)&lt;/span&gt;.  Not big enough.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How about, say, summing calls to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$RANDOM&lt;/span&gt; until the number &lt;i&gt;is&lt;/i&gt; big enough?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nope. Adding a bunch of uniformly-distributed numbers gives a random number, all right.  But it isn't uniformly distributed anymore.  &lt;a href="http://en.wikipedia.org/wiki/Central_limit_theorem"&gt;It's a clumped-up, bell curve&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Hal explores several routes, culminating with a good one-liner:&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;  &lt;blockquote&gt;$ head /dev/urandom | tr -dc 0-9 | cut -c1-8&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;But is there a way with the shell's own built-ins?&lt;br /&gt;&lt;br /&gt;Yep.  The answer's below.  What's more, because this way doesn't call outside utilities or fork subshells, it should, in theory, be faster.  And it is.&lt;br /&gt;&lt;br /&gt;How much faster?&lt;br /&gt;&lt;br /&gt;On my machine, the one-liner above generates 10,000 random numbers in just under 40 seconds.  The code below does the same 10,000 in about a quarter of a second.&lt;br /&gt;&lt;br /&gt;I've written it out as a script, with a dramatic reading in the comments, but if I were using it in something else, I'd ditch the big comments and put the code in-line.&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;#!/bin/bash&lt;br /&gt;## Generate a uniformly distributed, &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;##   8-digit, random number: U(0,99999999)&lt;br /&gt;&lt;br /&gt;## First, the logic&lt;br /&gt;&lt;br /&gt;# (1) Get a uniformly-distributed random number,&lt;br /&gt;# N = $RANDOM, up to R = 2^15-1 = 32767.&lt;br /&gt;# That's U(0,R)&lt;br /&gt;&lt;br /&gt;# (2) Stretch out the interval covered,&lt;br /&gt;# up to nearly T = 10^8-1&lt;br /&gt;#   by multiplying by C = K/R.&lt;br /&gt;#  (We'll figure out K in a minute)&lt;br /&gt;#   This turns 0,1, 2, 3, ... into 0, C*1, C*2, ... K&lt;br /&gt;&lt;br /&gt;# (3) Now add a random shift S = U(0,C-1)&lt;br /&gt;#   to turn these into 0, 0+1, 0+2, ... 0+C-1,&lt;br /&gt;#     C*1+0, C*1+1, ..., K+0, K+1, ... K+C-1.&lt;br /&gt;#   We can get S from another random number M = $RANDOM % C&lt;br /&gt;#   (% is the 'mod' operator)&lt;br /&gt;&lt;br /&gt;# What's K?  We want K+C-1 = T = 10^8-1, so we solve:&lt;br /&gt;#   K+C-1 = K+(K/R)-1 = 10^8-1; K[ (R+1)/R ] = 10^8;&lt;br /&gt;# K = (10^8)*R/(R+1)&lt;br /&gt;&lt;br /&gt;# For big R, that's so close to T&lt;br /&gt;# that I'll just use K=T, C=T/R&lt;br /&gt;#  Our U(0,10^8-1) number is N*C + M&lt;br /&gt;&lt;br /&gt;## Next, the code&lt;br /&gt;&lt;br /&gt;# calculate the constants&lt;br /&gt;(( R = 2**15-1, T = 10**8-1, C = T/R ))&lt;br /&gt;readonly R T C&lt;br /&gt;&lt;br /&gt;# do the calculation, and print the result out&lt;br /&gt;#   with 8, full digits.&lt;br /&gt;printf "%8.8u\n" $(( RANDOM*C + ( RANDOM%C ) ))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;Nothing up my sleeve ... &lt;i&gt;Presto&lt;/i&gt;!  Not bad, for a shell.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt; Hal helpfully points out several things.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I misspelled his name.  &lt;/li&gt;&lt;/ul&gt;Oof.  Sorry.  Fixed.  Thanks.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There may be even faster solutions.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote style="font-style: italic;"&gt;if the task were to generate 10K 8-digit&lt;br /&gt;random numbers, I'd just suck 80K digits out of /dev/urandom and&lt;br /&gt;chop them up into 8-digit chunks.  That would be considerably&lt;br /&gt;faster than running my command line 10K times in a row.  &lt;/blockquote&gt;Maybe so ....  Is there a way to do that in the shell?  It's thought-provoking and an interesting challenge.&lt;br /&gt;&lt;br /&gt;You couldn't store the 80K digits in the code, but you could keep from having to store them in a file, and the attendant I/O slowdown, by just providing them as output from a pipe.&lt;br /&gt;&lt;br /&gt;(I'm told that in Windows, pipes are implemented with intermediate files. &lt;span style="font-family:courier new;"&gt; &lt;span style="font-family: georgia;"&gt;Not so in Unix and its offspring--the system really does hand data directly from one process to another.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;So, is there an easy way, in a shell script, to pull 8 digits at a time out of standard in?&lt;/span&gt;&lt;ul style="font-family: georgia;"&gt;&lt;li&gt;Execution efficiency isn't why you use the shell.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote style="font-family: georgia;"&gt;&lt;span style="font-style: italic;"&gt;If the&lt;/span&gt;&lt;span style="font-style: italic;"&gt; task is to generate a single 8-digit number, I claim my solution&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; is better from a typing perspective.  :-)&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: georgia;"&gt; Just so.  Hal's exactly right.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8110096991564872966?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8110096991564872966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8110096991564872966' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8110096991564872966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8110096991564872966'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/09/another-challenge-from-hal-ed-random.html' title='Another Challenge From Hal &amp; Ed: Random Numbers In the Shell'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7765759219317743662</id><published>2009-08-28T15:53:00.002-06:00</published><updated>2009-08-28T16:38:15.675-06:00</updated><title type='text'>Hash Collisions in Git</title><content type='html'>This post would be easier if I knew how to post formulas in Blogger.  If you know, tell me.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the &lt;a href="http://progit.org/book"&gt;Pro-Git Book&lt;/a&gt;, Scott Chacon notes that to have a probability of a SHA1-hash collision rise to 1/2, you need about 10^24 objects (more, he says, than the number of sand grains on earth).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Where's this come from?  It's a classic birthday problem.  If we have K people, with birthdays on any of 365 days, what are the odds of two or more people having the same birthday?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;P(same) = 1-P(everyone's different).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To assign different birthdays to K different people, we can give the first person any of 365 birthdays, the next any of the remaining 364, and so on.  The Kth person has a choice of 365-K+1 days.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Turning this into a probability means dividing by 365^K -- the number of different ways to assign birthdays to K folks if you don't care about collisions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But what's that product?  Just multiply it out:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;X = 365(365-1)(365-2) ... (365-K+1) = 365^K - [1+2+...+(365-K+1)]365^(K-1) + something,&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Where something is O(365^(K-2))  (That's big-Oh notation, if it's not clear.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Dividing by 365^K gives, approximately, P(no collision) = 1-[K(K-1)/2]/365,&lt;/div&gt;&lt;div&gt;or P(collision) = (1/365)K(K-1)/2 .&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For SHA1 sums, we replace 365 by the number of 160-bit SHA1 values: 2^160.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How big does K have to be for (1/2^160)K(K-1)/2 to be about 1/2?  About&lt;/div&gt;&lt;div&gt;K ~ sqrt(2^160) = 2^80, or about 10^24!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another quick applications of this idea comes from the fact that the SHA1 prefix git is now requiring to specify unique kernel objects is 10 hex digits long.  We can, therefore, guess the database now has something on the order of 2^20, or a million, distinct objects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And then there's the original birthday party question.  If you have sqrt(365) people in the room -- that's 17 or 18 -- you have about a 50-50 chance that two will have the same birthday.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This would, however, been clearer if I could have stuck real formulae in the post.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7765759219317743662?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7765759219317743662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7765759219317743662' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7765759219317743662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7765759219317743662'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/hash-collisions-in-git.html' title='Hash Collisions in Git'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3846380775214892101</id><published>2009-08-28T08:42:00.003-06:00</published><updated>2009-08-28T08:51:28.374-06:00</updated><title type='text'>Using Git Stash as a Snapshotter</title><content type='html'>I use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git stash&lt;/span&gt; to snapshot my work.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I even use it to snapshot my home directory.  I have a cron job that periodically does, basically, this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;git stash&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;git apply&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;to squirrel away any work I haven't checked in yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Basically.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Until today, it did &lt;i&gt;exactly&lt;/i&gt; that, but a few days ago, I started having a Makefile change get undone.  My old version kept coming back up like bad Mexican food. Hmm.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The bad (old) version was in my stash.  What would happen was that &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git stash&lt;/span&gt; would run, figure out I had no recent changes, and do nothing.  Then, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git apply &lt;span class="Apple-style-span" style="font-family: Georgia, serif; "&gt;would run, and restore the last un-checked-in code in the stash (my bad Makefile).&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hah.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, the code says this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;git stash | grep -q 'No local changes to save' ||&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;  git stash apply&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3846380775214892101?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3846380775214892101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3846380775214892101' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3846380775214892101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3846380775214892101'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/using-git-stash-as-snapshotter.html' title='Using Git Stash as a Snapshotter'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1764851363997633614</id><published>2009-08-26T13:45:00.003-06:00</published><updated>2009-08-26T14:46:34.823-06:00</updated><title type='text'>Remember When?</title><content type='html'>My uncle used to send "Remember when?" email to giant lists of people.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You've seen them from folks who are feeling old.  "Remember when penny candy cost a penny?" ... things like that.  Mostly, my answer was, "No."&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was walking back from lunch with David Russell, today, when a woman stopped us to ask for directions.  I said, "I'd look on Google Maps, but I left my phone at home."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then I thought about that for a second, and said, "Remember when we always left all our phones at home?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Remember when people used to send email to giant mailing lists instead of blogging or Tweeting?  You're probably answering, "No."&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1764851363997633614?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1764851363997633614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1764851363997633614' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1764851363997633614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1764851363997633614'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/remember-when.html' title='Remember When?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1455535097110491228</id><published>2009-08-26T13:10:00.002-06:00</published><updated>2009-08-26T13:45:12.720-06:00</updated><title type='text'>Are We There, Yet?  Using fuser() to See If The Job's Done.</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;Ever write a script that ends before the things in it should?&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The symptom is a file that gets partially written or partially copied.  Sometimes the output files are zero-length.  One example is the &lt;a href="http://seejeffrun.blogspot.com/2009/08/empty-turns-hard-into-not-so-hard.html"&gt;batch-mode sftp I wrote about last post.&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an illustrative example, followed by a trick to solve it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the empty-sftp program, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;empty&lt;/span&gt; spawns an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp&lt;/span&gt; session, which runs in parallel, waiting for me (really empty, but it thinks it's me) to type ftp commands.  If I only want to run one command&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;sftp&gt; get filename&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I can exit my script after issuing the command, but the pty will still be running.  I can kill the pty before I exit the script, but if the file transfer hasn't finished, the kill will truncate the output.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The basic problem is that there is no process that I can watch that terminates after the file transfer ends; like any shell (which is really what it is), &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp&lt;/span&gt; just keeps running, waiting for the next command.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The trick:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When the transfer's over, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp&lt;/span&gt; closes the output file.  We can watch to see when that happens, like this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;while true&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;sleep 1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;/sbin/fuser $localfile || break&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;done&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As soon as it finishes, we kill the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp&lt;/span&gt; session, and exit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1455535097110491228?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1455535097110491228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1455535097110491228' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1455535097110491228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1455535097110491228'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/are-we-there-yet-using-fuser-to-see-if.html' title='Are We There, Yet?  Using fuser() to See If The Job&apos;s Done.'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3904387278172498029</id><published>2009-08-26T09:20:00.005-06:00</published><updated>2009-08-26T09:51:53.556-06:00</updated><title type='text'>Empty Turns "Hard" Into "Not-So-Hard"</title><content type='html'>&lt;div&gt;Some things should be personal, even when you're at a computer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Logging in, for example. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Good, Linux, command-line tools read from standard in and write to standard out, which are connected, by default, to the keyboard and screen.  I try out programs by typing at them.  When I'm convinced I understand how they work, I can redirect I/O, to give them input from a file and capture their output in a second.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The upside-down is true, too: I can automate things I typically do interactively, just by having the programs do I/O to files instead of terminals.   I've written automated test suites for &lt;i&gt;screen editors&lt;/i&gt; with this trick.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Logging-in is different.  When the &lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;login&lt;/span&gt;&lt;/b&gt; program prompts you for your name and password, it puts the prompts directly on the screen and reads the answer from the keyboard.  Stdin and stdout aren't part of the picture.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This not only makes it hard to automate, it's supposed to make it hard to automate.  It's hard to make robots to batter down the system's doors, trying user name after user name and password after password for days on end.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's a security feature.  When a program seems not to be taking input from stdin, I think, "Is this like logging in?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, how do you automate those un-automatable jobs? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/Don_Libes"&gt;Don Libes&lt;/a&gt;, at NIST, in Gaithersburg, Maryland, gave us the first, good solution: &lt;a href="http://en.wikipedia.org/wiki/Expect"&gt;Expect&lt;/a&gt;.  Expect creates a pseudo-terminal whose virtual keyboard and screen are FIFOs that you can write to and read from.  Expect programs are mostly lists of the strings you expect to see, like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;login:&lt;/span&gt;, paired with the responses you want Expect to send when it sees those strings.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's wonderful.  I've used Expect for everything from testing printers to creating a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;make&lt;/span&gt; replacement that drives builds on &lt;a href="http://en.wikipedia.org/wiki/Tandem_Computers"&gt;Tandem's archaic Guardian OS&lt;/a&gt; from Unix machines running Expect scripts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately, Don picked the wrong horse.  Don built Expect on &lt;a href="http://en.wikipedia.org/wiki/Tcl"&gt;Tcl&lt;/a&gt;, a popular programming language in the early nineties, and used Tcl's syntax.  Today, Tcl is no longer in fashion; for most folks, writing Expect is like writing Latin.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nowadays, Perl, Java, and other languages, have Expect-like extensions, too, but they all feel fragile and hard to use.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yesterday, I needed to automate an &lt;a href="http://en.wikipedia.org/wiki/Secure_file_transfer_program"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sftp&lt;/span&gt;&lt;/a&gt; session, without any way to install public keys on the target machine.  I thought about Tcl, winced, then looked at &lt;a href="http://empty.sourceforge.net/"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;empty&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;, which is supposed to offer the same magic in shell scripts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Installation was just this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;$ sudo apt-get install empty-expect&lt;/span&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The program I wrote was short, simple, and it worked.  The meat was these lines, trivial modifications of examples in the man page:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# set up a session&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;empty -f -i in.fifo -o out.fifo -p empty.pid -L $log sftp $username@$remote_machine&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;empty -w -i out.fifo -o in.fifo password: $password'\n'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;# transfer the file&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;empty -w -i out.fifo -o in.fifo sftp "get $remotefile $localfile"'\n'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;For things that should be personal but can't be, I recommend &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;empty.&lt;/b&gt;&lt;/span&gt; At least, on your computer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3904387278172498029?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3904387278172498029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3904387278172498029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3904387278172498029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3904387278172498029'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/empty-turns-hard-into-not-so-hard.html' title='Empty Turns &quot;Hard&quot; Into &quot;Not-So-Hard&quot;'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-757187265877075222</id><published>2009-08-20T22:16:00.002-06:00</published><updated>2009-08-20T22:30:09.841-06:00</updated><title type='text'>How Do I Find Missing Files in a Sequence?</title><content type='html'>In&lt;a href="http://blog.commandlinekungfu.com/2009/08/episode-56-find-missing-jpeg.html"&gt; this week's Command-Line Kung Fu&lt;/a&gt;, Hal Pomerantz &amp;amp; Ed Skoudis field this question from a reader:&lt;i&gt;&lt;br /&gt;&lt;blockquote&gt;I have about 1300 pictures that I am trying to organize.&lt;br /&gt;They are numbered sequentially eg. ( 0001.jpg -&gt; 1300.jpg )&lt;br /&gt;The problem is that I seem to be missing some...&lt;br /&gt;&lt;br /&gt;Is there a fast way to be able to scan the directory to see which ones I am missing? Other than to do it manually, which would take a long time.&lt;br /&gt;&lt;/blockquote&gt;&lt;/i&gt;While they provide good, loop-based solutions, like this one:&lt;pre&gt;&lt;blockquote&gt;$ for i in $(seq -w 1 1300); do [ ! -f $i.jpg ] &amp;amp;&amp;amp; echo $i.jpg; done&lt;span style="font-family:Georgia,serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/pre&gt;and this&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;for ((i=1; $i &lt;= 1300; i++)); do file=$(printf "%04d.jpg" $i);[ ! -f $file ] &amp;amp;&amp;amp; echo $file; done&lt;/blockquote&gt;&lt;/pre&gt;they don't mention bash brace expansion.  In bash 4.0 and above, this does the trick:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;span style="font-size:85%;"&gt;$ ls {0001..1300}.jpg &gt;/dev/null&lt;/span&gt;&lt;/blockquote&gt;No loop.  No subprocess.  Quite readable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-757187265877075222?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/757187265877075222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=757187265877075222' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/757187265877075222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/757187265877075222'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/how-do-i-find-missing-files-in-sequence.html' title='How Do I Find Missing Files in a Sequence?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1083326093041902292</id><published>2009-08-20T15:13:00.002-06:00</published><updated>2009-08-20T15:26:52.849-06:00</updated><title type='text'>Include Guards in Sourced Files</title><content type='html'>How do I keep from sourcing the same files over and over?&lt;br /&gt;&lt;br /&gt;My shell scripts often have lines like this:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;source gripe.sh&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;Unfortunately, so do other sourced files.  How do I keep from sourcing something more than once?&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In C programs, my include files handle this with constructs like this:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;// foo.h -- include file for foo definitions&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;#ifndef _FOO_H&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;#define _FOO_H&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;#endif&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;The first time foo.h is included, it grabs all the included information.  If it's accidentally included a second time, though, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;_FOO_H&lt;/span&gt; is already defined, so the file is skipped.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an analogous construct that I use at the top of shell "include" files.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;# include guard&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if [ ${_gripe_version:-0} -gt 0 ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  return 0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  _gripe_version=1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new', serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new', serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;...  # remainder of file&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I could put the file contents inside the else block, and the fi at the end of the file, but I like just clumping the whole thing at the top.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1083326093041902292?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1083326093041902292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1083326093041902292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1083326093041902292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1083326093041902292'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/include-guards-in-sourced-files.html' title='Include Guards in Sourced Files'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-694368196359260567</id><published>2009-08-10T10:09:00.002-06:00</published><updated>2009-08-10T10:24:45.762-06:00</updated><title type='text'>Another Use For The Colon (:) Command</title><content type='html'>I've &lt;a href="http://seejeffrun.blogspot.com/2009/07/whats-this-colon-doing-in-my-comments.html"&gt;already blogged about the shell's no-op command&lt;/a&gt;, when I use it, and why.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I forgot about another way I use it.  Here 'tis.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Consider this loop:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;for i in {1..100}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;some-command-or-other $i&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;If you want to comment out the loop, you could comment out the whole thing by putting a comment character in front of each line, but that's tedious.  Easier would be to comment out the one-line loop body, like this&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;for i in {1..100}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;# some-command-or-other $i&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Except, um, that's an empty loop body and a syntax error.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;&lt;b&gt;bash: syntax error near unexpected token `done'&lt;/b&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This, however, is fine:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;for i in {1..100}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;blockquote&gt;: some-command-or-other $i&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;That loop body isn't empty, it just doesn't do anything.  No fuss, no muss.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-694368196359260567?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/694368196359260567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=694368196359260567' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/694368196359260567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/694368196359260567'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/another-use-for-colon-command.html' title='Another Use For The Colon (:) Command'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5141771475237775937</id><published>2009-08-07T12:46:00.000-06:00</published><updated>2009-08-07T12:47:05.203-06:00</updated><title type='text'>Amazondroid</title><content type='html'>I have seen the future of retail and it is my phone.&lt;br /&gt;&lt;br /&gt;Today, Amazon announced an Amazon Market app for the Android.  (There's one for the iPhone, too.) &lt;br /&gt;&lt;br /&gt;You point the camera at the barcode of an item and push a button.  It scans the barcode, then looks to see whether Amazon stocks the item. If so, it puts the item onto your wish list, so you can buy it (or so someone else can buy it for you).&lt;br /&gt;&lt;br /&gt;What would you pay? But wait. There's more.&lt;br /&gt;&lt;br /&gt;If Amazon doesn't have your item, they offer another option. Select the other button, and your camera takes a picture of the item, sends it up to Amazon, and a minute or less later, Amazon tells you *similar* items that they stock.  And puts them on your wish list.&lt;br /&gt;&lt;br /&gt;How do they do this?  Is it OCR?  Is it image recognition?  Is it Amazon Mechanical Turk?  I have no idea.&lt;br /&gt;&lt;br /&gt;And, frankly, who cares?&lt;br /&gt;&lt;br /&gt;They make it easy to buy. From them. This is brilliant.  Better even than the browser-based "Buy this together with ...."  Better even than "You might also be interested in."   Better even than "People who bought this item also bought ...."&lt;br /&gt;&lt;br /&gt;I have seen the future of retail and it is my phone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5141771475237775937?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5141771475237775937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5141771475237775937' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5141771475237775937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5141771475237775937'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/08/amazondroid.html' title='Amazondroid'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3304455512207636114</id><published>2009-07-27T16:42:00.005-06:00</published><updated>2009-07-27T16:46:32.403-06:00</updated><title type='text'>Linux Google Chrome, the Alpha Version</title><content type='html'>I've been trying out the Linux alpha of Google Chrome.  I started on Monday, June 8 09:40:37 MDT 2009 with version 3.0.183.1 .  A month and a half later, it's at 3.0.195.1 .  I haven't had any crashes.  That's not bad.&lt;br /&gt;&lt;br /&gt;I'm trying to switch to it, not because I'm unhappy with Firefox, but because it's the only way I ever learn new stuff -- by forcing myself to use it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3304455512207636114?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3304455512207636114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3304455512207636114' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3304455512207636114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3304455512207636114'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/07/linux-google-chrome-alpha-version.html' title='Linux Google Chrome, the Alpha Version'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5498606564841887571</id><published>2009-07-26T13:19:00.005-06:00</published><updated>2009-07-26T13:48:40.963-06:00</updated><title type='text'>What's this Colon Doing in My Comments?</title><content type='html'>Shell comments start with&lt;span style="font-weight: bold;"&gt; '&lt;/span&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;#&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;' &lt;/span&gt;--  except when they start with &lt;span style="font-weight: bold;"&gt;'&lt;/span&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;:&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;'&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Before 1981, they all started with &lt;span style="font-weight: bold;"&gt;':'&lt;/span&gt;, and they weren't really comments, they were commands.  They still are.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;$ type :&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: is a shell builtin&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;':' &lt;/span&gt;is a no-op.  Like &lt;span style="font-weight: bold;"&gt;true&lt;/span&gt;, it's a command that always succeeds, and does nothing.&lt;br /&gt;&lt;br /&gt;Since it doesn't do anything, you can give it whatever arguments you want.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;: This is a command that does nothing.  And, a comment.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;With one wrinkle: since it's a command, the shell processes its arguments. Side-effects? You bet.&lt;br /&gt;&lt;br /&gt;Here's a surprisingly common idiom in shell scripts. (Look through the &lt;span style="font-weight: bold;"&gt;/etc/&lt;/span&gt; directory for these.)&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;: ${FOO:=bar}&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;Huh?  Okay,  step at a time:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family: courier new;"&gt;$FOO&lt;/span&gt; is the value of the variable &lt;span style="font-family: courier new;"&gt;FOO&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: courier new;"&gt;${FOO:-bar}&lt;/span&gt; has the value &lt;span style="font-family: courier new;"&gt;$FOO&lt;/span&gt;, unless &lt;span style="font-family: courier new;"&gt;FOO&lt;/span&gt; doesn't have a value.  If &lt;span style="font-family: courier new;"&gt;FOO&lt;/span&gt; is unset or null, then the value of this typographic mess is the string, &lt;span style="font-weight: bold;"&gt;"bar"&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: courier new;"&gt;${FOO:=bar}&lt;/span&gt; is like that, but it also assigns &lt;span style="font-family: courier new;"&gt;FOO&lt;/span&gt; the value bar as a side-effect if it didn't already have a value.&lt;/li&gt;&lt;li&gt;So this command&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;blockquote&gt;: ${FOO:=bar}&lt;/blockquote&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;/blockquote&gt;sets &lt;span style="font-weight: bold;"&gt;FOO &lt;/span&gt;to the default value &lt;span style="font-weight: bold;"&gt;"bar", &lt;/span&gt; if it hasn't already been set to something else.  And then, it goes on to the next line in the script, because the command itself is a no-op.&lt;br /&gt;&lt;br /&gt;The entire purpose of that null command is the side-effect produced when the shell evaluates its arguments -- it announces a default value for &lt;span style="font-family: courier new;"&gt;$FOO&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;More verbose ways to say this include these:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;$ FOO=${FOO:-bar}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;or&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;$ [ "$FOO" ] || FOO=bar&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;or even&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;$ if [ "$FOO" = "" ]; then FOO=bar; fi&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;But if you want to understand the scripts in the &lt;span style="font-weight: bold;"&gt;/etc/&lt;/span&gt; directory, you need to at least recognize:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;${FOO:=bar}&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;and not be intimidated by it.&lt;br /&gt;&lt;br /&gt;Plus, knowing this lets you make sense of shell scripts that are more than 29 years old.  Since this is the &lt;a href="http://www.unix.org/"&gt;40th anniversary of Unix&lt;/a&gt;, that seems fitting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5498606564841887571?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5498606564841887571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5498606564841887571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5498606564841887571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5498606564841887571'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/07/whats-this-colon-doing-in-my-comments.html' title='What&apos;s this Colon Doing in My Comments?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8306476257170788027</id><published>2009-07-25T08:09:00.003-06:00</published><updated>2009-07-25T08:26:17.344-06:00</updated><title type='text'>File Access Times as Debugging Tools</title><content type='html'>&lt;span style="font-style: italic;"&gt;"Is that configuration file actually being read?  I'm sure I changed it.  Maybe I'm just not reading the data file I think I am."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"Is my command actually being executed?  Is my initialization script getting executed first?"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I use the Linux "file access time" as a debugging tool.&lt;br /&gt;&lt;br /&gt;If you want to know the last time a file was written, &lt;span style="font-family: courier new;"&gt;ls -l&lt;/span&gt; tells you the time.  You knew that.&lt;br /&gt;&lt;br /&gt;If you want to know the last time a file was read (or was run, if it's an executable), &lt;span style="font-family: courier new;"&gt;ls -ul&lt;/span&gt; tells you the time.  Maybe you didn't know that.&lt;br /&gt;&lt;br /&gt;Or the last time a particular app is getting invoked.  The access time tells you when an executable was run because Linux has to read it to execute it.&lt;br /&gt;&lt;br /&gt;Or, at least, it used to work this way.  Newer Linux systems no longer do, but you can still get the information you need.  I'll show you how.&lt;br /&gt;&lt;br /&gt;On newer systems, the access time (the time &lt;span style="font-family: courier new;"&gt;ls -ul&lt;/span&gt; reports) is the last time a file was read &lt;span style="font-style: italic;"&gt;after&lt;/span&gt; the last time it changed.   You can get the same information, it just takes a little more setup work.  Here's a script that shows how:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;#!/bin/bash -x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;PS4='$(date +%H:%M) $ '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == Create a file at a well-defined time.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;rm -f /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;touch /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == File write and access times are the same.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;ls -l /tmp/foo; ls -ul /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == Sleep, so the time changes, and read the file&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 60; cat /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == The access time is now later than the write time.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;ls -l /tmp/foo; ls -ul /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == Do it again.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 60; cat /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == The access time DOES NOT change, because There was no intervening write.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;ls -l /tmp/foo; ls -ul /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == Now "write" the file.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;touch /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == Sleep so the time changes, and read it.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 60; cat /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;: == This time, the time does change.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;ls -l /tmp/foo; ls -ul /tmp/foo&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;The meaning of access time was changed as an efficiency hack, so that inodes aren't re-written as often.&lt;br /&gt;&lt;br /&gt;In the script, I'm using ':' as a comment character.  I should explain why, but I'll leave that as a separate post.  Or, you could run the script to see. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8306476257170788027?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8306476257170788027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8306476257170788027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8306476257170788027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8306476257170788027'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/07/file-access-times-as-debugging-tools.html' title='File Access Times as Debugging Tools'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7704565625465782667</id><published>2009-07-02T11:38:00.003-06:00</published><updated>2009-07-02T12:40:45.834-06:00</updated><title type='text'>Using Preferred Applications from the CLI</title><content type='html'>I can use a command-line interface to invoke (not just "set," but &lt;span style="font-style: italic;"&gt;"invoke"&lt;/span&gt;) my GUI preferences.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;System-&gt; Preferences -&gt; Preferred Applications&lt;/span&gt; lets me set things like my preferred email application and preferred browser.  Works fine in the GUI, but how about from the command line?&lt;br /&gt;&lt;br /&gt;The solution is XDG tools, from the &lt;a href="http://en.wikipedia.org/wiki/Portland_project"&gt;Portland Project&lt;/a&gt;.  Browse a url or edit a file?&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;span style="font-size:85%;"&gt;xdg-open https://google.com&lt;br /&gt;xdg-open /tmp/foo.txt&lt;/span&gt;&lt;/blockquote&gt;Email?&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;span style="font-size:85%;"&gt;xdg-email&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7704565625465782667?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7704565625465782667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7704565625465782667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7704565625465782667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7704565625465782667'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/07/using-preferred-applications-from-cli.html' title='Using Preferred Applications from the CLI'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2303061854002829840</id><published>2009-06-26T13:04:00.002-06:00</published><updated>2009-06-26T13:26:55.947-06:00</updated><title type='text'>To Be Continued</title><content type='html'>I hate backslashes.  They make code harder to read.&lt;br /&gt;&lt;br /&gt;In these four code snippets, I like the first two, but not the last two:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;sleep 10 &amp;amp; date&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 10 &amp;amp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;date&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 10 &amp;amp; \&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;date&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;sleep 10 \&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;amp; date&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;So?  So, for the same reason, I would re-write:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;grep :0: /etc/passwd | \&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;wc -l&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;as&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;grep :0: /etc/passwd |&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;wc -l&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;and&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;grep -c jsh /etc/passwd \&lt;/span&gt;&lt;br /&gt;   &lt;span style="font-family: courier new;"&gt;|| echo jsh not found&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;   &lt;/span&gt;&lt;/blockquote&gt;as&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;blockquote&gt;grep jsh /etc/passwd ||&lt;br /&gt;echo jsh not found&lt;/blockquote&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt; The symbols&lt;span style="font-style: italic;"&gt; ', ", `, &amp;amp;, |, &amp;amp;&amp;amp;,&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;||&lt;/span&gt;, at the ends of lines, say "I'm not done," and automatically continue to the next line (or, in the case of the quote, until the closing quote).&lt;br /&gt;&lt;br /&gt;For shell symbols with parens, like &lt;span style="font-style: italic;"&gt;$(&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;&lt;(&lt;/span&gt;, the continuation is until the matching, closing paren.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2303061854002829840?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2303061854002829840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2303061854002829840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2303061854002829840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2303061854002829840'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/to-be-continued.html' title='To Be Continued'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6672290205958956509</id><published>2009-06-25T13:08:00.002-06:00</published><updated>2009-06-25T13:24:01.299-06:00</updated><title type='text'>Printing Strings in Shell Scripts</title><content type='html'>&lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt;'s nice.  &lt;span style="font-weight: bold;"&gt;printf&lt;/span&gt; is nicer.&lt;br /&gt;&lt;br /&gt;I still see people use &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt;.  Heck, &lt;span style="font-style: italic;"&gt;I&lt;/span&gt; still use &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;But POSIX shells have had &lt;span style="font-weight: bold;"&gt;printf&lt;/span&gt; as a built-in for twenty years.  The syntax is like C's &lt;span style="font-weight: bold;"&gt;printf()&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;You don't always need fancy formatting, so &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt;'s still good for simple strings, like this:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;echo 'What are you -- nuts?'&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;but there's no reason to use &lt;span style="font-weight: bold;"&gt;echo -n&lt;/span&gt; when you can use &lt;span style="font-weight: bold;"&gt;printf&lt;/span&gt;.  None.&lt;br /&gt;&lt;br /&gt;Just the reverse.  Experiments like this:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;time for i in {1..10000}; do printf $i; done &gt; /dev/null&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;time for i in {1..10000}; do echo -n $i; done &gt; /dev/null&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;will show you that &lt;span style="font-weight: bold;"&gt;printf&lt;/span&gt; is about 10% faster.&lt;br /&gt;&lt;br /&gt;Similarly, you can discard &lt;span style="font-weight: bold;"&gt;echo -e "foo\tbar"&lt;/span&gt; for &lt;span style="font-weight: bold;"&gt;printf "foo\tbar\n"&lt;/span&gt; .  Why keep a bunch of flags to &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt; in your head if you're comfy with &lt;span style="font-weight: bold;"&gt;printf&lt;/span&gt; from other languages?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6672290205958956509?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6672290205958956509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6672290205958956509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6672290205958956509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6672290205958956509'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/printing-strings-in-shell-scripts.html' title='Printing Strings in Shell Scripts'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5693957923703481552</id><published>2009-06-24T16:57:00.002-06:00</published><updated>2009-06-24T17:09:44.984-06:00</updated><title type='text'>Truncating a File</title><content type='html'>You can make truncating a file harder than it needs to be.&lt;br /&gt;&lt;br /&gt;I'm walking through Hal Pomeranz's older Command-Line Kung Fu postings, both because I know there'll be useful stuff and because he has some fun challenges.&lt;br /&gt;&lt;br /&gt;His &lt;a href="http://blog.commandlinekungfu.com/2009/04/episode-19-clearing-contents-of-file.html"&gt;Episode #19&lt;/a&gt; attacks zeroing out an existing file.  The solutions suggested are&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;cat /dev/null &gt; my_file&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;and&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;cp /dev/null my_file&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;(which is both shorter and works even if &lt;span style="font-weight: bold;"&gt;noclobber&lt;/span&gt; is set, to prevent accidentally overwriting pre-existing files with &lt;span style="font-weight: bold;"&gt;&gt;&lt;/span&gt; ).&lt;br /&gt;&lt;br /&gt;Both of these are more typing than necessary.  This works just as well:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;span style="font-size:85%;"&gt;&gt; my_file&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;and never even invokes a command.  It's all done by the shell.&lt;br /&gt;&lt;br /&gt;What's that?  You're running with &lt;span style="font-weight: bold;"&gt;set -o noclobber&lt;/span&gt; ?&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&gt;| my_file&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;If you want to do it in fewer characters, you can omit the space. :-) &lt;br /&gt;&lt;br /&gt;Cut!  It's a wrap.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5693957923703481552?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5693957923703481552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5693957923703481552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5693957923703481552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5693957923703481552'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/truncating-file.html' title='Truncating a File'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1515547608876370184</id><published>2009-06-23T13:41:00.003-06:00</published><updated>2009-06-23T14:22:46.873-06:00</updated><title type='text'>TIMTOWTDI: There Is More Than One Way To Do It</title><content type='html'>My favorite programming language is still the shell.&lt;br /&gt;&lt;br /&gt;Hal Pomeranz, whom I finally met at the OS Bridge conference in Portland last week, has a blog called &lt;a href="http://blog.commandlinekungfu.com/"&gt;Command-line Kung Fu&lt;/a&gt; full of shell tricks and tips.   He posts to it on Tuesdays.&lt;br /&gt;&lt;br /&gt;In today's, a post on how to decide what tools to use and when, he recommends &lt;span style="font-weight: bold;"&gt;cut(1)&lt;/span&gt; for some tasks because "&lt;span style="font-style: italic;"&gt;cut is the only tool that allows you to easily pull out&lt;/span&gt;&lt;span style="font-style: italic;"&gt; ranges of characters&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;Ah.  A challenge.&lt;br /&gt;&lt;br /&gt;Well, you can do his example:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;grep -l spammer@example.com qf* | cut -c3- | xargs -I'{}' rm qf{} df{}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;without &lt;span style="font-weight: bold;"&gt;cut&lt;/span&gt; at all.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;grep -l spammer@example.com qf* | while read i; do echo&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; ${i:2}; done | ...&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;I confess I'd do it differently, but that's because I like substitution better than cuts.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;for f in $(grep -l spammer@example.com qf*); do rm $f ${f/q/d}; done&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;It's pronounced "Tim-toady."  Hal emailed me saying he still likes his way better.  YMMV.&lt;br /&gt;&lt;br /&gt;For jobs like this, where I'm using a program to write commands on-the-fly, I usually play it safe.  I start off using echo to see what the shell thinks I want to do&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;for f in $(grep -l spammer@example.com qf*); do &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt; rm $f ${f/q/d}; done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;which spits out a list of the generated commands.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;rm qf137965 df137965&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rm qf200920 df200920&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;Then, when I think it's right, instead of removing the &lt;span style="font-weight: bold;"&gt;echo&lt;/span&gt; -- which risks a typo -- I recall the command, and tack on a pipe to a subshell, which executes the commands.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;for f in $(grep -l spammer@example.com qf*); do echo rm $f ${f/q/d}; done &lt;span style="font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;bash&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1515547608876370184?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1515547608876370184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1515547608876370184' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1515547608876370184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1515547608876370184'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/timtowtdi-there-is-more-than-one-way-to.html' title='TIMTOWTDI: There Is More Than One Way To Do It'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2751950731266350620</id><published>2009-06-22T19:25:00.002-06:00</published><updated>2009-06-22T19:36:43.979-06:00</updated><title type='text'>Twitter, Again</title><content type='html'>I'm giving &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt; another shot.&lt;br /&gt;&lt;br /&gt;I tried Twitter a while back and couldn't get excited about it.  I didn't know why I'd use it, or how.&lt;br /&gt;&lt;br /&gt;I just got back from &lt;a href="http://opensourcebridge.org/"&gt;Open Source Bridge 2009&lt;/a&gt;, in Portland, OR, where it was all the rage.  (The other things most attendees  were into were Ruby and git.)&lt;br /&gt;&lt;br /&gt;"Okay," I said, "let me find someone who gets it, and I'll just ask how to approach it."&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.msamye.com/"&gt;Ms. Amye&lt;/a&gt; was willing to be my evangelista, so I logged in, set up my account, and am now following a few folks that I met at the conferences (#osb09 is the Twitter "hash code").  I've even tweeted.&lt;br /&gt;&lt;br /&gt;I'm @goyishekop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2751950731266350620?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2751950731266350620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2751950731266350620' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2751950731266350620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2751950731266350620'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/twitter-again.html' title='Twitter, Again'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1011540653397935111</id><published>2009-06-15T05:46:00.003-06:00</published><updated>2009-06-15T06:21:23.260-06:00</updated><title type='text'>Beeees!  And Kino to the rescue.</title><content type='html'>This weekend, I put my first videos up on YouTube.  Here's why.&lt;br /&gt;&lt;br /&gt;Three Saturdays ago, May 30, Kristina and I were in King Soopers when my cell rang.  It was Kristine Smock, a mandolin player from Lyons.&lt;br /&gt;&lt;br /&gt;There's a swarm of bees in the alley behind my house.  Do you want them?&lt;br /&gt;&lt;br /&gt;We hurried home. Kristina grabbed a cardboard filing box, shoved in a frame with old comb, tossed it in the car, and we drove out to Lyons.  After she'd gotten the swarm in the box, she put on the lid and duct-taped both handles shut.  Once home, she put it on the deck, pulled off one piece of tape and -- presto! -- one new hive.&lt;br /&gt;&lt;br /&gt;I'd gotten her an observation hive for Christmas, which was still unpopulated.  By last Wednesday, it was set to go and she'd drilled a hole in the wall.&lt;br /&gt;&lt;br /&gt;A flip videorecorder was waiting for me on the porch from Amazon, so its maiden voyage was taking a video of the installation.&lt;br /&gt;&lt;br /&gt;Okay, I had it captured.  My first, little, 15' home movie.  Now what?  It'd be nice, for example, to show it to Kristina's parents.&lt;br /&gt;&lt;br /&gt;Can't mail it, it's half a gig.  YouTube?  Uh-oh.  YouTube has a 10' limit.  Other services?  Turns out there's a reason YouTube is popular -- they're slow and hard to use.&lt;br /&gt;&lt;br /&gt;By the next night, I could get someone at the BLUG meeting to show me enough rudimentary Kino to chop my video and post the pieces to YouTube.&lt;br /&gt;&lt;br /&gt;The trickiest part was figuring out to download the jmpegtools package, so that Kino would export the files in a format that YouTube liked.  Figuring it out required actually reading the error messages on the screen, which told me to install the jmpegtools package.  Duh.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/share?p=D792F7032760C75B"&gt;Here's the result.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And here's the first one, in embedded form:&lt;br /&gt;&lt;br /&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/RbgIzrsqKmA&amp;amp;hl=en&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/RbgIzrsqKmA&amp;amp;hl=en&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="344" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1011540653397935111?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1011540653397935111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1011540653397935111' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1011540653397935111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1011540653397935111'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/beeees-and-kino-to-rescue.html' title='Beeees!  And Kino to the rescue.'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6128657013571134513</id><published>2009-06-15T05:19:00.002-06:00</published><updated>2009-06-15T05:32:36.050-06:00</updated><title type='text'>I finally learn how to do realpath</title><content type='html'>Kevin Fenzi said I should send my shell-level &lt;span style="font-weight: bold;"&gt;realpath&lt;/span&gt; off to the maintainer of an appropriate package -- coreutils, maybe -- for possible inclusion.&lt;br /&gt;&lt;br /&gt;So, I wrote unit tests, a simple Makefile and documentation: man page, README, INSTALL, stuff like that.&lt;br /&gt;&lt;br /&gt;Kevin, wiser than I, looked and found documentation that suggested &lt;span style="font-weight: bold;"&gt;readlink -f&lt;/span&gt; would do the trick.  And it does.  I could prove it to myself because I had unit tests.&lt;br /&gt;&lt;br /&gt;One difference in functionality, which I can live with: if the file is missing, readlink -f succeeds and reports it's in the current directory.&lt;br /&gt;&lt;br /&gt;So, to find the path to an executable, this does the trick:&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;path2 () {&lt;br /&gt;local  _cmd=$(type -p $1)&lt;br /&gt;[ -f $_cmd ] &amp;amp;&amp;amp; readlink -f $_cmd&lt;br /&gt;}&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6128657013571134513?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6128657013571134513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6128657013571134513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6128657013571134513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6128657013571134513'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/i-finally-learn-how-to-do-realpath.html' title='I finally learn how to do realpath'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6547014188972020883</id><published>2009-06-09T05:36:00.000-06:00</published><updated>2009-06-15T05:45:47.150-06:00</updated><title type='text'>iPods and Banshee</title><content type='html'>&lt;div&gt;&lt;div&gt;Scott Mann posted a note to the Boulder Linux Users' Group Mailing list, asking for advice about iPods, MP3 players, and what software to use to manage them under Linux. &lt;br /&gt;&lt;br /&gt;As you'd expect, much of the advice was hyperbolic.  "Don't get an iPod.  They're unuseable."  Quick, someone tell Steve Jobs.&lt;br /&gt;&lt;br /&gt;I replied with my recent experience.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;span style="font-style: italic;"&gt;A few months ago, I switched my girlfriend, Kristina, over to Linux; her old, G3, &lt;/span&gt;&lt;wbr style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;iBook was finally biting the &lt;/span&gt;&lt;wbr style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;dust. She's been completely &lt;/span&gt;&lt;wbr style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;happy with Ubuntu.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-style: italic;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="font-style: italic;"&gt;Last week, she bought an iPod Nano on eBay. &lt;/span&gt;&lt;div style="font-style: italic;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-style: italic;"&gt; She's going to fill it with &lt;/span&gt;&lt;div style="font-style: italic;"&gt;her Dad's favorite music and &lt;wbr&gt;give it to him.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When it arrived, she took it out of &lt;wbr&gt;the box, turned to me, and &lt;wbr&gt;said, "How do I put music on this?"&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I took Scott Mann's advice and installed Banshee.  It mostly just worked.  It rips CDs to ogg by default, but I kept throwing gstreamer &lt;wbr&gt;packages at it until it said it knew how to create mp3s, too.&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To my mild surprise, it now also converts flac, ogg, wmv, and wv files to mp3s, on the fly, when I drag them onto the iPod.  I found this out by accident.  I mean, uh, by carefully reading all the documentation.&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Still, after reviewing this thread, I started to wonder whether, instead, I should have traded Kristina in for a smarter girlfriend -- one who'd have bought an mp3 player with a much better interface and then re-flashed it with Linux or RockBox herself.&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I asked her if she thought so, too, she ignored the question.&lt;/div&gt;&lt;div&gt;&lt;div class="gmail_quote"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="gmail_quote"&gt;Maybe she's &lt;span class="il"&gt;smart&lt;/span&gt; &lt;span class="il"&gt;enough&lt;/span&gt;.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="font-style: italic;"&gt;&lt;div&gt;&lt;div class="gmail_quote"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6547014188972020883?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6547014188972020883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6547014188972020883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6547014188972020883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6547014188972020883'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/ipods-and-banshee.html' title='iPods and Banshee'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6935491546189873219</id><published>2009-06-02T13:24:00.010-06:00</published><updated>2009-06-05T08:46:57.455-06:00</updated><title type='text'>What's the Absolute Path to a File?</title><content type='html'>There's no standard command that gives you the absolute path to a file.  That's insane.  Here's an implementation.&lt;br /&gt;&lt;br /&gt;Yes, it resolves symlinks and works on directories, too.&lt;br /&gt;&lt;br /&gt;I couldn't figure out how to get Blogger to stop re-formatting my code, so I passed it through &lt;a href="http://www.manoli.net/csharpformat/format.aspx"&gt;this, web-based, C#-formatting tool&lt;/a&gt; (!), and now it seems to look okay.&lt;br /&gt;&lt;br /&gt;Argh.&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="cshapcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;// realpath - what's the real path to a file?&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Turn relative paths into absolute paths,&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//   resolve '.' and '..',&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//   follow symlinks&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;#include &amp;lt;limits.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; main(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, &lt;span class="kwrd"&gt;char&lt;/span&gt; *argv[])&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;char&lt;/span&gt; path[_POSIX_PATH_MAX];&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (argc != 2) {&lt;br /&gt;    fprintf(stderr, &lt;span class="str"&gt;"usage: %s filename\n"&lt;/span&gt;, argv[0]);&lt;br /&gt;    exit(EINVAL);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (!realpath(argv[1], path)) {&lt;br /&gt;    perror(NULL);&lt;br /&gt;    exit(errno);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  printf(&lt;span class="str"&gt;"%s\n"&lt;/span&gt;, path);&lt;br /&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt;(0);&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6935491546189873219?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6935491546189873219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6935491546189873219' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6935491546189873219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6935491546189873219'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/06/whats-absolute-path-to-file.html' title='What&apos;s the Absolute Path to a File?'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3114389548594996271</id><published>2009-05-29T11:35:00.003-06:00</published><updated>2009-05-29T11:45:30.277-06:00</updated><title type='text'>Google Runs Rings Around M$ This Week</title><content type='html'>Google seems to be in fine form this week. &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Wednesday, they gave away Android phones to everyone at the Google I/O conference.  &lt;/li&gt;&lt;li&gt;Yesterday, they announced Google Wave.&lt;/li&gt;&lt;li&gt;Today they have up the full &lt;a href="http://www.techcrunch.com/2009/05/28/google-wave-the-full-video-from-google-io/"&gt;video of the Google Wave talk&lt;/a&gt;.  And the product will be Open Source.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;And Microsoft?  &lt;a href="http://www.techcrunch.com/2009/05/28/what-just-happened-thursday-was-supposed-to-be-bing-day/"&gt;Their big announcement, yesterday, was &lt;span style="font-weight: bold;"&gt;bing&lt;/span&gt;&lt;/a&gt;, a new search engine to compete with Google.  Which, at this point, even if it eventually works and comes out, is soooo 20th-century.  Sorry.&lt;br /&gt;&lt;br /&gt;It'll be interesting to see how Google ties this to ads.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3114389548594996271?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3114389548594996271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3114389548594996271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3114389548594996271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3114389548594996271'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/google-runs-rings-around-m-this-week.html' title='Google Runs Rings Around M$ This Week'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5763518246125155453</id><published>2009-05-28T08:11:00.003-06:00</published><updated>2009-05-28T08:23:21.414-06:00</updated><title type='text'>Editing Parallel Trees</title><content type='html'>Sometimes, I need to work in parallel trees -- trees with the same structure, but some important difference (different revision numbers, different compiler flags, ...).  When I'm deep inside one tree, getting over to the homologous place in the other can be painful.  Not only is it a lot of typing, but I'm often made aware that I should work at "Typos R Us."&lt;br /&gt;&lt;br /&gt;The string substitution syntax &lt;span style="font-family: courier new;"&gt;${FOO/bar/mumble}&lt;/span&gt;, which returns &lt;span style="font-family: courier new;"&gt;$FOO&lt;/span&gt;, but with &lt;span style="font-style: italic;"&gt;mumble&lt;/span&gt; substituted for &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt;, solves my problem.  For example, if I'm in the tree &lt;span style="font-family: courier new;"&gt;/home/jsh/tree1/a/b/c/d&lt;/span&gt;, and I want to pop over to&lt;span style="font-family: courier new;"&gt; /home/jsh/tree2/a/b/c/d&lt;/span&gt;, I just say&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;blockquote&gt;$ pushd ${PWD/tree1/tree2}&lt;br /&gt;&lt;/blockquote&gt;&lt;/span&gt;or even&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;blockquote&gt;$ cd ${PWD/1/2}&lt;/blockquote&gt;&lt;/span&gt;Presto!  I'm there faster than you can say, &lt;span style="font-style: italic;"&gt;"xyzzy." &lt;/span&gt; Or, at least as fast.&lt;br /&gt;&lt;br /&gt;Not only am I in the new tree, but now &lt;span style="font-weight: bold; font-family: courier new;"&gt;pushd&lt;/span&gt;, with no arguments, (or &lt;span style="font-weight: bold; font-family: courier new;"&gt;cd -&lt;/span&gt; ) takes me back and forth.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5763518246125155453?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5763518246125155453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5763518246125155453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5763518246125155453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5763518246125155453'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/editing-parallel-trees.html' title='Editing Parallel Trees'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7879429526504122408</id><published>2009-05-27T14:04:00.003-06:00</published><updated>2009-05-27T14:18:22.932-06:00</updated><title type='text'>How to Change File Extensions</title><content type='html'>Changing file extensions is easier than people make it out to be.  Even on &lt;a href="http://www.linux.org/lessons/tips/shell.html"&gt;sites that provide shell programming tips&lt;/a&gt;, I see recipes like this:&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;for file in *.dat ;&lt;br /&gt;&lt;br /&gt;do mv $file `echo $file | sed 's/\(.*\.\)dat/\1txt/'` ;&lt;br /&gt;&lt;br /&gt;done&lt;/blockquote&gt;&lt;/pre&gt;It's easier than that.  Honest.&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;$ for file in *.dat; do mv $file ${file/.dat/.txt}; done&lt;/blockquote&gt;&lt;/pre&gt; All in the same, parent shell.  One process.  No pipes, no sed, no magic regex metacharacters.  So easy, you can type it on the command line.&lt;br /&gt;&lt;br /&gt;I do it all the time.&lt;br /&gt;&lt;br /&gt;If I need to be careful, I start like this:&lt;br /&gt;&lt;pre&gt;      $ for file in *.dat; do echo mv $file ${file/.dat/.txt}; done&lt;br /&gt;&lt;/pre&gt; Then, if the output commands look like what I intended, I recall the loop, and tack a pipe of its output to &lt;span style="font-weight: bold;"&gt;bash&lt;/span&gt; on the end, like this:&lt;br /&gt;&lt;pre&gt;      $ for file in *.dat; do echo mv $file ${file/.dat/.txt}; done &lt;span style="font-weight: bold;"&gt;| bash&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7879429526504122408?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7879429526504122408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7879429526504122408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7879429526504122408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7879429526504122408'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/how-to-change-file-extensions.html' title='How to Change File Extensions'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6843195740635414762</id><published>2009-05-12T17:14:00.002-06:00</published><updated>2009-05-12T17:26:50.080-06:00</updated><title type='text'>Shell Programming Texts</title><content type='html'>There are no brief but substantial shell-programming texts.&lt;br /&gt;&lt;br /&gt;There are two, alternative models for programming textbooks: &lt;a href="http://www.amazon.com/Programming-Language-Brian-W-Kernighan/dp/0131101633"&gt;K&amp;amp;R&lt;/a&gt;, and &lt;a href="http://www.amazon.com/s/ref=nb_ss_b?url=search-alias%3Dstripbooks&amp;amp;field-keywords=java+programming&amp;amp;x=0&amp;amp;y=0"&gt;almost any Java book you pick up&lt;/a&gt;.  The Java books are boat anchors.  They're comprehensive, verbose, detailed, and replete with extensive terminology.  K&amp;amp;R is brief, to-the-point.&lt;br /&gt;&lt;br /&gt;Shell-programming books seem to follow the Java model.  What would a K&amp;amp;R-style shell book look like?&lt;br /&gt;&lt;br /&gt;I can't write as well as Brian Kernighan or Dennis Ritchie, but let's take a shot at a few pieces.&lt;br /&gt;&lt;br /&gt;Beginnings.&lt;br /&gt;&lt;br /&gt;Unlike languages like Java or C, talking to the shell &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; programming in the shell.  Just open a terminal window and type:&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;$ echo hello, world&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;hello, world&lt;/span&gt;&lt;/blockquote&gt;(Please try all the examples, even if you think you understand them.  It's easy enough, so why not?)&lt;br /&gt;&lt;br /&gt;You could type this a few times, for practice, but it's easier to recall the command than to retype it.  Press the up-arrow once and you'll see the last command reappear.  Press enter and the shell will execute the command.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;$ ^&lt;br /&gt;$ echo hello, world&lt;br /&gt;&lt;/blockquote&gt;The dollar sign is the prompt.  It says the shell is ready to listen to your next command.  Until you see the dollar sign, it's not.  You can type while waiting for a prompt, and the terminal will buffer up your typing to give to the shell  when it's finally done with what it's doing and ready for your next command.&lt;br /&gt;&lt;br /&gt;A command will normally only be executed after you press &lt;span style="font-weight: bold;"&gt;ENTER&lt;/span&gt;, whether you've typed it or are just recalling it.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;$ sleep 10&lt;br /&gt;echo hello, world&lt;br /&gt;[ten seconds elapses, then the next line appears, along with the execution of your command.]&lt;br /&gt;$ echo hello, world&lt;br /&gt;hello&lt;/blockquote&gt;You can press the up arrow a few times to look back through your history, or you can just type the command &lt;span style="font-weight: bold;"&gt;history&lt;/span&gt;.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;$ history&lt;br /&gt;1 echo hello, world&lt;br /&gt;2 echo hello, world&lt;br /&gt;3 sleep 10&lt;br /&gt;4 echo hello, world&lt;/blockquote&gt;(Now that you've typed it, the command &lt;span style="font-weight: bold;"&gt;history&lt;/span&gt; is in your history.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;$ history&lt;br /&gt;1 echo hello, world&lt;br /&gt;2 echo hello, world&lt;br /&gt;3 sleep 10&lt;br /&gt;4 echo hello, world&lt;br /&gt;5 history&lt;br /&gt;&lt;/blockquote&gt;)&lt;br /&gt;&lt;br /&gt;You can refer to and re-execute a command by its history number, but we'd like to discourage that.  There are more powerful ways to use history, and you should build the habit of using them from the start.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Type &lt;span style="font-weight: bold;"&gt;control-R &lt;/span&gt;(&lt;span style="font-weight: bold;"&gt;^R&lt;/span&gt;), then, slowly, "&lt;span style="font-style: italic;"&gt;hel&lt;/span&gt;" and watch what happens.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;(reverse-i-search)`':&lt;br /&gt;(reverse-i-search)`h': history&lt;br /&gt;(reverse-i-search)`he': echo hello, world&lt;br /&gt;(reverse-i-search)`hel': echo hello, world&lt;/blockquote&gt;The shell is looking, in reverse, through your history to find a command that matches the string you're giving it.  This is incremental search.  'h' matched "history", so that's what it found first.  As soon as you typed the 'e' , it looked further and found "echo hello, world" The "l" still matched, so it didn't look for a new line. &lt;br /&gt;&lt;br /&gt;As soon as you've found the history line you want, press &lt;span style="font-weight: bold;"&gt;ENTER&lt;/span&gt; to execute it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Exercise 1-1&lt;/span&gt;: Search for a command that isn't in your history.&lt;br /&gt;&lt;br /&gt;If you find yourself marooned on a line that you do not want to execute, just press &lt;span style="font-weight: bold;"&gt;^C&lt;/span&gt; to cancel it and get back to a prompt.  Try this both while you're typing and while you're searching through your history.  Notice, by examining your history when you do this, that canceled commands don't go into your history.  Only executed commands are recorded.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6843195740635414762?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6843195740635414762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6843195740635414762' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6843195740635414762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6843195740635414762'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/shell-programming-texts.html' title='Shell Programming Texts'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7174849485550887080</id><published>2009-05-08T09:07:00.003-06:00</published><updated>2009-05-08T09:18:41.530-06:00</updated><title type='text'>Mounting USB Drives Under Ubuntu</title><content type='html'>I backup daily to a USB drive, at work with &lt;span style="font-family: courier new;"&gt;git push&lt;/span&gt;.  But the last couple of days, I've been home, sick.&lt;br /&gt;&lt;br /&gt;I called in to ask Mike to stick in my USB drive, and he did, but it didn't automount.  The automounting seems to be a Nautilus thing, and requires being logged in at the console.  (I lock my screen when I leave at night.) &lt;br /&gt;&lt;br /&gt;Humph.&lt;br /&gt;&lt;br /&gt;I made him a login, so he could get in, and that got us farther, but when it mounted, it was owned by him.&lt;br /&gt;&lt;br /&gt;I tried &lt;span style="font-family: courier new;"&gt;mount -o remount,uid=1000&lt;/span&gt;, but that didn't work.  The &lt;span style="font-weight: bold;"&gt;mount&lt;/span&gt; command showed two &lt;span style="font-family: courier new;"&gt;uid=&lt;/span&gt; arguments -- the first, his.  (If I did it again, there were three.  The first one was still his, so he still was owner.)  Okay. &lt;br /&gt;&lt;br /&gt;I jotted down the name of the device, &lt;span style="font-family: courier new;"&gt;/dev/sd1&lt;/span&gt;, unmounted it, and remounted it by hand, as me.  Ta-da.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7174849485550887080?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7174849485550887080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7174849485550887080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7174849485550887080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7174849485550887080'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/mounting-usb-drives-under-ubuntu.html' title='Mounting USB Drives Under Ubuntu'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-8992635538401601069</id><published>2009-05-05T14:28:00.002-06:00</published><updated>2009-05-05T14:35:08.094-06:00</updated><title type='text'>Helping My Girlfriend with Google Docs Templates</title><content type='html'>I was up past midnight beating out a first-cut resume for my girlfriend.&lt;br /&gt;&lt;br /&gt;She's getting laid off, so she needs a new job.  Her resume, built from an academic CV, is so big and impenetrable it needs to include bookmarks.&lt;br /&gt;&lt;br /&gt;Sometimes, a job's so big that it's hard to start it yourself, so I told her I'd do it.  I reasoned I could get it close enough that she could finish it up.&lt;br /&gt;&lt;br /&gt;I started with Google Docs, which now has &lt;a href="http://docs.google.com/support/bin/topic.py?hl=en&amp;amp;topic=15809"&gt;templates&lt;/a&gt; -- including, it turns out, resume templates.&lt;br /&gt;&lt;br /&gt;A few hours playing, cutting, and pasting, and she has a first-cut that looks reasonable.&lt;br /&gt;&lt;br /&gt;If you know someone who wants to hire a biologist, don't hesitate to post a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-8992635538401601069?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/8992635538401601069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=8992635538401601069' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8992635538401601069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/8992635538401601069'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/helping-my-girlfriend-with-google-docs.html' title='Helping My Girlfriend with Google Docs Templates'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5214704762685607841</id><published>2009-05-04T08:20:00.003-06:00</published><updated>2009-05-04T08:56:31.482-06:00</updated><title type='text'>Fixing the Default ISO App in Ubuntu Jaunty</title><content type='html'>I just changed the default application for handling .iso files under Ubuntu Jaunty Jackalope back to what it was under Intrepid Ibex.  With clicky stuff.&lt;br /&gt;&lt;br /&gt;I've been making a deliberate effort to become more comfy with GUI tools.  I've been a command-line guy forever, which works fine for me, but not so well if I'm trying to help my girlfriend, or other folks who are more used to GUI, user-friendly, point-and-click interfaces.&lt;br /&gt;&lt;br /&gt;Every Monday morning, I burn a pair of ISO images to back some stuff up to DVDs.  My scripts put them onto my desktop, and I just double-click on the Destktop icons, which launches a disk-burner.  (See?  GUI!).&lt;br /&gt;&lt;br /&gt;Except that this morning, I double-clicked on an iso-image icon and ... Whoops!  A behavior change.   It &lt;span style="font-style: italic;"&gt;mounted&lt;/span&gt; the ISO.&lt;br /&gt;&lt;br /&gt;Can I fix this by clicking?  (Not "Can one?" but "Can&lt;span style="font-style: italic;"&gt; I&lt;/span&gt;?")&lt;br /&gt;&lt;br /&gt;Yes.&lt;br /&gt;&lt;br /&gt;Right click on the ISO to get a context menu.  Click on "Properties," down at the bottom, then on the "Open With" tab.  Sure enough, it's now set to Archive Mounter.  Switch this to "Disc Burner." (And how did "disk" become "disc"?  Is this a South African thing?)&lt;br /&gt;&lt;br /&gt;Ta-da!  The default for ISOs now is to burn them to disk, which is usually what I do with them.&lt;br /&gt;&lt;br /&gt;I'm comfier with clicking all the time, which means I'm a better support guy for my friends.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5214704762685607841?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5214704762685607841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5214704762685607841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5214704762685607841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5214704762685607841'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/fixing-default-iso-app-in-ubuntu-jaunty.html' title='Fixing the Default ISO App in Ubuntu Jaunty'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-9006494412425546299</id><published>2009-05-01T09:18:00.002-06:00</published><updated>2009-05-01T09:38:49.009-06:00</updated><title type='text'>Setting envelope-from on Ubuntu</title><content type='html'>After my &lt;a href="https://wiki.ubuntu.com/JauntyJackalope"&gt;Jaunty Jackalope&lt;/a&gt; upgrade, at work, some of my command-line mail tests were bouncing.  Why?  My sending address didn't have a Fully-Qualified Domain Name (FQDN).  Some sites bounce mail that doesn't have a valid domain name in the field. &lt;br /&gt;&lt;br /&gt;Sure enough, &lt;span style="font-weight: bold; font-family: courier new;"&gt;dnsdomainname&lt;/span&gt; returned ... nothing.  And &lt;span style="font-weight: bold; font-family: courier new;"&gt;uname -a&lt;/span&gt; gave me a machine name, but not an FQDN.&lt;br /&gt;&lt;br /&gt;I use Gmail for almost all my routine email, at home and at work.  Gmail doesn't complain.&lt;br /&gt;&lt;br /&gt;I also use command-line email in shell scripts, but that stays inside my LAN, which doesn't care about FQDNs either.  I could probably have lived with the problem, but I wanted it fixed so I started poking.&lt;br /&gt;&lt;br /&gt;I set the domain in &lt;span style="font-weight: bold; font-family: courier new;"&gt;/etc/hosts&lt;/span&gt;.  That fixed the output of &lt;span style="font-weight: bold; font-family: courier new;"&gt;dnsdomainname&lt;/span&gt;,&lt;br /&gt;and the &lt;span style="font-style: italic;"&gt;From:&lt;/span&gt; field in the email was set correctly.&lt;br /&gt;&lt;br /&gt;But not the mail problem.  &lt;span style="font-style: italic;"&gt;Envelope-from&lt;/span&gt; was still wrong.  The mail to my test, outside hosts still bounced with the same complaint.&lt;br /&gt;&lt;br /&gt;I restored the old hosts file and got Dean, our sysadmin, to give my machine a domain name through DNS.  That was a little more work but it worked ... and also didn't solve the mail problem.&lt;br /&gt;&lt;br /&gt;Finally, I stumbled over &lt;span style="font-family: courier new; font-weight: bold;"&gt;/etc/mailname&lt;/span&gt;.  Putting an FQDN in there does the trick.  The man page provides details.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-9006494412425546299?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/9006494412425546299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=9006494412425546299' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/9006494412425546299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/9006494412425546299'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/05/setting-envelope-from-on-ubuntu.html' title='Setting envelope-from on Ubuntu'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-683902133638096836</id><published>2009-04-16T13:20:00.005-06:00</published><updated>2009-04-16T13:39:17.990-06:00</updated><title type='text'>Cat Skinning, Made Easy</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eqYJM_T8b24/SeeIzmdl8sI/AAAAAAAAAzM/FgyAti6tyFg/s1600-h/p2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 309px; height: 400px;" src="http://1.bp.blogspot.com/_eqYJM_T8b24/SeeIzmdl8sI/AAAAAAAAAzM/FgyAti6tyFg/s400/p2.png" alt="" id="BLOGGER_PHOTO_ID_5325375504468275906" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-style: italic;"&gt;[Click on the story, above, to enlarge it.]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;My friend, Debi, wants to put a newsletter article about herself on her LinkedIn page.  All she has is the pdf for the entire magazine issue.  She doesn't even have a PDF writer on her Windows box.&lt;br /&gt;&lt;br /&gt;Impossible?&lt;br /&gt;&lt;br /&gt;Piece of cake.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;She mails me the pdf.  &lt;/li&gt;&lt;li&gt;I use Ubuntu's Document Viewer to bring up the PDF.  &lt;/li&gt;&lt;li&gt;I print page 2 to a file, as PDF.&lt;/li&gt;&lt;li&gt;I use &lt;span style="font-style: italic;"&gt;convert(1)&lt;/span&gt; to turn that pdf into a png.&lt;/li&gt;&lt;li&gt;I import the png into my blog.&lt;/li&gt;&lt;li&gt;We verify that she can see it, and that it suits her needs.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;We use &lt;a href="http://blogger.com/"&gt;Blogger&lt;/a&gt; to create her a blog, put the same png into her own blog entry, and point to it on her &lt;a href="http://linkedin.com/"&gt;LinkedIn&lt;/a&gt; page.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="display: block;" id="formatbar_Buttons"&gt;&lt;span class="on down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;img src="http://www.blogger.com/img/blank.gif" alt="Link" class="gl_link" border="0" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-683902133638096836?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/683902133638096836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=683902133638096836' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/683902133638096836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/683902133638096836'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/04/cat-skinning-made-easy.html' title='Cat Skinning, Made Easy'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eqYJM_T8b24/SeeIzmdl8sI/AAAAAAAAAzM/FgyAti6tyFg/s72-c/p2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4141389369386620256</id><published>2009-03-19T15:52:00.002-06:00</published><updated>2009-03-19T15:54:31.136-06:00</updated><title type='text'>Google Voice</title><content type='html'>Well, okey doke.  Google's finally bringing GrandCentral back as Google Voice.&lt;br /&gt;&lt;br /&gt;Let's see if their new call button works.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="100%" height="100%"&gt;&lt;param name="movie" value="https://clients4.google.com/voice/embed/webCallButton"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="FlashVars" value="id=4bd823b579f102ad67cae9d829d0f593cc2fce90&amp;style=0"&gt;&lt;/param&gt;&lt;embed src="https://clients4.google.com/voice/embed/webCallButton" type="application/x-shockwave-flash"wmode="transparent" width="100%" height="100%" FlashVars="id=4bd823b579f102ad67cae9d829d0f593cc2fce90&amp;style=0"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4141389369386620256?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4141389369386620256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4141389369386620256' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4141389369386620256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4141389369386620256'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/03/google-voice.html' title='Google Voice'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4684897260587305698</id><published>2009-01-11T21:39:00.008-07:00</published><updated>2009-01-12T09:04:13.973-07:00</updated><title type='text'>Grand Central</title><content type='html'>I'm not posting regularly, but once in a while something is a must-post.  This is one.&lt;br /&gt;&lt;br /&gt;In the Marine Corps I was a radio operator, which required acquiring the skill "push to talk."  Finally, this reflex returns in a way I wouldn't have predicted.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://c-3903.estara.com/UI/gui.php?donotcache=1231775956327&amp;amp;accountid=200106281243&amp;amp;referrer=https%3A%2F%2Fwww.amazon.com%2Fgp%2Fhelp%2Fcontact-us%2Fgeneral-questions.html%3Fie%3DUTF8%26nodeId%3D508510%26type%3Demail%26skip%3Dtrue%23csTop&amp;amp;pagetitle=Express+-+Customer+Service&amp;amp;template=236973&amp;amp;anioverride=7248124709&amp;amp;var2=US&amp;amp;var3=7248124709&amp;amp;calltype=webvoicepop&amp;amp;guiid=43834a54eac25&amp;amp;timestamp=1231775956"&gt;Jeff Bezos has a call-me button&lt;/a&gt;?  Me, too.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="left: 0px ! important; top: 15px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-08405983964885595 visible ontop" href="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2"&gt;&lt;/a&gt;&lt;a style="left: 0px ! important; top: 0px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-08405983964885595 visible ontop" href="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2"&gt;&lt;/a&gt;&lt;a style="left: 0px ! important; top: 0px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-08405983964885595 visible ontop" href="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2"&gt;&lt;/a&gt;&lt;a style="left: 0px ! important; top: 0px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-044443073880286976 visible ontop" href="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2"&gt;&lt;/a&gt;&lt;a style="left: 0px ! important; top: 0px ! important;" title="Click here to block this object with Adblock Plus" class="abp-objtab-044443073880286976 visible ontop" href="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2"&gt;&lt;/a&gt;&lt;embed src="http://embed.grandcentral.com/webcall/44e55dd45e2628f08c88a3b331613ba2" wmode="transparent" height="213" width="435"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4684897260587305698?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4684897260587305698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4684897260587305698' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4684897260587305698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4684897260587305698'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2009/01/well-im-obviously-not-posting-very.html' title='Grand Central'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-6468830850893228834</id><published>2008-08-15T06:35:00.005-06:00</published><updated>2008-08-15T07:06:28.156-06:00</updated><title type='text'>Kevin Kempter</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_eqYJM_T8b24/SKV4r8cuBII/AAAAAAAAAgI/xfxlYyUmaxQ/s1600-h/Image005.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_eqYJM_T8b24/SKV4r8cuBII/AAAAAAAAAgI/xfxlYyUmaxQ/s400/Image005.jpg" alt="" id="BLOGGER_PHOTO_ID_5234722838244361346" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eqYJM_T8b24/SKV4MneiuqI/AAAAAAAAAf4/psZeWyD3ArQ/s1600-h/Image006.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_eqYJM_T8b24/SKV4MneiuqI/AAAAAAAAAf4/psZeWyD3ArQ/s400/Image006.jpg" alt="" id="BLOGGER_PHOTO_ID_5234722300038920866" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I met &lt;a href="http://kevinkempterllc.com/"&gt;Kevin Kempter&lt;/a&gt; at a &lt;a href="http://www.cluedenver.org/display.php?node=installfest"&gt;CLUE Installfest&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Kevin was hauling around gear in a great, Marine Corps bag.  I thought, "Hah!  Another jarhead.  Hey ...  how can&lt;span style="font-style: italic;"&gt; I&lt;/span&gt; get one of those bags?"&lt;br /&gt;&lt;br /&gt;He'd had the same thought.  On a visit to &lt;a href="http://www.mcrdsd.usmc.mil/"&gt;MCRD&lt;/a&gt;, he saw a guard with the same bag, and asked him where he could get one.&lt;br /&gt;&lt;br /&gt;"They're only for active-duty Marines, so I'm not allowed to tell you that if you go down that way one block and over two, you'll find the PX.  Sir."&lt;br /&gt;&lt;br /&gt;"Interested in giving a BLUG talk?" I asked Kevin.&lt;br /&gt;&lt;br /&gt;"Sure."&lt;br /&gt;&lt;br /&gt;"What would you talk about?"&lt;br /&gt;&lt;br /&gt;"&lt;a href="http://www.postgresql.org/"&gt;Postgres&lt;/a&gt;."&lt;br /&gt;&lt;br /&gt;Turns out, people &lt;span style="font-style: italic;"&gt;are&lt;/span&gt; interested in Postgres.&lt;br /&gt;&lt;br /&gt;Kevin played to a standing-room-only crowd last night.&lt;br /&gt;&lt;br /&gt;He told us he has one client who's now pulling in a terabyte of data a day, and expects to expand this by a factor of 100.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-6468830850893228834?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/6468830850893228834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=6468830850893228834' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6468830850893228834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/6468830850893228834'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/kevin-kempter.html' title='Kevin Kempter'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eqYJM_T8b24/SKV4r8cuBII/AAAAAAAAAgI/xfxlYyUmaxQ/s72-c/Image005.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5338238373803844781</id><published>2008-08-14T05:20:00.002-06:00</published><updated>2008-08-14T05:29:06.648-06:00</updated><title type='text'>Apache Status</title><content type='html'>You can get your apache2 (and, I suspect, apache) server to display status information on prefab server-status and server-info pages by loading the status and info modules and tweaking the configuration files to pay attention to them.&lt;br /&gt;&lt;br /&gt;Having done that, http://localhost/server-info and http://localhost/server-status&lt;br /&gt;will tell you what modules are loaded and what they do.  With little more work, you can also permit access to these pages by other boxes.&lt;br /&gt;&lt;br /&gt;I set this up yesterday at work, but haven't done it at home because this laptop isn't serving up web pages at all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5338238373803844781?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5338238373803844781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5338238373803844781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5338238373803844781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5338238373803844781'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/apache-status.html' title='Apache Status'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-440839874172595573</id><published>2008-08-11T06:26:00.002-06:00</published><updated>2008-08-11T06:34:25.678-06:00</updated><title type='text'>Gitosis</title><content type='html'>I spent part of the weekend playing with &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;gitosis&lt;/a&gt;, a tool for administering remotely-accessible &lt;a href="http://git.or.cz/"&gt;git&lt;/a&gt; repositories.&lt;br /&gt;&lt;br /&gt;Access revolves around &lt;a href="http://en.wikipedia.org/wiki/Secure_Shell"&gt;ssh&lt;/a&gt; and public/private key pairs.  You give me your public key, and I can grant you selective permissions, repo-by-repo, if I'm the gitosis administrator.  Once I do, it's painless to check stuff in and out, since all the permissions stuff is under-the-covers.  Much nicer than Subversion's cacheing of passwords in plain text.&lt;br /&gt;&lt;br /&gt;One of the coolest things is that the administrative data, including public keys, are kept in a git database.  If I'm the (or an) administrator, I can administer access remotely, with git pull and git push -- including adding new users and their keys -- using gitosis itself for the repo access.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-440839874172595573?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/440839874172595573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=440839874172595573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/440839874172595573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/440839874172595573'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/gitosis.html' title='Gitosis'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2486374931185617826</id><published>2008-08-10T10:18:00.002-06:00</published><updated>2008-08-10T10:39:47.413-06:00</updated><title type='text'>Error-handling, again.</title><content type='html'>Here's a better version of my error-handling shell functions.  Maybe I am educable, after all.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;# common error-handling functions&lt;br /&gt;&lt;br /&gt;if [ $_gripe ]; then return 0; else _gripe=1; fi  # include guard&lt;br /&gt;&lt;br /&gt;warn() { printf "$* at line %s file %s: $msg\n" $(caller) 1&gt;&amp;amp;2 ; }&lt;br /&gt;die() { printf "$* at line %s file %s: $msg\n" $(caller) 1&gt;&amp;amp;2 ; exit -1; }&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;I have an include guard so I can include it in other shell functions that may be included with one another.  I use &lt;span style="font-style: italic;"&gt;if&lt;/span&gt;, rather than a &lt;span style="font-style: italic;"&gt;[test] || alternative&lt;/span&gt; construct because I'm often running &lt;span style="font-style: italic;"&gt;set -e&lt;/span&gt;, and don't want to die because of the test itself.&lt;br /&gt;&lt;br /&gt;I have &lt;span style="font-style: italic;"&gt;die()&lt;/span&gt; printing its own message, instead of calling &lt;span style="font-style: italic;"&gt;warn()&lt;/span&gt;, so that it reports where it's invoked.  Otherwise, &lt;span style="font-style: italic;"&gt;warn()&lt;/span&gt; announces it's being called by &lt;span style="font-style: italic;"&gt;die()&lt;/span&gt;.  Duh.&lt;br /&gt;&lt;br /&gt;It amazes me that after doing this for so long, I can still be fixing bugs in my own code -- and code as basic as this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2486374931185617826?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2486374931185617826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2486374931185617826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2486374931185617826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2486374931185617826'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/error-handling-again.html' title='Error-handling, again.'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3202033257067206002</id><published>2008-08-09T05:08:00.003-06:00</published><updated>2008-08-09T05:32:58.650-06:00</updated><title type='text'>Making Makefiles Behave: Loops</title><content type='html'>The last command in a shell &lt;span style="font-style: italic;"&gt;for&lt;/span&gt; loop determines whether the loop succeeds or fails.&lt;br /&gt;&lt;br /&gt;This succeeds:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;$ for i in false true; do echo $i; $i; done&lt;br /&gt;false&lt;br /&gt;true&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;$ echo $?&lt;/span&gt;&lt;br /&gt;0&lt;/span&gt;&lt;/blockquote&gt;This fails&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;$ for i in true false; do echo $i; $i; done&lt;br /&gt;true&lt;br /&gt;false&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;$ echo $?&lt;br /&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;When does this matter?  In Makefiles.  Suppose you have a &lt;span style="font-style: italic;"&gt;make&lt;/span&gt; rule that looks like this:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;foo:&lt;br /&gt;        for dir in $(SUBDIRS); do $(MAKE) -C $$dir; done&lt;/span&gt;&lt;/blockquote&gt;A failure of one of the subdirectory makes will not cause the make to fail!&lt;br /&gt;&lt;br /&gt;How do you solve this?  There are several sophisticated ways, but the dead-easy way is to start the Makefile like this:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;SHELL := /bin/bash -e&lt;/span&gt;&lt;/blockquote&gt;This will cause all shell commands to be executed with the &lt;span style="font-style: italic;"&gt;-e&lt;/span&gt; flag, which causes any simple command to terminate the shell.&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;$ ( set -e; for i in false true; do echo $i; $i; done )&lt;br /&gt;false&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;$ echo $?&lt;br /&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;(I have to put the command and the &lt;span style="font-style: italic;"&gt;set -e&lt;/span&gt; in parens here -- though not in the &lt;span style="font-style: italic;"&gt;Makefile&lt;/span&gt; -- because any failure causes the command to fail and the shell to exit, so the following "&lt;span style="font-style: italic;"&gt;echo $?&lt;/span&gt;" would never be reached.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3202033257067206002?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3202033257067206002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3202033257067206002' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3202033257067206002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3202033257067206002'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/making-makefiles-behave-loops.html' title='Making Makefiles Behave: Loops'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5136982945535686829</id><published>2008-08-05T06:29:00.002-06:00</published><updated>2008-08-05T06:32:37.236-06:00</updated><title type='text'>CruiseControl</title><content type='html'>For fun, I've set up CruiseControl on my laptop.&lt;br /&gt;&lt;br /&gt;It's annoyingly hard to configure, and there seems not to be an rpm for Ubuntu, but it works.&lt;br /&gt;&lt;br /&gt;I have it set up to watch a git repository, and build "hello, world."  I can push to the repository from elsewhere and trigger a new build. &lt;br /&gt;&lt;br /&gt;Ta-da!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5136982945535686829?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5136982945535686829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5136982945535686829' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5136982945535686829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5136982945535686829'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/cruisecontrol.html' title='CruiseControl'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5310462622665808150</id><published>2008-08-03T05:10:00.004-06:00</published><updated>2008-08-03T05:58:13.375-06:00</updated><title type='text'>Google Chat-Bots for Translation</title><content type='html'>I use the &lt;a href="http://googletalk.blogspot.com/2007/12/merry-christmas-god-jul-and.html"&gt;Google chat-bots&lt;/a&gt; for quick translations.  Here's an illustration from a note to a friend:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;&lt;span style="font-size:85%;"&gt;For whatever reason, I looked at the story you gave me, saw "laberintos," and thought, "Shouldn't that be 'labArintos'?"&lt;br /&gt;&lt;br /&gt;So I popped up a chat window in gmail, invited &lt; &lt;a href="mailto:en2es@bot.talk.google.com" target="_blank"&gt;&lt;span class="nfakPe"&gt;en2es&lt;/span&gt;@bot.talk.google.com&lt;/a&gt;&gt; to chat, and typed in "labyrinth."  It responded,&lt;br /&gt;"Laberinto."&lt;br /&gt;&lt;br /&gt;I said, "thank you," to which it replied "Gracias." :-)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;Now that Google has group chat, you can invite a pair of simultaneous translators to join, and have chats with people you don't even share a language with.  Mostly, though, I use them for quick translation: it's easier than going to a website.&lt;br /&gt;&lt;br /&gt;Update:  I just looked, and Google has added &lt;a href="http://googletalk.blogspot.com/2008/06/more-translation-bots.html"&gt;many more translation-bots&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5310462622665808150?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5310462622665808150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5310462622665808150' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5310462622665808150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5310462622665808150'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/08/google-chat-bots-for-translation.html' title='Google Chat-Bots for Translation'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1546790760083314274</id><published>2008-07-28T19:12:00.003-06:00</published><updated>2008-07-28T19:17:30.883-06:00</updated><title type='text'>Sort-of Techical Problems, Sort-of Technical Solutions</title><content type='html'>I subscribe to the &lt;a href="http://lug.boulder.co.us"&gt;Boulder Linux Users' Group&lt;/a&gt; mailing list.  It's my local LUG, it carries announcements of local events, and the posts are mostly technical.&lt;br /&gt;&lt;br /&gt;Plus, when you know folks, it's fun to see what they think and how they write.  I read the stuff Sean Reifschneider posts even when I have no clue what he's talking about.&lt;br /&gt;&lt;br /&gt;The opposite's true, too.  I started going to Dave Anselmi's Installfests just to meet him and Collins Ritchie.  I'd been so impressed by their steady, helpful contributions to the mailing list that I wanted to see what they looked like.&lt;br /&gt;&lt;br /&gt;Oh, sure, there's an occasional call to boycott a large company because they buy closed-source software.&lt;br /&gt;&lt;br /&gt;In some cases, these move me to action.  As soon as I learned Microsoft uses Microsoft products in-house, I stopped buying stuff from Microsoft.&lt;br /&gt;&lt;br /&gt;In other cases, not so much.  King Soops?  I still shop there.&lt;br /&gt;&lt;br /&gt;And, once in a while, some poster decides it's important we all read about their far-left political views.  But what do you expect from the People's Republic of Boulder Linux Users' Group?&lt;br /&gt;&lt;br /&gt;Mostly, though, the signal-to-noise ratio is high.&lt;br /&gt;&lt;br /&gt;Just now, however, we've had a couple of back-to-back flamefests running that swamp out the parts I find useful.&lt;br /&gt;&lt;br /&gt;At first, I thought, "Oh well.  If this is going to turn into Slashdot, I'll unsubscribe."&lt;br /&gt;&lt;br /&gt;Then I realized that I have a technical solution at hand.  Gmail lets me, with a single keypress ('m'), mute threads I'm not interested in: they no longer show up in my mailbox.  As long as no one hijacks the thread, by changing the subject line, I can go back to reading the stuff I'm interested in.&lt;br /&gt;&lt;br /&gt;The thread, meanwhile, continues to go into my archives, so if I suddenly become passionate and want to flame, too, I can retrieve it.&lt;br /&gt;&lt;br /&gt;I suppose there's a chance my mailbox will fill up with the stuff, but even if Google stopped giving me more space &lt;span style="font-style: italic;"&gt;today&lt;/span&gt;, a quick back-of-the-envelope calculation says I'll be 72 before my mailbox fills up.&lt;br /&gt;&lt;br /&gt;I can live with that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1546790760083314274?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1546790760083314274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1546790760083314274' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1546790760083314274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1546790760083314274'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/sort-of-techical-problems-sort-of.html' title='Sort-of Techical Problems, Sort-of Technical Solutions'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1193136798675661918</id><published>2008-07-28T05:30:00.002-06:00</published><updated>2008-07-28T05:48:47.352-06:00</updated><title type='text'>I Need Google Gears, not Prism</title><content type='html'>&lt;a href="http://lifehacker.com/399296/the-lifehacker-editors-favorite-software-and-hardware"&gt;The Lifehacker list of favorite software and hardware&lt;/a&gt; is mostly non-Linux or things like Gmail that I already use.  Prism, however, is neither.&lt;br /&gt;&lt;br /&gt;I've looked and I don't want it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lifehacker.com/375830/create-distraction+free-customized-webapps-with-prism"&gt;Prism, from Mozilla Labs&lt;/a&gt;, is a single-app browser.   For example, it lets you create something that will run only &lt;a href="https://www.rememberthemilk.com/"&gt;RememberTheMilk&lt;/a&gt;.  They call this a "customized webapp."&lt;br /&gt;&lt;br /&gt;The advantage?  It's distraction-free.  The disadvantage?  It's still a browser.&lt;br /&gt;&lt;br /&gt;Unfortunately, mostly what I want isn't freedom from distractions, it's performance.  My major annoyances aren't the icon that says I have new mail -- I put that icon there, after all -- but network slowdowns.&lt;br /&gt;&lt;br /&gt;Unfortunately, the best solution I've seen, &lt;a href="http://gears.google.com/"&gt;Google Gears&lt;/a&gt;, often isn't available for the webapps I use.  I mean, there's no Google Gears for Gmail! &lt;br /&gt;&lt;br /&gt;And often, it's broken.  Every new Firefox seems to break Gears.&lt;br /&gt;&lt;br /&gt;If Mozilla Labs wants to help me, I hope they put some time into fixing the last of these problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1193136798675661918?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1193136798675661918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1193136798675661918' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1193136798675661918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1193136798675661918'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/i-need-google-gears-not-prism.html' title='I Need Google Gears, not Prism'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7053986551146704403</id><published>2008-07-27T10:42:00.002-06:00</published><updated>2008-07-27T10:50:09.584-06:00</updated><title type='text'>Exporting HTML from Tomboy Notes</title><content type='html'>I've now tried Tomboy Notes, so I know what it can do.&lt;br /&gt;&lt;br /&gt; spent part of yesterday fussing with a little Java/Design Patterns project.  I made some progress, but the most practical benefit was taking notes on what I was doing with Tomboy -- not because the notes helped, but because I'd never really tried Tomboy out.&lt;br /&gt;&lt;br /&gt;One useful feature is its "Export to HTML" option.  I spent a few hours noting what I was doing, as I was doing it, then exported the note.  Here's the result, with no editing.  After the export, it puts up a web page in the browser.  From there, getting it here took three keystrokes: mark all (^A), cut (^C), and paste (^V).&lt;br /&gt;&lt;br /&gt;&lt;div class="note" id="HFP-July 26"&gt;&lt;a name="#HFP-July 26"&gt;&lt;/a&gt;&lt;h1&gt;HFP-July 26&lt;/h1&gt;  &lt;ul&gt;&lt;li dir="ltr"&gt;Unpacked a bunch of stuff from the book's web site.  It includes code for all examples. &lt;/li&gt;&lt;li dir="ltr"&gt;Learned, from one of the downloaded textfiles, that I can run using a classpath with &lt;i&gt;java -cp&lt;/i&gt;. &lt;/li&gt;&lt;li dir="ltr"&gt;Hacked their ant &lt;span style="font-family: monospace;"&gt;build.xm&lt;/span&gt;l file to works with my &lt;i&gt;weatherstation &lt;/i&gt;data. &lt;/li&gt;&lt;li dir="ltr"&gt;Verified that ant, like make, notices times. &lt;/li&gt;&lt;li dir="ltr"&gt;Fixed an eclipse installation hiccup by paying attention to eclipse's output, which told me how to fix it. &lt;/li&gt;&lt;li dir="ltr"&gt;Put&lt;i&gt; weatherstation&lt;/i&gt; under git, and tried out &lt;i&gt;git commit --interactive&lt;/i&gt; &lt;/li&gt;&lt;li dir="ltr"&gt;Put all this into Tomboy Notes in a notebook called&lt;b&gt; hfp-diary&lt;/b&gt;, for an excuse to play with TN.  Tried out fonts, exporting to HTML, navigating menus with the keyboard. &lt;/li&gt;&lt;li dir="ltr"&gt;Successfully, though unintentionally, removed my entire project, including the git repository. :-(  After my hacking &lt;i&gt;&lt;span style="font-family: monospace;"&gt;build.xml&lt;/span&gt;&lt;/i&gt;, &lt;i&gt;ant clean&lt;/i&gt; wiped the entire directory. &lt;/li&gt;&lt;li dir="ltr"&gt;Copy the code over from the book, and experiment with various things in git, to try to keep from wiping out the code again. &lt;/li&gt;&lt;li dir="ltr"&gt;Get rid of the project lines, so that the sucker will compile and run. &lt;/li&gt;&lt;li dir="ltr"&gt;Figure out how to get a run configuration set up.  This is tedious, but I suppose I'll get used to it.&lt;/li&gt;&lt;/ul&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7053986551146704403?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7053986551146704403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7053986551146704403' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7053986551146704403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7053986551146704403'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/exporting-html-from-tomboy-notes.html' title='Exporting HTML from Tomboy Notes'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1810396230919165878</id><published>2008-07-26T05:39:00.002-06:00</published><updated>2008-07-26T05:51:58.459-06:00</updated><title type='text'>Character Mis-placement in Firefox</title><content type='html'>Can anyone tell me why the diacriticals in Hebrew-character fonts, like the ones in &lt;a href="http://inmolaraan.blogspot.com/2007/12/vodka-piecrust.html"&gt;this article&lt;/a&gt;, are misplaced, when I look at it in Firefox?&lt;br /&gt;&lt;br /&gt;If you look at words containing alephs, you'll see that most of them have a little mark underneath the character to its left.  The mark should be under the aleph itself.  This makes the words hard to read, and is a bit like having the dots on every 'i' appear over the following character.&lt;br /&gt;&lt;br /&gt;Background info, not directly relevant.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The text is in Yiddish, not Hebrew.  Yiddish is a Germanic language, like English, but uses the Hebrew alphabet for the same reason we use the Latin alphabet: the people who started writing the language picked an alphabet they already knew.  Hebrew-language text has the same problem.&lt;/li&gt;&lt;li&gt;The diacriticals are under the following character, not the preceding one.  Hebrew script, like this, is written right-to-left, not left-to-right.&lt;/li&gt;&lt;li&gt;The diacriticals change the character -- just like drawing a horizontal line across the top of an 'l' turns it into a 'T'.  One of the characters is silent, a second is an 'o', a third is an 'a'.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1810396230919165878?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1810396230919165878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1810396230919165878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1810396230919165878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1810396230919165878'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/character-mis-placement-in-firefox.html' title='Character Mis-placement in Firefox'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-4251699684704919648</id><published>2008-07-25T05:16:00.002-06:00</published><updated>2008-07-25T05:19:02.863-06:00</updated><title type='text'>ReviewBoard</title><content type='html'>&lt;a href="http://www.review-board.org"&gt;ReviewBoard&lt;/a&gt; seems to be getting some interest as an open-sourced code-review tool.  I like the slogan:&lt;br /&gt;&lt;h2 style="font-weight: normal; font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:100%;"&gt;Code reviews are fun again! ...almost.&lt;/span&gt;&lt;/blockquote&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-4251699684704919648?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/4251699684704919648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=4251699684704919648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4251699684704919648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/4251699684704919648'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/reviewboard.html' title='ReviewBoard'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1718252717161517321</id><published>2008-07-23T09:28:00.000-06:00</published><updated>2008-07-23T09:35:59.598-06:00</updated><title type='text'>3 Things</title><content type='html'>Get CC stuff reproducible.&lt;br /&gt;Fix LF build.&lt;br /&gt;Read through Randy's document.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1718252717161517321?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1718252717161517321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1718252717161517321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1718252717161517321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1718252717161517321'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/3-things.html' title='3 Things'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7537493566720287308</id><published>2008-07-21T06:39:00.003-06:00</published><updated>2008-07-21T06:50:23.916-06:00</updated><title type='text'>makemake</title><content type='html'>The newest "Plutoid" (almost a planet) is called &lt;a href="http://www.nytimes.com/2008/07/20/science/space/20plutoid.html?ex=1374292800&amp;amp;en=71e75a852ea4b652&amp;amp;ei=5124&amp;amp;partner=permalink&amp;amp;exprod=permalink"&gt;makemake&lt;/a&gt;.  The claim is that it's named after "a Polynesian creator of humanity and god of fertility."&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.fortran.com/makemake.perl"&gt;Oh, nonsense.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7537493566720287308?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7537493566720287308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7537493566720287308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7537493566720287308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7537493566720287308'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/makemake.html' title='makemake'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-97962923669901749</id><published>2008-07-21T05:09:00.003-06:00</published><updated>2008-07-21T05:20:45.403-06:00</updated><title type='text'>Eclipse and Design Patterns</title><content type='html'>I'm learning design patterns.  Frank Stahl told me, about a similar subject, "You sure do know how to have fun."&lt;br /&gt;&lt;br /&gt;Marcia Derr and I went to Caffe Sole yesterday, in the heat, and tried to slog through the very beginning of &lt;a href="http://oreilly.com/catalog/9780596007126/"&gt;&lt;span style="font-weight: bold;"&gt;Head First  Design Patterns&lt;/span&gt;&lt;/a&gt; by Eric Freeman, et al. (O'Reilly and Associates).&lt;br /&gt;&lt;br /&gt;The book is a little verbose and cutesy for all our tastes, but it's what we had.  Mostly, we just tried figuring out how to compile and run Java programs and how to use Eclipse.&lt;br /&gt;&lt;br /&gt;In the end, we got an example to run.  The second example, we're still stuck on; they seem to use a class they don't supply a definition of.&lt;br /&gt;&lt;br /&gt;Still, it was a pleasant way to spend a Sunday afternoon.  Frank Stahl told me, about a similar subject, "You sure do know how to have fun."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-97962923669901749?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/97962923669901749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=97962923669901749' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/97962923669901749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/97962923669901749'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/eclipse-and-design-patterns.html' title='Eclipse and Design Patterns'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-711091511168970684</id><published>2008-07-20T06:20:00.002-06:00</published><updated>2008-07-20T06:36:40.156-06:00</updated><title type='text'>Command-Line Tricks</title><content type='html'>I got diverted by &lt;a href="http://www.ukuug.org/events/linux2003/papers/bash_tips/"&gt;a presentation by Simon Myers&lt;/a&gt; this morning and have spent time messing around with the shell.&lt;br /&gt;&lt;br /&gt;I've used these before, and particularly like shell-expand-line for editing my path.&lt;br /&gt;&lt;br /&gt;Put this into &lt;span style="font-weight: bold;"&gt;~/.inputrc&lt;/span&gt; and arrange to re-read it (say, by starting a new shell).&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;$if Bash&lt;br /&gt;  Control-x: shell-expand-line&lt;br /&gt;$endif&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;Now you get this behavior from the shell (which is giving you command-line editing throug &lt;span style="font-style: italic;"&gt;readline(3&lt;/span&gt;) ).&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;$ PATH=$PATH&lt;br /&gt;&lt;span style="font-style: italic;"&gt;# now type control-x&lt;/span&gt;&lt;br /&gt;$ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/jsh/bin/bash_functions:/home/jsh/bin:/usr/local/libexec/git-core:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;# and the path is there, ready for editing&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;I can get a lot of his tricks to work, but I can't bind "yank-last-arg" in vi mode. Works fine in emacs mode (Meta-.), but I'm a vi guy.  I'm doing something wrong, but I don't know what.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-711091511168970684?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/711091511168970684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=711091511168970684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/711091511168970684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/711091511168970684'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/command-line-tricks.html' title='Command-Line Tricks'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-1747965650914766260</id><published>2008-07-18T05:07:00.003-06:00</published><updated>2008-07-18T05:17:29.740-06:00</updated><title type='text'>A Tool With Many Uses: The Local Yum Server</title><content type='html'>I've set up a yum server, at work.  This achieves several ends:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It lets us mirror the Fedora distro we're using locally, so we can pull and update packages faster.&lt;/li&gt;&lt;li&gt;It gives us a single place to stick third-party rpms.  No more asking developers to "go out and get package X from web site Y."&lt;/li&gt;&lt;li&gt;It gives me a single distribution point for things I produce.  I don't have to give developers a login on my box, or find a common server to ftp things to and from, I can just stick an rpm on the server and have them install it with yum.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-1747965650914766260?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/1747965650914766260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=1747965650914766260' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1747965650914766260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/1747965650914766260'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/setting-up-yum-server.html' title='A Tool With Many Uses: The Local Yum Server'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-3685732943562966396</id><published>2008-07-17T05:07:00.003-06:00</published><updated>2008-07-17T05:17:11.824-06:00</updated><title type='text'>Expanding Windows, a Mouse-Click at a Time</title><content type='html'>I accidentally learned how to maximize my windows in just one direction: click a different mouse button.&lt;br /&gt;&lt;br /&gt;At least in Gnome, clicking the "maximize window" decoration with the left mouse button expands it to the size of the screen (if the app permits).&lt;br /&gt;&lt;br /&gt;However, clicking the same decoration with the right mouse button expands it horizontally, to the width of the screen, and clicking with the middle mouse button maximizes it vertically.&lt;br /&gt;&lt;br /&gt;Paired, sequentially (right click, middle click) they act like a single left click.  Indeed, they work the way you'd think in all combinations.&lt;br /&gt;&lt;br /&gt;Cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-3685732943562966396?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/3685732943562966396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=3685732943562966396' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3685732943562966396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/3685732943562966396'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/expanding-windows-mouse-click-at-time.html' title='Expanding Windows, a Mouse-Click at a Time'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-7672055905216299640</id><published>2008-07-16T08:50:00.002-06:00</published><updated>2008-07-16T09:17:13.966-06:00</updated><title type='text'>Setting Defaults Properly</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Problem:&lt;/span&gt; I have a new developer who wants to check something into &lt;a href="http://en.wikipedia.org/wiki/Subversion_%28software%29"&gt;Subversion&lt;/a&gt;.  He tries, and is mystified by &lt;span style="font-style: italic;"&gt;svn&lt;/span&gt;'s message, telling him he has to set the environment variable &lt;span style="font-style: italic;"&gt;$EDITOR&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Solution:&lt;/span&gt; I tell him to set the environment variable.&lt;br /&gt;&lt;br /&gt;(Okay, this should read &lt;span style="font-style: italic;"&gt;"Problem: My software developers can't read.&lt;/span&gt;"  It's still a problem.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Git_%28software%29"&gt;&lt;span style="font-weight: bold;"&gt;git&lt;/span&gt;&lt;/a&gt;, in contrast, has this one figured out.  From the &lt;span style="font-weight: bold;"&gt;git-config&lt;/span&gt; man page:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;       core.editor&lt;br /&gt;     Commands such as commit and tag that lets you edit messages by&lt;br /&gt;     launching an editor uses the value of this variable when it is set,&lt;br /&gt;     and the environment variable GIT_EDITOR is not set. The order of&lt;br /&gt;     preference is GIT_EDITOR environment, core.editor, VISUAL and&lt;br /&gt;     EDITOR environment variables and then finally vi.&lt;/span&gt;&lt;/blockquote&gt;Yes, it isn't quite grammatical.  The author's Finnish.  Give him a break.  "... and then finally vi."  This because every Posix-conforming system is required to have a text editor named &lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/Vi"&gt;vi&lt;/a&gt; that acts according to the IEEE spec.  (It can be a superset, like &lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/Gvim"&gt;gvim&lt;/a&gt;, but it has to respond correctly to the basic commands.)&lt;br /&gt;&lt;br /&gt;Richard Stallman and the FSF were asked for an &lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/Emacs"&gt;emacs&lt;/a&gt; spec to put into Posix (&lt;a href="http://en.wikipedia.org/wiki/Posix"&gt;Stallman named Posix&lt;/a&gt;, by the way), but they refused, so there's no guarantee that a Posix-conforming system will have it, out of the box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-7672055905216299640?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/7672055905216299640/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=7672055905216299640' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7672055905216299640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/7672055905216299640'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/setting-defaults-properly.html' title='Setting Defaults Properly'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-2811978814658207353</id><published>2008-07-16T05:04:00.002-06:00</published><updated>2008-07-16T05:33:31.904-06:00</updated><title type='text'>A Twisty Maze of Symlinks, All Different: readlink -f</title><content type='html'>Which of the &lt;span style="font-style: italic;"&gt;vi&lt;/span&gt; clones on your system are you using?  Do you know?&lt;br /&gt;&lt;br /&gt;In Linux, when more than one installed executable could reasonably have the same name  a common solution is to make the executable in &lt;span style="font-style: italic;"&gt;/bin&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;/usr/bin&lt;/span&gt; a symlink to an entry in &lt;span style="font-style: italic;"&gt;/etc/alternatives&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;/etc/alternatives&lt;/span&gt; entry, in its turn, symlinks to the real executable.  Or, maybe to another symlink to ...&lt;br /&gt;&lt;br /&gt;Finding the ultimate executable in this twisty maze of symlinks, all different, can be an &lt;a href="http://en.wikipedia.org/wiki/Adventure_%28computer_game%29#Maze_of_twisty_little_passages"&gt;Adventure&lt;/a&gt;.  The solution?  &lt;span style="font-style: italic;"&gt;readlink&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Here's an example, with &lt;span style="font-style: italic;"&gt;java&lt;/span&gt;:&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:85%;"&gt;$ which java&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;/usr/bin/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ ls -l /usr/bin/java&lt;/span&gt;&lt;br /&gt;lrwxrwxrwx 1 root root 22 2007-11-05 15:14 /usr/bin/java -&gt; /etc/alternatives/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ ls -l /etc/alternatives/java&lt;/span&gt;&lt;br /&gt;lrwxrwxrwx 1 root root 36 2008-04-26 07:10 /etc/alternatives/java -&gt; /usr/lib/jvm/java-6-sun/jre/bin/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ ls -l /usr/lib/jvm/java-6-sun/jre/bin/java&lt;/span&gt;&lt;br /&gt;-rwxr-xr-x 1 root root 47116 2008-03-25 03:01 /usr/lib/jvm/java-6-sun/jre/bin/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ readlink -f /usr/bin/java&lt;/span&gt;&lt;br /&gt;/usr/lib/jvm/java-6-sun-1.6.0.06/jre/bin/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ readlink -f $(which java)&lt;/span&gt;&lt;br /&gt;/usr/lib/jvm/java-6-sun-1.6.0.06/jre/bin/java&lt;/span&gt;&lt;/blockquote&gt;Beware: &lt;span style="font-style: italic;"&gt;readlink&lt;/span&gt; won't warn you if something's not a symlink (okay) or doesn't exist (not okay):&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;$ ls -l /home/jsh/java&lt;/span&gt;&lt;br /&gt;ls: cannot access /home/jsh/java: No such file or directory&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ readlink -f /home/jsh/java&lt;/span&gt;&lt;br /&gt;/home/jsh/java&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$ echo $?&lt;/span&gt;&lt;br /&gt;0&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-2811978814658207353?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/2811978814658207353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=2811978814658207353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2811978814658207353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/2811978814658207353'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/twisty-maze-of-symlinks-all-different.html' title='A Twisty Maze of Symlinks, All Different: readlink -f'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8872817900941149635.post-5989565692660281758</id><published>2008-07-11T05:49:00.003-06:00</published><updated>2008-12-13T01:46:43.418-07:00</updated><title type='text'>Tom Tromey and Stormy Peters</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_eqYJM_T8b24/SHrTAea2LnI/AAAAAAAAAeQ/5KGlAaSQMBA/s1600-h/Image002.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_eqYJM_T8b24/SHrTAea2LnI/AAAAAAAAAeQ/5KGlAaSQMBA/s400/Image002.jpg" alt="" id="BLOGGER_PHOTO_ID_5222718723008638578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_eqYJM_T8b24/SHrTAcWZ1CI/AAAAAAAAAeY/3hSyNEKvR9M/s1600-h/Image003.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_eqYJM_T8b24/SHrTAcWZ1CI/AAAAAAAAAeY/3hSyNEKvR9M/s400/Image003.jpg" alt="" id="BLOGGER_PHOTO_ID_5222718722453132322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Tom Tromey did a fun &lt;a href="http://lug.boulder.co.us"&gt;BLUG&lt;/a&gt; talk about &lt;a href="http://en.wikipedia.org/wiki/Emacs"&gt;emacs&lt;/a&gt; last night, with slides he did in, well, you know, emacs.&lt;br /&gt;&lt;br /&gt;As you can see from the pictures, it's all downhill from here.&lt;br /&gt;&lt;br /&gt;He recommends the &lt;a href="http://www.emacswiki.org/cgi-bin/wiki"&gt;emacs wiki&lt;/a&gt;, which is created with &lt;a href="http://www.emacswiki.org/cgi-bin/wiki/EmacsWikiMode"&gt;EmacsWikiMode&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tom's worked on a pile of stuff over the years, including the Gnu Java compiler, and both automake and autoconf.&lt;br /&gt;&lt;br /&gt;Perhaps the video will be up soon.  I hope it does as much for his career as&lt;a href="http://video.google.com/videoplay?docid=-3678508430633344244&amp;amp;hl=en"&gt; her recent talk at BLUG&lt;/a&gt; did for &lt;a href="http://lwn.net/Articles/288892/rss"&gt;Stormy Peters&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What's the hardest thing about switching from emacs?  Getting the deposit back when you return a garage full of empty Alt-Meta-Cokebottles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8872817900941149635-5989565692660281758?l=seejeffrun.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seejeffrun.blogspot.com/feeds/5989565692660281758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8872817900941149635&amp;postID=5989565692660281758' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5989565692660281758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8872817900941149635/posts/default/5989565692660281758'/><link rel='alternate' type='text/html' href='http://seejeffrun.blogspot.com/2008/07/tom-tromey-and-stormy-peters.html' title='Tom Tromey and Stormy Peters'/><author><name>goyishekop</name><uri>http://www.blogger.com/profile/18016285119774805016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_eqYJM_T8b24/R9gJB5c1h2I/AAAAAAAAATk/2wOR6t5SeEE/S220/foo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_eqYJM_T8b24/SHrTAea2LnI/AAAAAAAAAeQ/5KGlAaSQMBA/s72-c/Image002.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
