<?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-18543508</id><updated>2011-04-21T18:21:40.699-07:00</updated><title type='text'>Shell Shul</title><subtitle type='html'>If I go for a day without learning something, I get the shakes.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><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>36</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18543508.post-113651814814135565</id><published>2006-01-06T19:26:00.000-08:00</published><updated>2006-01-05T19:47:45.716-08:00</updated><title type='text'>Using the Return Value</title><content type='html'>Functions, like programs, succeed or fail.  That's what &lt;em&gt;$?&lt;/em&gt; is about. (At the shell level, &lt;em&gt;$?&lt;/em&gt; tells whether the last command succeeded or failed. Here, as far as the shell is concerned, the function is just like a command.)&lt;br /&gt;&lt;br /&gt;This means that if you have a function to check out and build code&lt;blockquote&gt;&lt;pre&gt;get-N-make() {&lt;br /&gt; svn co $*&lt;br /&gt; (&lt;br /&gt;  cd $_&lt;br /&gt;  make&lt;br /&gt; )&lt;br /&gt;} &amp;&gt; /dev/null&lt;/pre&gt;&lt;/blockquote&gt;You can call it like this:&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;get-N-make -Dyesterday mycode ||&lt;br /&gt; die "something in the checkout or build failed"&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;(Notice that you can redirect the output of a function as part of its definition.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651814814135565?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651814814135565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651814814135565&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651814814135565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651814814135565'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/using-return-value.html' title='Using the Return Value'/><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-18543508.post-113651799811211468</id><published>2006-01-05T20:00:00.000-08:00</published><updated>2006-01-05T19:49:23.246-08:00</updated><title type='text'>The Return of the Value</title><content type='html'>Okay, so the only way to return a value from a function is with a side effect. What the heck do you do to return values?&lt;br /&gt;&lt;br /&gt;One option is to have the function create real output and capture it.&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;date_diff() {&lt;br /&gt; t2=$(date -d "$1" +%s)&lt;br /&gt; t1=$(date -d "$2" +%s)&lt;br /&gt; echo $((t1-t2))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;secs=$(date_diff "Dec 25" "now")&lt;br /&gt;echo "$secs more shopping seconds until Christmas"&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;This works, but costs the execution of a subshell each time you call the function.  A more efficient approach is to capture output in a global, and use a naming convention to keep from accidentally stepping on a some other variable with the same name.&lt;br /&gt;&lt;br /&gt;I've seen a handful, but I like this:&lt;blockquote&gt;&lt;pre&gt;date_diff() {&lt;br /&gt; t2=$(date -d "$1" +%s)&lt;br /&gt; t1=$(date -d "$2" +%s)&lt;br /&gt; _date_diff=$((t1-t2))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;date_diff &lt;br /&gt;echo "$_date_diff more shopping seconds until Christmas"&lt;/pre&gt;&lt;/blockquote&gt;Try using the name of the function, preceded by an underscore, to hold the return value of the latest call.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651799811211468?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651799811211468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651799811211468&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651799811211468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651799811211468'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/return-of-value.html' title='The Return of the Value'/><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-18543508.post-113651782356550063</id><published>2006-01-04T20:00:00.000-08:00</published><updated>2006-01-05T19:50:42.280-08:00</updated><title type='text'>Functions Don't Return Values</title><content type='html'>Functions really don't return values.  Really.  That's hard to get used to. The shell does have a &lt;i&gt;return()&lt;/i&gt; call, but it doesn't do what you'd guess.&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;jo_mamma() {&lt;br /&gt; return 69&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;fezmo=jo_mamma&lt;br /&gt;echo fezmo is $fezmo&lt;br /&gt;&lt;br /&gt;# No?  Well, what if we reason by analogy and use $() to call the function?&lt;br /&gt;&lt;br /&gt;fezmo=$(jo_mamma)&lt;br /&gt;echo fezmo is $fezmo&lt;br /&gt;&lt;br /&gt;# Still no.  But look at this:&lt;br /&gt;&lt;br /&gt;jo_mamma&lt;br /&gt;echo after call, status is $?&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;em&gt;return()&lt;/em&gt; returns from a function call and sets the predefined variable, &lt;em&gt;$?&lt;/em&gt; -- the &lt;i&gt;"exit status."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Even this isn't as useful as you'd hope.  Substitute a string for the "69" in the example to see what happens.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651782356550063?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651782356550063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651782356550063&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651782356550063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651782356550063'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/functions-dont-return-values.html' title='Functions Don&apos;t Return 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-18543508.post-113651769441040361</id><published>2006-01-03T20:00:00.000-08:00</published><updated>2006-01-05T19:51:51.566-08:00</updated><title type='text'>Functions Can Set Globals</title><content type='html'>The title says it all.  Shell variables are global by default.&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;fezmo=6&lt;br /&gt;jo_mamma() {&lt;br /&gt; fezmo=9&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;echo before call fezmo is $fezmo&lt;br /&gt;jo_mamma&lt;br /&gt;echo after call fezmo is $fezmo&lt;/pre&gt;&lt;/blockquote&gt;That means that you have to keep track of the names of every variable you set in a function.  Bummer.  Shell scripts aren't typically very long, so this usually isn't a big deal. Still, using &lt;em&gt;local&lt;/em&gt; inside functions is a good habit to get into.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;fezmo=6&lt;br /&gt;jo_mamma() {&lt;br /&gt; local fezmo=9&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;echo before call fezmo is $fezmo&lt;br /&gt;jo_mamma&lt;br /&gt;echo after call fezmo is $fezmo&lt;/pre&gt;&lt;/blockquote&gt; (Don't just read these examples and nod your head.  Use snarf-N-barf to try them.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651769441040361?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651769441040361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651769441040361&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651769441040361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651769441040361'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/functions-can-set-globals.html' title='Functions Can Set Globals'/><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-18543508.post-113651737430897270</id><published>2006-01-02T20:00:00.000-08:00</published><updated>2006-01-05T19:30:43.056-08:00</updated><title type='text'>Design by Analogy</title><content type='html'>Here's a function that's in almost every shell script I write:&lt;blockquote&gt;&lt;pre&gt;die() {&lt;br /&gt; echo $* &gt;&amp;2 ; exit -1;&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;The syntax is straightforward and obvious.  &lt;em&gt;$*&lt;/em&gt; is the list of&lt;br /&gt;arguments passed to die() by the caller.  The call&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;die "usage: foobar mumble frabitz"&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;spits a usage message to stderr and then ends the program.&lt;br /&gt;&lt;br /&gt;Why call it "&lt;em&gt;die()&lt;/em&gt;"? Because that's what the corresponding Perl&lt;br /&gt;function is called.&lt;br /&gt;&lt;br /&gt;Designing things to mimic one another is a good habit.  To link&lt;br /&gt;&lt;code&gt;bar&lt;/code&gt; to &lt;code&gt;foo&lt;/code&gt;, do you say &lt;code&gt;ln foo bar&lt;/code&gt; or&lt;br /&gt;&lt;code&gt;ln bar foo&lt;/code&gt;?  It's easier to remember once you know that &lt;b&gt;cp&lt;/b&gt;,&lt;br /&gt;&lt;b&gt;mv&lt;/b&gt;, and &lt;b&gt;ln&lt;/b&gt; all use the same argument order.  Similarly, once you&lt;br /&gt;know &lt;code&gt;rm -i&lt;/code&gt;, you're more likely to guess that &lt;code&gt;cp -i&lt;/code&gt;,&lt;br /&gt;&lt;code&gt;mv -i&lt;/code&gt;, and &lt;code&gt;ln -i&lt;/code&gt; all work, too.&lt;br /&gt;&lt;br /&gt;The drawback is that you need to remember that the copy isn't exactly the same&lt;br /&gt;as the original.  For example, Perl's &lt;em&gt;die()&lt;/em&gt; spits out additional&lt;br /&gt;information unless the argument string ends with a carriage return.  In&lt;br /&gt;practice, I don't find this a disadvantage.  If you do, you could name yours&lt;br /&gt;&lt;em&gt;s.die()&lt;/em&gt; or something.&lt;br /&gt;&lt;br /&gt;For example, &lt;em&gt;$*&lt;/em&gt; in a function is all the args to a function; in a&lt;br /&gt;shell script, it's all the args to the script.  &lt;em&gt;$1&lt;/em&gt;, &lt;em&gt;$2&lt;/em&gt;, etc.&lt;br /&gt;are the individual args to a script.  Guess what &lt;em&gt;$1&lt;/em&gt; is inside a&lt;br /&gt;function.&lt;br /&gt;&lt;br /&gt;But don't just guess.  Try it.  And try writing a &lt;em&gt;warn()&lt;/em&gt; function to&lt;br /&gt;mimic Perl's.  If you don't know Perl, try writing a shell analogue to some&lt;br /&gt;other useful thing you know from another language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651737430897270?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651737430897270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651737430897270&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651737430897270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651737430897270'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/design-by-analogy.html' title='Design by Analogy'/><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-18543508.post-113651710611716793</id><published>2006-01-01T20:00:00.000-08:00</published><updated>2006-01-05T19:11:46.140-08:00</updated><title type='text'>Functions</title><content type='html'>Well, I'm back from the holidays.  Hope yours were fun.  This week: shell functions.&lt;br /&gt;&lt;br /&gt;Macros, subroutines, procedures, functions ..., a programming language needs some way a way to encapsulate repeated actions.&lt;br /&gt;&lt;br /&gt;The shell calls 'em functions.  An academic might say a function should return a value, while a subroutine works through its side-effects.   Unfortunately, shell functions mostly work through their side effects.  Oh well.&lt;br /&gt;&lt;br /&gt;They're still very useful little things, and you can use them a lot, to good effect.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113651710611716793?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113651710611716793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113651710611716793&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651710611716793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113651710611716793'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2006/01/functions.html' title='Functions'/><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-18543508.post-113442231247976051</id><published>2005-12-16T20:00:00.000-08:00</published><updated>2006-01-05T19:54:40.230-08:00</updated><title type='text'>Grow a Command, Then Execute It</title><content type='html'>Let's make a copy of all the files under /etc/ that contain references to &lt;b&gt;httpd&lt;/b&gt;, the Apache http daemon.&lt;br /&gt;&lt;br /&gt;First, a directory to hold the copies:&lt;blockquote&gt;&lt;pre&gt;mkdir /tmp/Apachefiles&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Next, we'll construct the commands, on the fly, by growing a pipeline.  Follow along with me by executing these in a terminal window.  For each step, just recall the previous line and edit it.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;find /etc/ # list all the files under /etc.&lt;br /&gt;find /etc/ | xargs grep -l httpd # look for all those files that contain the string httpd&lt;br /&gt;{ find /etc/ | xargs grep -l httpd; } 2&gt;/dev/null # get rid of annoying warnings&lt;br /&gt;# now transform the list into a series of commands&lt;br /&gt;{ find /etc/ | xargs grep -l httpd; } 2&gt;/dev/null |&lt;br /&gt; perl -lane 'print "cp $_ /tmp/Apachefiles/"'&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Okay, these look good.  (I've left out all the mistakes I made while developing the pipeline, because I know you would never make any.  I do, so command history is my friend.)&lt;br /&gt;&lt;br /&gt;Now, how about executing it?  We could redirect the output into a file, mark the file as executable, and then execute it as a script.&lt;br /&gt;&lt;br /&gt;Or we could just add one step to the pipeline, like this:&lt;blockquote&gt;&lt;pre&gt;{ find /etc/ | xargs grep -l httpd; } 2&gt;/dev/null |&lt;br /&gt; perl -lane 'print "cp $_ /tmp/Apachefiles/"' | bash&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;I frequently grow a set of commands like this, on the fly, then when I have them right, pipe them into a subshell, which will execute them, one by one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442231247976051?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442231247976051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442231247976051&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442231247976051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442231247976051'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/grow-command-then-execute-it.html' title='Grow a Command, Then Execute 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-18543508.post-113442208787391695</id><published>2005-12-15T20:00:00.000-08:00</published><updated>2005-12-12T13:20:30.643-08:00</updated><title type='text'>Command Substitution for Counted Loops</title><content type='html'>Here's a loop.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20&lt;br /&gt;do&lt;br /&gt;    echo $i&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Here's another way to do the same thing: &lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;for i in $(seq 20)&lt;br /&gt;do&lt;br /&gt;    echo $i&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Just the command &lt;code&gt;seq 20&lt;/code&gt; by itself spits out the sequence 1 .. 20 .  (Try it.)&lt;br /&gt;&lt;br /&gt;The expression &lt;code&gt;$(command)&lt;/code&gt; says "Run &lt;i&gt;command&lt;/i&gt; in a subshell,&lt;br /&gt;substitute its output for the expression, and then run the resulting command in the current shell."&lt;br /&gt;&lt;br /&gt;This is called &lt;b&gt;&lt;i&gt;command substitution&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Since "$" marks variables, think of $(command) as "The value of the temporary variable containing the output of the subshell '(command)'"&lt;br /&gt;&lt;br /&gt;You have a mystery version of &lt;b&gt;foo.c&lt;/b&gt; and you want to know what archival version it's closest to?&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;for i in $(seq 10 -1 1)&lt;br /&gt;do&lt;br /&gt;    cvs co -p -r1.$i foo.c | diff - foo.c | wc -l&lt;br /&gt;done &lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;The version with the smallest diff is the version you're looking for.&lt;br /&gt;&lt;br /&gt;If you have a very large number of versions, you can pipe the loop's output through &lt;b&gt;less&lt;/b&gt;.  Alternatively, if you're using a terminal emulator, you can use the scroll bar to scroll back up the screen, or, in &lt;b&gt;kterm&lt;/b&gt;, the convenient &lt;i&gt;Shift PgUp&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442208787391695?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442208787391695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442208787391695&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442208787391695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442208787391695'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/command-substitution-for-counted-loops.html' title='Command Substitution for Counted 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-18543508.post-113442173770082977</id><published>2005-12-14T20:00:00.000-08:00</published><updated>2005-12-12T13:21:20.570-08:00</updated><title type='text'>Get Scope With Subshells</title><content type='html'>You can tell the shell to execute a few commands in a subshell by surrounding them with parens:&lt;blockquote&gt;&lt;pre&gt;pwd; ( cd /tmp; pwd }; pwd&lt;/pre&gt;&lt;/blockquote&gt;You change directories in the subshell, but once you exit that subshell, the original shell hasn't gone anywhere.&lt;br /&gt;&lt;br /&gt;This is particularly useful for scripts where you want to go somewhere and do something, temporarily. My scripts are chock-a-block full of code like this:&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;cvs -Q co modulename&lt;br /&gt;(&lt;br /&gt;    cd modulename&lt;br /&gt;    make&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Don't confuse this with curly braces, which group commands in the current&lt;br /&gt;shell:&lt;blockquote&gt;&lt;pre&gt;pwd; { cd /tmp; pwd; }; pwd&lt;/pre&gt;&lt;/blockquote&gt;The two kinds of grouping are for two different things.  Curlies are good when you want to do I/O redirection of groups of commands.  Parens are good when you want to insulate a parent shell from a bunch of temporary changes, without having to save and restore context by hand.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442173770082977?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442173770082977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442173770082977&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442173770082977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442173770082977'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/get-scope-with-subshells.html' title='Get Scope With Subshells'/><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-18543508.post-113442149933326515</id><published>2005-12-13T20:00:00.000-08:00</published><updated>2005-12-12T13:22:22.226-08:00</updated><title type='text'>Use pstree to See Your Tree of Subshells</title><content type='html'>Execute the command &lt;code&gt;csh&lt;/code&gt;.  The prompt changes!  You are now running an older shell, csh, that has a different syntax.  Try, for example, typing in a comment, like this&lt;blockquote&gt;&lt;pre&gt;# this is a comment &lt;/pre&gt;&lt;/blockquote&gt;This new shell is a subshell of the bash you were talking to a minute ago. Exit the subshell, and you'll see you're back in the parent shell.  You can see&lt;br /&gt;this with the &lt;b&gt;ps&lt;/b&gt; command.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;ps -o pid,ppid,args&lt;br /&gt;csh&lt;br /&gt;ps -o pid,ppid,args&lt;br /&gt;exit&lt;br /&gt;ps -o pid,ppid,args&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Each running program is a &lt;i&gt;process&lt;/i&gt;, with an identifying number, or Process ID.  If that process is a subprocess of some other program, then the &lt;b&gt;ps&lt;/b&gt; command shown above also shows the Parent Process ID.&lt;br /&gt;&lt;br /&gt;You should be able to trace out what's a child of what in the listings above, pretty easily.&lt;br /&gt;&lt;br /&gt;Actually, in Linux, every process is the child of another process, except for the very first process, which is called init.  Look:&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;pstree -A -p | less&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;The numbers in parens are PIDs.  Try invoking some subshells and watch how the process tree changes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442149933326515?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442149933326515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442149933326515&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442149933326515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442149933326515'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/use-pstree-to-see-your-tree-of.html' title='Use pstree to See Your Tree of Subshells'/><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-18543508.post-113442123427180534</id><published>2005-12-12T12:57:00.000-08:00</published><updated>2005-12-12T13:23:08.500-08:00</updated><title type='text'>You Can Invoke the Shell By Hand</title><content type='html'>You invoke a shell the same way you invoke any other program: type its name.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;bash&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;You get back a prompt, but now this is a second shell, a subshell under the previous shell.  The shell you were running a minute ago is now patiently waiting for this subshell to finish, so it can put up another prompt and let you issue some other command.&lt;br /&gt;&lt;br /&gt;See for yourself?  Type &lt;code&gt;exit&lt;/code&gt;.  You'll exit this subshell, and return to the shell a level up.  You're back in the shell you started from.&lt;br /&gt;&lt;br /&gt;Want more convincing?  Type &lt;code&gt;history&lt;/code&gt;.  That's your current shell. Now execute a subshell, and look at the history again:&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;bash&lt;br /&gt;history&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Finally, exit the subshell, and look at the history again: &lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;exit&lt;br /&gt;history&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;You get two different histories because it's two different shells.&lt;br /&gt;&lt;br /&gt;If you execute commands, then spawn a subshell, and then try to recall the commands you were just executing before you entered the subshell, you won't find them.&lt;br /&gt;&lt;br /&gt;It's important that you have a firm grasp on the idea of subshells before you continue, so I'll return to this, tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442123427180534?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442123427180534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442123427180534&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442123427180534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442123427180534'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/you-can-invoke-shell-by-hand.html' title='You Can Invoke the Shell By Hand'/><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-18543508.post-113442102509267572</id><published>2005-12-11T20:00:00.000-08:00</published><updated>2005-12-12T13:24:30.263-08:00</updated><title type='text'>Subshells</title><content type='html'>The shell is just a program.  It's not wired into the kernel.  Many programmers who've been in the business for a while have written a shell, for their own amusement.  If you haven't, you can imagine the pseudocode.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;while (1) {&lt;br /&gt;    put up a prompt&lt;br /&gt;    read the line the user types in&lt;br /&gt;    parse the line&lt;br /&gt;    execute any commands you find&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Thinking of the shell as just another program, no different from &lt;b&gt;ls&lt;/b&gt; or &lt;b&gt;date&lt;/b&gt; or &lt;b&gt;cc&lt;/b&gt;, is a big help in dealing with the shell.&lt;br /&gt;&lt;br /&gt;This week, I'll explore that a little.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113442102509267572?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113442102509267572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113442102509267572&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442102509267572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113442102509267572'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/subshells.html' title='Subshells'/><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-18543508.post-113400455786986951</id><published>2005-12-09T08:00:00.000-08:00</published><updated>2005-12-08T18:52:43.706-08:00</updated><title type='text'>Ancient History?  RTFM</title><content type='html'>Just as our bodies have little, atavistic features that recapitulate our phylogeny, so does the shell.  Back when dinosaurs roamed the earth, there was a shell called the "C shell" (cute name, eh?), that had a clumsy-but-complex history mechanism built around the &lt;span style="font-weight:bold;"&gt;!&lt;/span&gt; key.  Bash retains that mechanism, alongside its more modern one.&lt;br /&gt;&lt;br /&gt;About the only useful thing left from it is &lt;span style="font-weight:bold;"&gt;!!&lt;/span&gt;, which means "redo the last command."&lt;br /&gt;&lt;br /&gt;If you want to read about it, though, see the man page.&lt;blockquote&gt;&lt;code&gt;man bash&lt;/code&gt;&lt;/blockquote&gt;Impressive, huh?&lt;br /&gt;&lt;br /&gt;I don't just mean the &lt;code&gt;HISTORY EXPANSION&lt;/code&gt; section, which is 120 lines, starting around line 3172 on my machine.  I mean the fact that the man page is over 3000 lines long.  (Mine's close to 5000).  There's a lot there.&lt;br /&gt;&lt;br /&gt;It's usually easier to read a man page this big in a text editor, so stash a copy somewhere.  Send it through &lt;span style="font-style:italic;"&gt;col&lt;/span&gt; first, to remove funny characters.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;man bash | col -b &gt; /tmp/bash.man&lt;br /&gt;vi /tmp/bash.man +/"^HISTORY EXPANSION"&lt;/pre&gt;&lt;/blockquote&gt;On tomorrow, the seventh day, you should rest.  The day after, I'll start to grade insensibly into more advanced topics: I'll talk a bit about processes, and how to handle them in the shell.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113400455786986951?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400455786986951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400455786986951&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400455786986951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400455786986951'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/ancient-history-rtfm.html' title='Ancient History?  RTFM'/><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-18543508.post-113400423822313667</id><published>2005-12-08T08:00:00.000-08:00</published><updated>2005-12-08T13:05:54.466-08:00</updated><title type='text'>Command-line Comments</title><content type='html'>Shell comments start with &lt;span style="font-weight:bold;"&gt;#&lt;/span&gt;.  Important for scripts, but useless on the command-line, right?  Wrong.&lt;br /&gt;&lt;br /&gt;Suppose you've typed most of a line, but you need to stop and check on something -- how some file or command is spelled, for example.&lt;br /&gt;&lt;br /&gt;Just go to the beginning of the line (&lt;span style="font-weight:bold;"&gt;Home&lt;/span&gt;), type a &lt;span style="font-weight:bold;"&gt;#&lt;/span&gt;, and press &lt;span style="font-weight:bold;"&gt;Enter&lt;/span&gt;. What happens?  Nothing.  It's a comment.&lt;br /&gt;&lt;br /&gt;But it goes into the history.  When you've finished checking on whatever it was, recall the command, make any needed modifications, delete the &lt;span style="font-weight:bold;"&gt;#&lt;/span&gt;, and press &lt;span style="font-weight:bold;"&gt;Enter&lt;/span&gt; again.  Voila!&lt;br /&gt;&lt;br /&gt;If you're using &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt;-style editing, use &lt;span style="font-weight:bold;"&gt;Esc&lt;/span&gt; to switch to command mode, then type the command &lt;span style="font-weight:bold;"&gt;#&lt;/span&gt;.  Bash will insert a &lt;span style="font-weight:bold;"&gt;#&lt;/span&gt; at the beginning of the line and give you a new prompt for the next command.&lt;br /&gt;&lt;br /&gt;In otherwords,&lt;br /&gt;&lt;blockquote&gt;emacs: &lt;span style="font-weight:bold;"&gt;Home # Enter&lt;/span&gt;&lt;br /&gt;vi: &lt;span style="font-weight:bold;"&gt;Escape #&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/18543508-113400423822313667?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400423822313667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400423822313667&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400423822313667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400423822313667'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/command-line-comments.html' title='Command-line 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-18543508.post-113400395287755226</id><published>2005-12-07T08:00:00.000-08:00</published><updated>2005-12-08T13:05:30.043-08:00</updated><title type='text'>History at Full Speed</title><content type='html'>If the command-line editor is really a full-featured history editor, then history should be searchable.&lt;br /&gt;&lt;br /&gt;Is this possible?  Yes sirree.&lt;br /&gt;&lt;br /&gt;In &lt;span style="font-style:italic;"&gt;emacs&lt;/span&gt; mode, type &lt;span style="font-weight:bold;"&gt;^R&lt;/span&gt;, then start typing the string you're looking for. You'll get the normal, emacs incremental search.  If you find the string you want, but it's not the command you want, press &lt;span style="font-weight:bold;"&gt;^R&lt;/span&gt; again to get the next instance.&lt;br /&gt;&lt;br /&gt;In &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; mode, use &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt;'s search command, &lt;span style="font-weight:bold;"&gt;/&lt;/span&gt;.  Find the next command containing that string with &lt;span style="font-weight:bold;"&gt;n&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If there's a command you issued a few minutes ago and you want to bring it back, you don't have to type up-arrow after up-arrow to find it.  You can recall it by just typing in a few characters from the command and searching.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; doesn't have incremental search, but it turns out that some of the &lt;span style="font-style:italic;"&gt;emacs&lt;/span&gt;-mode commands, like &lt;span style="font-weight:bold;"&gt;^R&lt;/span&gt;, still work in &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt;-mode, so it's often worth trying them.&lt;br /&gt;&lt;br /&gt;No, this isn't logical.  Oh, well.&lt;br /&gt;&lt;br /&gt;Happy Pearl Harbor Day!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113400395287755226?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400395287755226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400395287755226&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400395287755226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400395287755226'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/history-at-full-speed.html' title='History at Full Speed'/><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-18543508.post-113400374450221199</id><published>2005-12-06T08:00:00.000-08:00</published><updated>2005-12-08T19:01:55.706-08:00</updated><title type='text'>Editor Choice</title><content type='html'>If you prefer &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; to &lt;span style="font-style:italic;"&gt;emacs&lt;/span&gt;, do this: &lt;code&gt;set -o vi&lt;/code&gt; (If you're just experimenting, &lt;code&gt;set -o emacs&lt;/code&gt; gets you back to emacs mode.)&lt;br /&gt;&lt;br /&gt;Me, I use vi-mode in the shell.  I've been using &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; for so long, it's in my firmware. I don't have to think about how to edit files with &lt;span style="font-style:italic;"&gt;vi&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt;, it just comes out of my fingers.  Editing command lines comes just as naturally.&lt;br /&gt;&lt;br /&gt;Do remember that &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; is a modal editor.  When you begin to type, you're in insert mode.  To get to command mode, type &lt;span style="font-weight:bold;"&gt;Esc&lt;/span&gt;.  Once you're in command mode, the familiar &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; commands just work.  End of line? &lt;span style="font-weight:bold;"&gt;$&lt;/span&gt;  Beginning of line?  &lt;span style="font-weight:bold;"&gt;^&lt;/span&gt;. Back two words? &lt;span style="font-weight:bold;"&gt;2b&lt;/span&gt;. Change the word under the cursor? &lt;span style="font-weight:bold;"&gt;cw&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;As soon as you type &lt;span style="font-weight:bold;"&gt;Enter&lt;/span&gt;, the current line, as you see it, is handed to the shell and executed.  You're put back in insert-mode with a new, empty line.&lt;br /&gt;&lt;br /&gt;If you prefer TECO or WordStar or some other editor, you're out of luck.  &lt;span style="font-style:italic;"&gt;emacs&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; come standard, but nothing else.  Sorry.&lt;br /&gt;&lt;br /&gt;On the other hand, if you want to learn &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt; or &lt;span style="font-style:italic;"&gt;emacs&lt;/span&gt; (because, say, you're coming from another operating system), then the shell is an excellent teaching tool.  Each history-editing command you learn will work in the editor, and each text-editing command you learn will work on the command-line.&lt;br /&gt;&lt;br /&gt;As one last trivium, the old line editor, &lt;span style="font-style:italic;"&gt;ex&lt;/span&gt;, feels just like &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt;-mode history editing.  Some day, you'll be stuck using a line editor to recover a system.  Instead of being nervous, you'll find yourself completely comfortable.  It'll feel just like editing your history.&lt;br /&gt;&lt;br /&gt;After you're comfortable with &lt;span style="font-style:italic;"&gt;vi&lt;/span&gt;-mode history editing, go try &lt;span style="font-style:italic;"&gt;ex&lt;/span&gt;; you'll see what I mean.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113400374450221199?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400374450221199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400374450221199&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400374450221199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400374450221199'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/editor-choice.html' title='Editor Choice'/><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-18543508.post-113400335986884537</id><published>2005-12-05T08:00:00.000-08:00</published><updated>2005-12-08T13:06:24.676-08:00</updated><title type='text'>Editing History</title><content type='html'>&lt;blockquote&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;The Moving Finger writes; and, having writ,&lt;br /&gt;Moves on: - Omar Khayyam.&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You've used arrow keys and the &lt;span style="font-style:italic;"&gt;backspace/delete&lt;/span&gt; keys to edit command lines. They're just the tip of the iceberg.&lt;br /&gt;&lt;br /&gt;To give you access to the most powerful command-editing facilities, I have to give you a new viewpoint.  Let me see if I can take you there.&lt;br /&gt;&lt;br /&gt;Imagine all the commands you've issued as a file.  &lt;code&gt;history&lt;/code&gt; shows you this file, with line numbers.&lt;br /&gt;&lt;br /&gt;Next, imagine that when you type, you're actually editing that file.  There's an empty line at the bottom of the file; as you type, you're typing into that empty line.  When you press the carriage return, you move on to the next empty line.&lt;br /&gt;&lt;br /&gt;You're in a text editor with a screen so narrow it only displays a single line.&lt;br /&gt;&lt;br /&gt;As you press the arrow keys, you're navigating through a file.&lt;br /&gt;&lt;br /&gt;But since you are in an editor, you can edit the lines you see.  Like most editors you've used, it understands the arrow keys, backspace, and delete, but it understands a lot more -- the &lt;span style="font-style:italic;"&gt;Home&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;End&lt;/span&gt; keys for example.&lt;br /&gt;&lt;br /&gt;How powerful an editor is it?  I'll cut to the chase: it's emacs.  Want to go to the beginning of the line?  &lt;span style="font-style:italic;"&gt;^A (control-A)&lt;/span&gt;.  End of line?  &lt;span style="font-style:italic;"&gt;^E&lt;/span&gt;. Delete to end of line?  &lt;span style="font-style:italic;"&gt;^K&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Most familiar &lt;span style="font-weight:bold;"&gt;emacs&lt;/span&gt; commands will work.&lt;br /&gt;&lt;br /&gt;One-line &lt;span style="font-weight:bold;"&gt;emacs&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113400335986884537?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400335986884537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400335986884537&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400335986884537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400335986884537'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/editing-history.html' title='Editing History'/><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-18543508.post-113400305203689965</id><published>2005-12-04T08:00:00.000-08:00</published><updated>2005-12-08T12:58:43.086-08:00</updated><title type='text'>History</title><content type='html'>&lt;blockquote&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;God alone knows the future, but only an historian can alter the past.&lt;br /&gt;- Ambrose Bierce&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;This week, we're going to give an introduction to history.  History is, in turn, the introduction to everything else.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113400305203689965?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113400305203689965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113400305203689965&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400305203689965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113400305203689965'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/history.html' title='History'/><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-18543508.post-113349936872389681</id><published>2005-12-02T08:00:00.000-08:00</published><updated>2005-12-02T08:02:59.866-08:00</updated><title type='text'>Remember the Pipe</title><content type='html'>Sometimes, you want to save output.  For that, the shell gives you redirection.&lt;br /&gt;&lt;br /&gt;Sometimes, though, you want to save the pipeline that you grew to get the&lt;br /&gt;output.&lt;br /&gt;&lt;br /&gt;You could recall it, write it down, and then type it into a file, but there's&lt;br /&gt;an easier way.&lt;br /&gt;&lt;br /&gt;After you run the pipeline, make your next command "fc."&lt;br /&gt;&lt;br /&gt;Try this:&lt;blockquote&gt;&lt;pre&gt;ls | wc -l&lt;br /&gt;fc&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;(You've run other things since the pipeline?  Recall it with command history, rerun it, &lt;span style="font-style:italic;"&gt;then&lt;/span&gt; type &lt;code&gt;fc&lt;/code&gt;)&lt;br /&gt;&lt;br /&gt;Once &lt;code&gt;fc&lt;/code&gt; puts the pipeline into a text editor, you can write it out to a file. &lt;span style="font-style:italic;"&gt;Presto!&lt;/span&gt; A shell script.&lt;br /&gt;&lt;br /&gt;And as long as you're in there, you could even take your time, add shebang lines and comments, and change the layout.  The shell gives you command-line history and pipes, for quick-and-dirty script development, and then gives you &lt;code&gt;fc&lt;/code&gt;, to capture what works and clean it up.&lt;br /&gt;&lt;br /&gt;The default editor is &lt;span style="font-weight:bold;"&gt;vi&lt;/span&gt;, but you can make it whatever you want.&lt;blockquote&gt;&lt;pre&gt;EDITOR=kate&lt;br /&gt;ls | wc -l&lt;br /&gt;fc&lt;/pre&gt;&lt;/blockquote&gt;Notice that when you exit the editor, the command is rerun. &lt;code&gt;fc&lt;/code&gt; stands for &lt;span style="font-style:italic;"&gt;"fix command"&lt;/span&gt;.  Instead of editing a long command line with arrow keys, you can edit it with your favorite text editor.&lt;br /&gt;&lt;br /&gt;Being able to write to a file and create a shell script, once you've edited it, is just a side-effect of the shell's clean design.&lt;br /&gt;&lt;br /&gt;And now that we're talking about command history, we'll make that next week's introductory topic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349936872389681?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349936872389681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349936872389681&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349936872389681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349936872389681'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/remember-pipe.html' title='Remember the Pipe'/><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-18543508.post-113349927619913516</id><published>2005-12-01T08:00:00.000-08:00</published><updated>2005-12-02T08:03:28.306-08:00</updated><title type='text'>Pipelines</title><content type='html'>You can add as many elements to a pipeline as you want.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;ls -l /dev/&lt;br /&gt;ls -l /dev/ | grep -v ,&lt;br /&gt;ls -l /dev/ | grep -v , | grep -v -- '-&gt;'&lt;br /&gt;ls -l /dev/ | grep -v , | grep -v -- '-&gt;' | grep -v ' 0'&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;This is an everyday, and brilliant, use of command history: exploratory&lt;br /&gt;programming.&lt;br /&gt;&lt;br /&gt;Issue a command, look at the output.  Filter that output through something else to get closer to what you want.  Look at the result of that, and filter it again.  When you finally get what you want, redirect the output to save it.&lt;br /&gt;&lt;br /&gt;The metaphor of pipes and filters suffuses shell programming. To make your own programs (including your shell scripts) fit in, all you have to do is design them to take input from standard in, and spit output to standard out.&lt;br /&gt;&lt;br /&gt;Unless there are multiple inputs or outputs, don't write to files or read from them; use redirection for that.&lt;br /&gt;&lt;br /&gt;Suppose, for example, you write a program that collects all the &lt;code&gt;#ifdef&lt;/code&gt; variables into a file, one per line.  One design choice is to have it called like this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;ifdefvars CFILE VARFILE&lt;/pre&gt;&lt;/blockquote&gt;Worse, you could even design it to be called like this:&lt;blockquote&gt;&lt;pre&gt;ifdefvars CFILE&lt;/pre&gt;&lt;/blockquote&gt;and have it automatically generate &lt;code&gt;CFILE.VARS&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;If, instead, you have it read from stdin and write to stdout, so it's called like this&lt;blockquote&gt;&lt;pre&gt;ifdefvars &lt; CFILE &gt; VARS&lt;/pre&gt;&lt;/blockquote&gt; you can pop together a pipeline, at a moment's notice, to scan your code for mistyped variables:&lt;blockquote&gt;&lt;pre&gt;find . -name '*.[ch]' | xargs cat | ifdefvars | sort | uniq -c | awk '$1 == 1'&lt;/pre&gt;&lt;/blockquote&gt;(Don't know what all these commands do?  Type the first one in and run it.  Next, use command history to recall it, add the next stage in the pipeline and watch what changes.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349927619913516?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349927619913516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349927619913516&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349927619913516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349927619913516'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/12/pipelines.html' title='Pipelines'/><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-18543508.post-113349919377969611</id><published>2005-11-30T08:00:00.000-08:00</published><updated>2005-12-02T08:02:17.913-08:00</updated><title type='text'>Pipes</title><content type='html'>&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;You see, wire telegraph is a kind of a very, very long cat. You pull his tail in New York and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat. - Albert Einstein&lt;/span&gt;&lt;/blockquote&gt;The shell's biggest innovation is pipes.&lt;br /&gt;&lt;br /&gt;To hook stdout of one program to stdin of another, you just connect the two programs with a pipe symbol: &lt;span style="font-weight:bold;"&gt;'|'&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;How many files do I have?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;ls | wc -l&lt;/pre&gt;&lt;/blockquote&gt; You can think of it as shorthand for this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;ls &gt; TMPFILE; wc -l TMPFILE; rm TMPFILE&lt;/pre&gt;&lt;/blockquote&gt;The only thing is, &lt;span style="font-style:italic;"&gt;there is no temporary file&lt;/span&gt;.  In a pipeline, the output from one command really is hooked up to the input of the next, and both processes run simultaneously.  It's magic.&lt;br /&gt;&lt;br /&gt;If the first process is too slow, and the pipe gets empty, the second process just sits and waits for the first one to send it more stuff.  If the first process is too fast, and the pipe starts to clog, it just blocks until the second sucks enough out of the pipe to make it worth starting up again.&lt;br /&gt;&lt;br /&gt;For me, the ability to pipe into &lt;code&gt;wc -l&lt;/code&gt;, alone, is invaluable.&lt;br /&gt;&lt;br /&gt;How many processes are running?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;ls -d /proc/[0-9]* | wc -l&lt;/pre&gt;&lt;/blockquote&gt;How many .c and .h files are there in my source tree?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;find . -name '*.[ch]' | wc -l&lt;/pre&gt;&lt;/blockquote&gt;How many files have we had to change since the "FINAL" release?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;cvs -nq update -rFINAL | wc -l&lt;/pre&gt;&lt;/blockquote&gt;Next time you're asking "How many ...?", remember to answer it with a pipe.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349919377969611?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349919377969611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349919377969611&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349919377969611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349919377969611'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/pipes.html' title='Pipes'/><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-18543508.post-113349903747227732</id><published>2005-11-29T08:00:00.000-08:00</published><updated>2005-12-02T08:06:51.466-08:00</updated><title type='text'>Here Documents</title><content type='html'>Ouput has &lt;span style="font-weight:bold;"&gt;'&gt;'&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;'&gt;&gt;'&lt;/span&gt;.  Now that you've seen &lt;span style="font-weight:bold;"&gt;'&lt;'&lt;/span&gt;, what about &lt;span style="font-weight:bold;"&gt;'&lt;&lt;'&lt;/span&gt;?&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;cat &amp;lt;&amp;lt;FOO&lt;br /&gt;hello world&lt;br /&gt;FOO&lt;/blockquote&gt;&lt;/pre&gt;This is a &lt;span style="font-style:italic;"&gt;here document&lt;/span&gt;, which says &lt;span style="font-style:italic;"&gt;"Take input from from 'here to FOO'"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Actually, &lt;code&gt;FOO&lt;/code&gt; can be a little visually confusing, because I often use &lt;code&gt;FOO&lt;/code&gt; and &lt;code&gt;foo&lt;/code&gt; for variable or file names, so I usually use a marker for "End of Input" or "End of File"  instead, like &lt;code&gt;__EOF__&lt;/code&gt; or &lt;code&gt;__EOI__&lt;/code&gt;.  These stand out and I don't use them for other things.&lt;br /&gt;&lt;br /&gt;If you want to imbed the contents of a file into a script, a here document is a good way to do it.&lt;br /&gt;&lt;br /&gt;As usual, you should try out moving around the redirects, and use command history to do it.&lt;br /&gt;&lt;br /&gt;There's even a &lt;span style="font-weight:bold;"&gt;'&lt;&lt;&lt;'&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;H='hello, world'&lt;br /&gt;cat &amp;lt;&amp;lt;&amp;lt; $H&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;It's sort of a &lt;span style="font-style:italic;"&gt;"right here"&lt;/span&gt; document, which provides input from the current line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349903747227732?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349903747227732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349903747227732&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349903747227732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349903747227732'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/here-documents.html' title='Here Documents'/><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-18543508.post-113349846620389967</id><published>2005-11-28T08:00:00.000-08:00</published><updated>2005-12-01T20:51:05.360-08:00</updated><title type='text'>Redirecting Standard Input</title><content type='html'>Start like this:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;pre&gt;&lt;blockquote&gt;cat&lt;br /&gt;hello, world&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;hello, world&lt;/span&gt;&lt;br /&gt;^D&lt;/blockquote&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;cat&lt;/span&gt; copies the input that you type -- standard input, or stdin -- to the screen.&lt;br /&gt;Next, redirect output to a file.&lt;br /&gt;&lt;li&gt;&lt;pre&gt;&lt;blockquote&gt;cat&lt;br /&gt;cat &gt; FOO&lt;br /&gt;hello, world&lt;br /&gt;^D&lt;/blockquote&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;This puts the string &lt;span style="font-style:italic;"&gt;"hello, world"&lt;/span&gt; into the file, &lt;code&gt;FOO&lt;/code&gt;.&lt;br /&gt;You can check it by looking at the contents of &lt;code&gt;FOO&lt;/code&gt;.&lt;br /&gt;&lt;li&gt;&lt;pre&gt;&lt;blockquote&gt;cat FOO&lt;br /&gt;hello, world&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;Finally, use the command history and editing keys to recall command [2], change&lt;br /&gt;the &lt;span style="font-weight:bold;"&gt;'&gt;'&lt;/span&gt; to a &lt;span style="font-weight:bold;"&gt;'&lt;'&lt;/span&gt;, and to press a carriage return.&lt;br /&gt;&lt;li&gt;&lt;pre&gt;&lt;blockquote&gt;cat &lt; FOO&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;With &lt;span style="font-weight:bold;"&gt;'&lt;'&lt;/span&gt; the arrowhead points from the file toward the command,&lt;br /&gt;redirecting the contents of the file &lt;code&gt;FOO&lt;/code&gt; into the command &lt;span style="font-weight:bold;"&gt;cat&lt;/span&gt;.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Part of learning the shell is losing your fear of making mistakes.  The sooner you make your first 5000 mistakes, the better.  What do these do?&lt;br /&gt;&lt;pre&gt;&lt;blockquote&gt;cat &lt; FOO &gt; BAR&lt;br /&gt;&lt; FOO &gt; BAR cat&lt;br /&gt;&lt; cat &gt; BAR&lt;br /&gt;BAR &lt; &gt; cat&lt;br /&gt;&lt;/blockquote&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349846620389967?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349846620389967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349846620389967&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349846620389967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349846620389967'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/redirecting-standard-input.html' title='Redirecting Standard Input'/><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-18543508.post-113349757345355665</id><published>2005-11-27T08:00:00.000-08:00</published><updated>2005-12-02T08:07:46.263-08:00</updated><title type='text'>Input</title><content type='html'>We've talked about output, but without input, I/O would just be "O" -- a big&lt;br /&gt;nothing of a subject.  This week, I'll sketch some input redirection.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113349757345355665?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113349757345355665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113349757345355665&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349757345355665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113349757345355665'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/input.html' title='Input'/><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-18543508.post-113254519335196840</id><published>2005-11-25T08:00:00.000-08:00</published><updated>2005-11-27T15:44:06.450-08:00</updated><title type='text'>Fancier Redirection</title><content type='html'>The shell lets you do a lot of fancy redirection without much work. I'll show many examples as we go along, but here are a couple you'll use frequently.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Q: How do I put stdout and stderr into the same file?&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;# first, let's make sure X exists and Y doesn't&lt;br /&gt;&gt; X&lt;br /&gt;rm Y&lt;br /&gt;&lt;br /&gt;# now some experiments&lt;br /&gt;# try these on the command line&lt;br /&gt;ls X Y&lt;br /&gt;ls X Y &gt; OUT&lt;br /&gt;ls X Y 2&gt; ERR&lt;br /&gt;ls X Y &amp;&gt; BOTH&lt;br /&gt;ls X Y &gt; AMANDOI 2&gt;&amp;1    # Sometimes you see this form instead.  It's the same as &lt;span style="font-weight:bold;"&gt;&amp;&gt;&lt;/span&gt;.  &lt;br /&gt;                         # We'll explain why another time.&lt;br /&gt;                         # Any Romanians reading this?&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;If you didn't do the last commands by recalling and editing earlier commands,&lt;br /&gt;I suggest going back and trying that out.  Make using and editing the command history a habit now, not later.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Q: What if I don't want to overwrite files?  What if I want to tack onto the end of a file instead?&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;# &gt; overwrites, &gt;&gt; appends&lt;br /&gt;&lt;br /&gt;echo hello &gt; /tmp/$$&lt;br /&gt;echo world &gt;&gt; /tmp/$$&lt;br /&gt;cat /tmp/$$&lt;br /&gt;&lt;br /&gt;rm -f /tmp/$$&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;This script logs network activity, once an hour.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;while true&lt;br /&gt;do&lt;br /&gt;    date&lt;br /&gt;    ruptime&lt;br /&gt;    sleep $[ 60 * 60 ]      # an hour's worth of seconds&lt;br /&gt;    echo                    # blank line between each timepoint&lt;br /&gt;done &gt;&gt; /tmp/LOG&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113254519335196840?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113254519335196840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113254519335196840&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254519335196840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254519335196840'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/fancier-redirection.html' title='Fancier Redirection'/><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-18543508.post-113254440323954641</id><published>2005-11-24T08:00:00.000-08:00</published><updated>2005-11-27T15:43:36.923-08:00</updated><title type='text'>stderr</title><content type='html'>I've run programs before that huff and puff and produce ... an error message.  If the output is going into some archive, or is input into another program, I usually don't find out about the error until too late, and I think, &lt;span style="font-style:italic;"&gt;"Gee.  I wish it had beeped or something."&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;In well-designed programs, errors are announced through a separate channel from normal output.&lt;br /&gt;&lt;br /&gt;On Linux, default output goes to "standard output" (&lt;span style="font-weight:bold;"&gt;stdout&lt;/span&gt;), while errors go to "standard error" (&lt;span style="font-weight:bold;"&gt;stderr&lt;/span&gt;).  These are two separate channels.  Both go to the screen by default, but you can redirect them separately.&lt;br /&gt;&lt;br /&gt;Try this.  First, snarf-and-barf this script into the file &lt;span style="font-weight:bold;"&gt;hello&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;echo hello, world&lt;br /&gt;ls A_NONEXISTENT_FILE&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; Run &lt;span style="font-weight:bold;"&gt;hello&lt;/span&gt; and you'll see this:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;blockquote&gt;&lt;pre&gt;hello, world&lt;br /&gt;ls: A_NONEXISTENT_FILE: No such file or directory&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/span&gt; Next, use the command-line-editing keys to redirect the output into a file.  What happens?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;hello &gt; OUT&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; You can capture the errors with the construction "2&gt;"&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;hello 2&gt; ERR&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; You can redirect both separately.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;hello &gt; OUT 2&gt; ERR&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; Try this and think about what happens.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;hello &gt; OUT 2&gt; OUT&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Try redirecting either channel to the bit-bucket, &lt;span style="font-weight:bold;"&gt;/dev/null&lt;/span&gt;.  Then make up experiments of your own.&lt;br /&gt;&lt;br /&gt;Oh, &lt;a href="http://en.wikipedia.org/wiki/Thanksgiving"&gt;Happy Thanksgiving!&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113254440323954641?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113254440323954641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113254440323954641&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254440323954641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254440323954641'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/stderr.html' title='stderr'/><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-18543508.post-113254331176279595</id><published>2005-11-23T08:00:00.000-08:00</published><updated>2005-11-23T08:46:38.740-08:00</updated><title type='text'>Redirection Inside Your Scripts</title><content type='html'>Naturally, you can use redirection inside your scripts, too.  &lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# The shell lets you redirect output&lt;br /&gt;&lt;br /&gt;echo hello, world &gt; /tmp/$$         # "$$" is the process id of this script, just like Perl&lt;br /&gt;cat /tmp/$$&lt;br /&gt;&lt;br /&gt;rm -f /tmp/$$                       # when you make temporary files, clean up after yourself&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; Sometimes, when they're just starting out, people get confused about the difference between output produced by a script and output produced by commands inside a script.  Snarf-n-barf this into a script:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;echo "the 'hello world' step comes next"&lt;br /&gt;echo hello, world &gt; X&lt;br /&gt;echo "the 'hello world' step is now done"&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; Run it, then think about what happened for a second.&lt;br /&gt;&lt;br /&gt;You can now stick debugging statements into your scripts. (I'm not just trying to show you features of the shell, I'm trying to help you learn how to program in it.)&lt;br /&gt;&lt;br /&gt;But now that you're thinking carefully, think about this: there is a &lt;a href="http://en.wikipedia.org/wiki/Catch-22"&gt;Catch-22&lt;/a&gt; looming.&lt;br /&gt;&lt;br /&gt;Suppose you're developing a script by letting the ouput go to your screen. Now you redirect output to a file.  Something mysterious happens and the output file's suddenly full of garbage instead of what you expect.  (This has happened to you with other programming languages; it will happen to you in the shell, too.)&lt;br /&gt;&lt;br /&gt;How do you debug it?  Where's your debugging output?  In the same pile of garbage.&lt;br /&gt;&lt;br /&gt;This sets me up for what I'll talk about tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113254331176279595?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113254331176279595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113254331176279595&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254331176279595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254331176279595'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/redirection-inside-your-scripts.html' title='Redirection Inside Your 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-18543508.post-113254211818596714</id><published>2005-11-22T20:00:00.000-08:00</published><updated>2005-11-22T07:51:33.813-08:00</updated><title type='text'>Learning by Playing Around, and a Psychological Time Bomb</title><content type='html'>I learn the shell by playing around.  &lt;br /&gt;&lt;br /&gt;Using the up-arrow key to recall commands, plus the backspace and left-and right-arrow keys to edit them, you can do a lot of quick, little experiments.&lt;br /&gt;&lt;br /&gt;Try it now.  &lt;br /&gt;&lt;br /&gt;Start as usual:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;./hello &gt; 1&lt;br /&gt;cat 1&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;  What happens if the "&gt;" symbol is in front of the command instead of after it?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&gt; 2 ./hello&lt;br /&gt;cat 2&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; What happens if there's no command at all?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&gt; 3&lt;br /&gt;cat 3&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; What happens if there's already something in the file you're writing to?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;echo Your mother wears army boots. &gt; 4&lt;br /&gt;./hello &gt; 4&lt;br /&gt;cat 4&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; What happens if you accidentally write to yourself?&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;./hello &gt; hello&lt;br /&gt;cat hello&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;  This last experiment shows you that the shell starts redirection before it runs the command.  The shell opens up the output file, &lt;span style="font-weight:bold;"&gt;hello&lt;/span&gt;, cleans it out in preparation for filling it with the output of the the command &lt;code&gt;"./hello,"&lt;/code&gt; and then, uh, ... finds it's painted itself into a corner.  The command you've told it to run is now an empty file.&lt;br /&gt;&lt;br /&gt;You will do this to yourself eventually.  Instead of being mystified, you'll remember this, smack your forehead, and say, &lt;span style="font-style:italic;"&gt;"Dang!"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm setting a psychological time-bomb.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113254211818596714?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113254211818596714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113254211818596714&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254211818596714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254211818596714'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/learning-by-playing-around-and.html' title='Learning by Playing Around, and a Psychological Time Bomb'/><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-18543508.post-113254122719643488</id><published>2005-11-21T08:00:00.000-08:00</published><updated>2005-11-21T07:55:57.223-08:00</updated><title type='text'>Redirection</title><content type='html'>You ran your "hello, world" script like this: &lt;blockquote&gt;&lt;pre&gt; ./hello &lt;/pre&gt;&lt;/blockquote&gt; Output to a file, instead of the screen, is trivial. &lt;blockquote&gt;&lt;pre&gt; ./hello &gt; foo &lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;What could be easier?  Think of "&lt;span style="font-weight:bold;"&gt;&gt;&lt;/span&gt;" as an arrowhead that points the output into a file. If the file doesn't exist, it's created.&lt;br /&gt;&lt;br /&gt;The easiest way to learn the shell is to bounce back and forth between interactive and non-interactive uses.  We'll start doing that now.  First, create a "hello, world" script and run it.  &lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;echo "echo hello, world" &gt; hello&lt;br /&gt;chmod +x hello &lt;br /&gt;./hello &lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Press the up-arrow key.  The &lt;code&gt;./hello&lt;/code&gt; command will reappear, with your cursor at the end of the line, ready for you to type.  Append the characters &lt;span style="font-style:italic;"&gt;" &gt; foo"&lt;/span&gt; and press &lt;span style="font-style:italic;"&gt;ENTER&lt;/span&gt;. Then look to see what was put in the file &lt;span style="font-weight:bold;"&gt;foo&lt;/span&gt;.  &lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;./hello &gt; foo&lt;br /&gt;cat foo&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; Next, recall that command (&lt;code&gt;./hello &gt; foo&lt;/code&gt;), and use the backspace key to change &lt;code&gt;foo&lt;/code&gt; to &lt;code&gt;bar&lt;/code&gt;.  Press &lt;span style="font-style:italic;"&gt;ENTER&lt;/span&gt; and presto! now the output goes to &lt;span style="font-weight:bold;"&gt;bar&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Sending output to a file instead of to the screen is called "redirection."  (The key to stage  magic is &lt;a href="http://www.amazon.com/gp/product/0941599361/104-7228921-8305506?v=glance&amp;n=283155&amp;n=507846&amp;s=books&amp;v=glance"&gt;misdirection,&lt;/a&gt; the key to shell magic, redirection.)&lt;br /&gt;&lt;br /&gt;This is a common, and fruitful, way to develop shell scripts.  While you're developing, let output go to the screen.  When it's finally the way you want it, recall the command and redirect to a file to capture the output.&lt;br /&gt;&lt;br /&gt;November 21 is &lt;a href="http://www.worldhelloday.org/"&gt;World Hello Day&lt;/a&gt;, so rerun your program a few times, redirecting or not as fits your fancy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113254122719643488?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113254122719643488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113254122719643488&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254122719643488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113254122719643488'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/redirection.html' title='Redirection'/><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-18543508.post-113253986426593676</id><published>2005-11-20T08:00:00.000-08:00</published><updated>2005-11-20T18:24:24.280-08:00</updated><title type='text'>Quick tour: Output</title><content type='html'>Every language has strengths and weaknesses.&lt;br /&gt;&lt;br /&gt;The shell's loops and conditionals, for constructing algorithms, are pretty&lt;br /&gt;conventional.  They'll do, but they're nothing special&lt;br /&gt;&lt;br /&gt;The shell's data structures are just terrible.  All it has are scalars and&lt;br /&gt;arrays, just like FORTRAN. (Anyone out there remember FORTRAN?)  Actually,&lt;br /&gt;FORTRAN had multi-dimensional arrays.  The shell doesn't even have that.&lt;br /&gt;&lt;br /&gt;The shell does handle input and output of textfiles particularly well.&lt;br /&gt;&lt;br /&gt;This week, I'll show you how to do basic output.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113253986426593676?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113253986426593676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113253986426593676&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113253986426593676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113253986426593676'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/quick-tour-output.html' title='Quick tour: Output'/><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-18543508.post-113235331177867637</id><published>2005-11-17T14:27:00.000-08:00</published><updated>2005-11-19T11:55:09.363-08:00</updated><title type='text'>Control Flow: Loops</title><content type='html'>Millions recognize &lt;a href="http://www2.gol.com/users/quakers/simple_gifts.htm"&gt; the Shaker hymn, "Simple Gifts" &lt;/a&gt; from &lt;a href="http://www.amazon.com/gp/product/B0000026GG/104-7228921-8305506?v=glance&amp;n=5174&amp;v=glance"&gt; Aaron Copeland's "Appalachian Spring."&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The words begin&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;blockquote&gt;&lt;br /&gt;'Tis the gift to be simple,&lt;br /&gt;'tis the gift to be free,&lt;br /&gt;'tis the gift to come down where you ought to be,&lt;br /&gt;And when we find ourselves in the place just right, &lt;br /&gt;It will be in the valley of love and delight.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Open Source programmers around the world today, like modern-day &lt;a href="http://en.wikipedia.org/wiki/Shakers"&gt; Shakers &lt;/a&gt;, practice freedom and simplicity.  (The Shakers also practiced celibacy, however theirs was voluntary.)&lt;br /&gt;&lt;br /&gt;In honor of the Shakers, you should try out the Linux, command-line version of their hymn, which is even simpler:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;yes "'Tis the gift to be simple"&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, no one can sing that fast.&lt;br /&gt;&lt;br /&gt;The shell lets us bring this down to a reasonable pace with a loop:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;while true&lt;br /&gt;do&lt;br /&gt;    echo "'Tis the gift to be simple"&lt;br /&gt;    sleep 3&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;As usual, you should try this out, both in a file and on the command line.  Try also substituting the lyrics to the K&amp;R hymn, "Hello, world".&lt;br /&gt;&lt;br /&gt;Once you know loops are available, it's surprising how useful they can be.  This next loop tells us when the file "MY_LONG_AWAITED_OUTPUT" appears.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;while true&lt;br /&gt;do&lt;br /&gt;    if test -e MY_LONG_AWAITED_OUPUT&lt;br /&gt;    then&lt;br /&gt;        printf 'DONE!!!\a\n'&lt;br /&gt;        break&lt;br /&gt;    fi&lt;br /&gt;done&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;See if you can use a loop sometime today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113235331177867637?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113235331177867637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113235331177867637&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113235331177867637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113235331177867637'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/control-flow-loops.html' title='Control Flow: 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-18543508.post-113182121431565509</id><published>2005-11-17T08:00:00.000-08:00</published><updated>2005-11-19T11:54:46.190-08:00</updated><title type='text'>Control Flow: Conditionals</title><content type='html'>Real programming languages also have control flow constructs, like conditionals and loops. Here's a conditional&lt;blockquote&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# Some variables are built in, and predefined.&lt;br /&gt;# $0 is C's argv[0], or Perl's $0&lt;br /&gt;&lt;br /&gt;# $1, $2, etc., are the rest of argv[]/$ARGV&lt;br /&gt;# $* is the whole arg list&lt;br /&gt;&lt;br /&gt;# You can even use "test" to test the value of variables&lt;br /&gt;&lt;br /&gt;if test "$*" = ""&lt;br /&gt;then&lt;br /&gt;        HELLO="hello, world"&lt;br /&gt;else&lt;br /&gt;        HELLO="hello $*"&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;echo $HELLO&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;As usual, snarf-n-barf this into a file -- call it &lt;span style="font-weight:bold;"&gt;hello&lt;/span&gt; -- make it executable, and run it. Try it both as &lt;span style="font-weight:bold;"&gt;hello&lt;/span&gt; and as &lt;span style="font-weight:bold;"&gt;hello $LOGNAME&lt;/span&gt; .&lt;br /&gt;&lt;br /&gt;Try typing this program interactively to see how the interactive shell handles control-flow statements.  Watch the prompt change.  What's &lt;span style="font-style:italic;"&gt;$*&lt;/span&gt; for your interactive shell? (Hint: &lt;span style="font-style:italic;"&gt;echo $*&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;But would anyone use an &lt;span style="font-style:italic;"&gt;if ... then ... else ...&lt;/span&gt; or even an &lt;span style="font-style:italic;"&gt;if ... then ...&lt;/span&gt; on the command line?  Daily.  I'll show practical examples, and some other useful forms for conditionals, too.&lt;br /&gt;&lt;br /&gt;(&lt;a href="http://portal.acm.org/citation.cfm?id=365646&amp;jmp=cit&amp;dl=GUIDE&amp;dl=ACM&amp;CFID=10941068&amp;CFTOKEN=59269176#CIT"&gt;The Boehm-Jacopini theorem&lt;/a&gt; says a programming language needs nothing but a "while" and an "if," but language designers know enough not to leave well enough alone. I could write this blog in &lt;a href="http://en.wikipedia.org/wiki/Basic_English"&gt;Basic English&lt;/a&gt;, but why would I want to?)&lt;br /&gt;&lt;br /&gt;Next up, loops.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113182121431565509?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113182121431565509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113182121431565509&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182121431565509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182121431565509'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/control-flow-conditionals.html' title='Control Flow: Conditionals'/><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-18543508.post-113182081496641270</id><published>2005-11-16T08:00:00.000-08:00</published><updated>2005-11-19T11:54:24.656-08:00</updated><title type='text'>Variables</title><content type='html'>If it's a programming language, it needs variables.  Here's how you assign a value to a shell variable, and how you get that value back (dereference it).&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;    #!/bin/bash&lt;br /&gt;&lt;br /&gt;    # Here's how&lt;br /&gt;    # you give variables values.&lt;br /&gt;&lt;br /&gt;    HELLO="hello, world"&lt;br /&gt;&lt;br /&gt;    # (No spaces allowed around the '=' sign:&lt;br /&gt;    # a design botch in the shell.)&lt;br /&gt;&lt;br /&gt;    # And here's how you use them.  Note the dollar sign.&lt;br /&gt;&lt;br /&gt;    echo $HELLO&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Convince yourself that this works interactively, too.  Try putting spaces around the equals sign, to see what the error message says.  That way, when you make this mistake, you'll recognize it.&lt;br /&gt;&lt;br /&gt;I don't know anyone who's crazy about this design (no spaces, '$' to dereference, no '$' to set), but we can no more fix it now than we can fix English syntax. There may be shell scripts still running that were written before you were born.  Hindsight's always 20-20.&lt;br /&gt;&lt;br /&gt;Unsurprisingly, you can also assign variables the values of other variables.  This is a programming language.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;    GOODBYE=$HELLO&lt;br /&gt;    echo $GOODBYE&lt;br /&gt;    echo $HELLO&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can also unset a variable.&lt;blockquote&gt;&lt;pre&gt;    &lt;br /&gt;    unset HELLO&lt;br /&gt;    echo $GOODBYE&lt;br /&gt;    echo $HELLO&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113182081496641270?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113182081496641270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113182081496641270&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182081496641270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182081496641270'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/variables.html' title='Variables'/><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-18543508.post-113182043032517299</id><published>2005-11-15T08:00:00.000-08:00</published><updated>2005-11-20T20:29:56.306-08:00</updated><title type='text'>Shebang!</title><content type='html'>The quickest way to make progress in bash is to bounce back and forth between using it interactivly and non-interactively.&lt;br /&gt;&lt;br /&gt;Before we do that, though, it's worth our taking a quick tour of some things you'll see in shell scripts (which is what shell programs are called).&lt;br /&gt;&lt;br /&gt;To cut down on confusion, most scripts we show on the tour will do the same thing as yesterday's: print "hello, world."  (It was that or &lt;a href="http://www.cpan.org/misc/japh"&gt;"Just Another Perl Hacker"&lt;/a&gt; :-)&lt;br /&gt;&lt;br /&gt;Here's the second version of yesterday's script.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# "#!" is prononced "shebang" (shell bang)&lt;br /&gt;# &lt;br /&gt;# When a program starts like this,&lt;br /&gt;# the Unix kernel treats it specially,&lt;br /&gt;# and feeds it to a particular interpreter -- in this case, /bin/bash.&lt;br /&gt;#&lt;br /&gt;# When the kernel sends it to bash, bash treats that line as a comment,&lt;br /&gt;# because it starts with a '#'&lt;br /&gt;&lt;br /&gt;echo hello, world&lt;br /&gt;&lt;br /&gt;# If you don't have bash, use ksh.  If you don't have either, us /bin/sh&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;br /&gt;Cut-and-paste this code into a file, make it executable, and run it. ("Cut-and-paste" is also colloquially known as "snarf-n-barf.")&lt;br /&gt;&lt;br /&gt;Try modifying the shebang line to have the kernel send it to other interpreters, like /bin/ksh, /bin/sh, /bin/tcsh, or even /bin/true.  What happens?&lt;br /&gt;&lt;br /&gt;Claims that &lt;span style="font-style:italic;"&gt;"shebang"&lt;/span&gt; was originally spelled &lt;a href="http://irishpage.com/songs/carolan/sheebeag.htm"&gt;&lt;span style="font-style:italic;"&gt;"Sí bheang"&lt;/span&gt;&lt;/a&gt; are ill-founded, &lt;a href="http://www.snopes.com"&gt;urban blarney&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113182043032517299?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113182043032517299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113182043032517299&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182043032517299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182043032517299'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/shebang.html' title='Shebang!'/><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-18543508.post-113182020040709400</id><published>2005-11-14T08:00:00.000-08:00</published><updated>2005-11-19T11:53:41.783-08:00</updated><title type='text'>The Canonical Program</title><content type='html'>Perhaps the single most influential book on programming is &lt;a href="http://cm.bell-labs.com/cm/cs/cbook/"&gt;&lt;span style="font-style:italic;"&gt;The C Programming Language&lt;/span&gt;, by Brian Kernighan and Dennis Ritchie.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It begins like this:&lt;span style="font-style:italic;"&gt;&lt;blockquote&gt;1.1 Getting Started&lt;br /&gt;&lt;br /&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: Print the words &lt;span style="font-weight:bold;"&gt;hello, world&lt;/span&gt;&lt;br /&gt;&lt;br /&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;/blockquote&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://swexpert.com/C9/SE.C9.APR.99.pdf"&gt;Since K&amp;R, everyone's begun this way&lt;/a&gt;.  No sense going against the crowd if you don't have to.  Let's begin.&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;# The canonical program&lt;br /&gt;&lt;br /&gt;echo hello, world   # note that '#' starts a comment&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can type these lines into a file, make the file executable, and run it as a command.  You can also just type the lines at the command prompt.  The result is the same.   &lt;a href="http://snltranscripts.jt.org/75/75ishimmer.phtml"&gt;It's a programming language.  It's a command-line language.  It's new &lt;span style="font-style:italic;"&gt;Shimmer&lt;/span&gt;.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(You can omit the comments, but it's more fun to type them in.)&lt;br /&gt;&lt;br /&gt;Give it a try.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113182020040709400?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113182020040709400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113182020040709400&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182020040709400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113182020040709400'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/canonical-program.html' title='The Canonical Program'/><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-18543508.post-113181908356593366</id><published>2005-11-13T08:00:00.000-08:00</published><updated>2005-11-19T11:53:15.113-08:00</updated><title type='text'>What's This Blog About, Anyway?</title><content type='html'>This blog is about using the shell.&lt;br /&gt;&lt;br /&gt;The shell is a full-featured command interpreter that's both a command-line and programming language.  By "command-line," I mean you can type, interactively, at a prompt and get things done.  By "programming language," I mean you can write programs in the same language.&lt;br /&gt;&lt;br /&gt;Having something that does both well is a pleasant surprise.&lt;br /&gt;&lt;br /&gt;I'll keep blog posts bite-sized, and I'll make the entries for a week relate to one another.&lt;br /&gt;&lt;br /&gt;Topics will progress, but I'll try not to make them too interdependent.  I'd like you to be able to jump in and out whenever you want, flitting from topic to topic like a butterfly going from flower to flower, sampling whatever attracts your fancy.&lt;br /&gt;&lt;br /&gt;Because shells are just programs, there are a lot of shells for Unix, Linux, and other, similar operating systems.  In this blog, when I say "shell," I mean a POSIX-conforming shell, which follows &lt;a href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=38790"&gt;the specs laid out in ISO 9945-2&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In other words, &lt;a href="http://graham.main.nc.us/~bhammel/graham/shell.html"&gt;not csh or tcsh, not zsh, not the Massey shell, and not even very old versions of /bin/sh. &lt;/a&gt;  This still leaves a lot of possibilities.&lt;br /&gt;&lt;br /&gt;Also, most commands you'll use in the shell are standalone applications. (Unlike other operating systems, most shell commands aren't built in to the command interpreter.)  This means shell programs can depend on the underlying operating system.&lt;br /&gt;&lt;br /&gt;You need to see real examples, so I'll focus on programming in &lt;a href="http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html"&gt;bash ("the Bourne-again shell")&lt;/a&gt; running on &lt;a href="http://www.linux.org/"&gt;Linux&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Ready?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18543508-113181908356593366?l=shellshul.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shellshul.blogspot.com/feeds/113181908356593366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18543508&amp;postID=113181908356593366&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113181908356593366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18543508/posts/default/113181908356593366'/><link rel='alternate' type='text/html' href='http://shellshul.blogspot.com/2005/11/whats-this-blog-about-anyway.html' title='What&apos;s This Blog About, Anyway?'/><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></feed>
