<?xml version="1.0" ?><entry xml:lang="en" xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/"><id>http://price.mit.edu/blog/?p=129</id><link href="http://price.mit.edu/blog/2010/02/pretend-bash-is-a-real-language/" rel="alternate" type="text/html"/><title>How to pretend bash is a real programming language, tip #13</title><summary>I wrote some throwaway shell code tonight that looked like this:

   for oo in $(cd .git/objects/ &amp;&amp; ls ??/*); do
     o=${oo%/*}${oo#*/}
     # do something horrible with the Git object $o, which is in the file $oo
   done


It doesn’t matter now exactly what the [...]</summary><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I wrote some throwaway shell code tonight that looked like this:</p>
<pre>   for oo in $(cd .git/objects/ &amp;&amp; ls ??/*); do
     o=${oo%/*}${oo#*/}
     # do something horrible with the Git object $o, which is in the file $oo
   done
</pre>
<p/>
<p>It doesn’t matter now exactly what the code was for.  But a collaborator wrote back to me:</p>
<pre>&gt; &gt; o=${oo%/*}${oo#*/}
&gt; How does this line work/what is it supposed to accomplish?  In
&gt; particular not sure what the %foo and #foo do.
</pre>
<p/>
<p><strong>Stop for a moment: do you know</strong> how that line works?  I wouldn’t have in my first years writing shell scripts.</p>
<p>This line demonstrates one of a repertoire of tricks I’ve picked up to get some things done in <code>bash</code> that might otherwise require invoking a separate program.  None of these will be news to shell-programming experts, but I sure didn’t know all of them when I started writing in shell.  Here’s a little braindump on one of my favorite tricks, and where to read about more.</p>
<p>The best documentation for Bash is <strong>the info page</strong>—the specific pages I find myself referring to most often are under “info bash” -&gt; “Basic Shell Features” -&gt; “Shell Expansions”.  (If you’ve never tried it, you’ve been missing out!  Type “info bash” at your favorite prompt.  But not on a Debian or Ubuntu machine, where the <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=427804">info page is missing</a> due to a <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=357260">stupid licensing dispute</a>.  Info is the home of the best documentation available for Bash, GCC, GDB, Emacs, miscellaneous GNU utilities, and Info itself.)  </p>
<p>This feature is under “Shell Parameter Expansion” there.</p>
<pre>`${PARAMETER#WORD}'
`${PARAMETER##WORD}'
     The WORD is expanded to produce a pattern just as in filename
     expansion (*note Filename Expansion::).  If the pattern matches
     the beginning of the expanded value of PARAMETER, then the result
     of the expansion is the expanded value of PARAMETER with the
     shortest matching pattern (the `#' case) or the longest matching
     pattern (the `##' case) deleted.
</pre>
<p>The <code>%</code> and <code>%%</code> features work similarly, with “beginning” substituted with “end”.</p>
<p>My mnemonic for <code>#</code> versus <code>%</code> is that <code>$</code> is for the variable; <code>#</code> is to the left of <code>$</code>, so it strips from the left, and <code>%</code> is to the right, so it strips from the right.  I suspect this is the actual motivation for the choice of <code>#</code> and <code>%</code>, though I’m curious to see evidence to confirm or refute that thought.</p>
<p>So after my line <code>o=${oo%/*}${oo#*/}</code>, <code>o</code> consists of the part of <code>oo</code> to the left of the last slash, and then the part of <code>oo</code> to the right of the first slash. Since there should be just one slash in <code>oo</code>, it has the effect of making <code>o</code> be everything but the slash.</p>
<p>That makes one trick I use all the time.  There’s plenty more, and those Info pages explain many of them.  I’m not sure all these tricks are a good thing on balance—they serve as a crutch to make the shell go further, when maybe I should just be quicker to switch to <a href="http://www.python.org/">a real programming language</a>.  But they sure come in handy.</p></div></content><updated planet:format="February 27, 2010 09:56 AM">2010-02-27T09:56:33Z</updated><category term="Uncategorized"/><category term="bash"/><category term="free software"/><category term="sipb"/><author><name>Greg Price</name></author><source><id>http://price.mit.edu/blog</id><link href="http://price.mit.edu/blog/tag/sipb/feed/" rel="self" type="application/rss+xml"/><link href="http://price.mit.edu/blog" rel="alternate" type="text/html"/><title>price.mit.edu/blog » sipb</title><updated planet:format="January 25, 2026 03:07 AM">2026-01-25T03:07:27Z</updated><planet:format>rss20</planet:format><planet:http_etag>&quot;452a10c017d6ace36ea6c313eb650a31&quot;</planet:http_etag><planet:http_last_modified>Mon, 16 Aug 2010 16:26:14 GMT</planet:http_last_modified><planet:bozo>false</planet:bozo><planet:encoding>utf-8</planet:encoding><planet:css-id>gregory-price</planet:css-id><planet:items_per_page>60</planet:items_per_page><planet:name>Gregory Price</planet:name><planet:days_per_page>0</planet:days_per_page><planet:http_status>200</planet:http_status></source></entry>