<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Joy of Hack &#187; bash</title>
	<atom:link href="http://www.aijazansari.com/tag/bash/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.aijazansari.com</link>
	<description>For people who like to make things</description>
	<lastBuildDate>Tue, 20 Jul 2010 13:20:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Processing A List Of Files In bash</title>
		<link>http://www.aijazansari.com/2010/07/17/processing-a-list-of-files-in-bash/</link>
		<comments>http://www.aijazansari.com/2010/07/17/processing-a-list-of-files-in-bash/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 05:21:53 +0000</pubDate>
		<dc:creator>Aijaz Ansari</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://www.aijazansari.com/?p=672</guid>
		<description><![CDATA[When you&#8217;re working in Unix or Linux or even Mac OS X, there are often times when you need to apply the same command to a list of files.  In this post I&#8217;ll show you a couple of quick ways to do this using the bash shell. Let&#8217;s assume you have a command called that [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_706" class="wp-caption alignleft" style="width: 295px"><a rel="attachment wp-att-706" href="http://www.aijazansari.com/2010/07/17/processing-a-list-of-files-in-bash/ogilvietunnel/"><img class="size-medium wp-image-706" title="Under the tracks at Washington and Canal" src="http://www.aijazansari.com/wp-content/uploads/2010/07/OgilvieTunnel-285x189.jpg" alt="Under the tracks at Washington and Canal" width="285" height="189" /></a><p class="wp-caption-text">Under the tracks at Washington and Canal</p></div>
<p>When you&#8217;re working in Unix or Linux or even Mac OS X, there are often times when you need to apply the same command to a list of files.  In this post I&#8217;ll show you a couple of quick ways to do this using the bash shell.</p>
<p>Let&#8217;s assume you have a command called <span class="icode">process</span> that takes a file name as its input and processes the file in place.  For example, if you want to process the file at <span class="icode">/tmp/f1</span>, the command would be</p>
<pre class="brush: plain;">process /tmp/f1</pre>
<p>.  Let&#8217;s also say that after processing a file you want to archive it, using the <span class="icode">archive</span> command.</p>
<p>Now, if you want to process and archive files <span class="icode">/tmp/f1</span>, <span class="icode">/tmp/f2</span> and <span class="icode">/tmp/f3</span> you could either do this:</p>
<pre class="brush: plain;">
./process /tmp/f1
./archive /tmp/f1
./process /tmp/f2
./archive /tmp/f2
./process /tmp/f3
./archive /tmp/f3
</pre>
<p>or, you could use the bash keyword <span class="icode">for</span> and process all files in a loop like this:</p>
<pre class="brush: plain;">
for f in /tmp/f1 /tmp/f2 /tmp/f3
do
    ./process $f
    ./archive $f
done
</pre>
<p>That&#8217;s a lot less typing.  Let&#8217;s look at this loop closely:</p>
<p>A <span class="icode">for</span> loop used like this has three key components: the loop variable, the loop list and the loop body.  Let&#8217;s identify them in reverse order: The loop body is the part between the <span class="icode">do</span> and <span class="icode">done</span> keywords.  The loop list is the list of &#8216;things&#8217; over which you want the for loop to iterate.  In this case, the loop list is the list of files /tmp/f1 through /tmp/f3.  Note that the items in the loop list are separated by spaces.</p>
<p>The last component that makes the for loop work is the loop variable.  In this example the loop variable is called <span class="icode">f</span>.  This means that in the body of the loop, the loop variable <span class="icode">f</span> will be used as a placeholder for each of the items in the loop list.</p>
<p>The first time through the loop, the loop variable <span class="icode">f</span> will have the value <span class="icode">/tmp/f1</span>.  To refer to the value of the loop variable, you put a &#8216;$&#8217; before its name.  That&#8217;s why the body of the loop contains <span class="icode">process $f</span> and not <span class="icode">process f</span>.  <span class="icode">process f</span> would attempt to process a file named &#8216;f&#8217;, while <span class="icode">process $f</span> processes /tmp/f1 (in the first iteration of the loop).</p>
<p>Let&#8217;s test this out just to be sure.  Let&#8217;s create a dummy <span class="icode">process</span> program that does nothing other than print out the name of the file it&#8217;s processing.</p>
<pre class="brush: plain;">
#!/bin/bash

echo &quot;process - processing file $1&quot;;
</pre>
<p>Let&#8217;s also create an <span class="icode">archive</span> program that prints out the name of the file it&#8217;s archiving:</p>
<pre class="brush: plain;">
#!/bin/bash

echo &quot;archive - archiving file $1&quot;;
</pre>
<p>Now, you could type the following on the command line:</p>
<pre class="brush: plain;">
for f in /tmp/f1 /tmp/f2 /tmp/f3
do
    ./process $f
    ./archive $f
done
</pre>
<p>but if you&#8217;re like me and you prefer to see everything on the same line, you could instead type in the following one line:</p>
<pre class="brush: plain;">
for f in /tmp/f1 /tmp/f2 /tmp/f3; do ./process $f; ./archive $f; done
</pre>
<p>What&#8217;s different here is that you need the two semicolons (;) to tell bash where the loop list and loop body end.</p>
<p>Whichever method you choose, you&#8217;ll see the following output:</p>
<pre class="brush: plain;">

process - processing file /tmp/f1
archive - archiving file /tmp/f1
process - processing file /tmp/f2
archive - archiving file /tmp/f2
process - processing file /tmp/f3
archive - archiving file /tmp/f3
</pre>
<p>As you can see, the loop body was executed three times, and each time the value of the loop variable f was used wherever there was a <span class="icode">$f</span> in the loop body.</p>
<h3>Using Wildcards With Loops</h3>
<p>Sometimes you may have so many files in the loop list that you don&#8217;t want to type all their names onto the comand line.  In cases like this you could use wildcards.</p>
<p>Let&#8217;s say you want to process all files whose names end with <span class="icode">.txt</span>. You can do that by replacing the loop list with the appropriate regular expression:</p>
<pre class="brush: plain;">
for f in *.txt; do ./process $f; ./archive $f; done
</pre>
<p>Now, even if you have a hundred <span class="icode">.txt</span> files to process, this short command line will still work for you.</p>
<p>If you want to process all <span class="icode">.txt</span> and <span class="icode">.jpg</span> files, you could use either of the following two methods:</p>
<pre class="brush: plain;">
for f in *.txt *.jpg ; do ./process $f; ./archive $f; done
</pre>
<p>or</p>
<pre class="brush: plain;">
for f in *.{txt,jpg}; do ./process $f; ./archive $f; done
</pre>
<h3>In Conclusion</h3>
<p>As you can see, it&#8217;s easy to perform the same operations on a bunch of files when you use loops.  Loops are exceptionally useful as one-time command-line hacks.  It is important to remember that loops are not appropriate for every task.  There are times when the loop body is so complex that it&#8217;s safer to abandon the command line method and instead &#8216;factor out&#8217; the complexity into a script in bash or other scripting language.</p>
<p>There are also times when the files on which you want to operate are all over the disk drive, or in many subdirectories of the current directory.  As we&#8217;ll see in a later post, there are other common programs like &#8216;find&#8217; that are perfect in this case.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aijazansari.com/2010/07/17/processing-a-list-of-files-in-bash/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Navigating the Directory Stack in &#8216;bash&#8217;</title>
		<link>http://www.aijazansari.com/2010/02/20/navigating-the-directory-stack-in-bash/</link>
		<comments>http://www.aijazansari.com/2010/02/20/navigating-the-directory-stack-in-bash/#comments</comments>
		<pubDate>Sat, 20 Feb 2010 23:40:22 +0000</pubDate>
		<dc:creator>Aijaz Ansari</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[My Software]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://www.aijazansari.com/?p=338</guid>
		<description><![CDATA[If you&#8217;re like me, you spend a lot of time jumping from project to project in a Linux shell.  I find that I have to switch back and forth between directories.  The bash shell has commands to maintain a stack of directories.  I&#8217;ve written some functions that use these utilities to make directory navigation easier. [...]]]></description>
			<content:encoded><![CDATA[<p><a rel="attachment wp-att-431" href="http://www.aijazansari.com/2010/02/20/navigating-the-directory-stack-in-bash/img_4950-edit/"><img class="alignleft size-medium wp-image-431" title="Barracks by the Taj Mahal" src="http://www.aijazansari.com/wp-content/uploads/2010/02/IMG_4950-Edit-285x190.jpg" alt="Barracks by the Taj Mahal" width="285" height="190" /></a>If you&#8217;re like me, you spend a lot of time jumping from project to project in a Linux shell.  I find that I have to switch back and forth between directories.  The <em>bash</em> shell has commands to maintain a <a title="What is a stack?" href="http://www.ece.cmu.edu/~koopman/stack_computers/sec1_2.html">stack</a> of directories.  I&#8217;ve written some functions that use these utilities to make directory navigation easier. I&#8217;ve found these functions very useful, and perhaps you will too.  Let&#8217;s see them in action first with some examples, and then look at the code:</p>
<div class="aaa_code_section">
<p>In this first snippet, I start working in the Documents/Training/qt/ch1 directory:</p>
<pre class="brush: bash;">
$ pwd
/Users/aijaz
$ cd Documents/Training/qt/ch1/
$ ls
p1    t2
$
</pre>
</div>
<div class="aaa_code_section">
<p>Now let&#8217;s say I have to work in the TaskForest lib directory for a while:</p>
<pre class="brush: bash;">
$ cd ~/Projects/projects/taskforest/lib/TaskForest/
$ ls -l
total 352
-rw-r--r--   1 aijaz  aijaz   8816 May 25  2009 Calendar.pm
...
-rw-r--r--   1 aijaz  aijaz   4558 May 25  2009 TimeDependency.pm
$
</pre>
</div>
<div class="aaa_code_section">
<p>Now my work gets preempted because I have to work in the &#8216;rates&#8217; directory:</p>
<pre class="brush: bash;">
$ cd ~/tc/config/rates/
$ ls -l
total 27544
drwxr-xr-x  21 aijaz  aijaz       714 Sep  3  2007 Text
...
-rwxr-xr-x   1 aijaz  aijaz       569 Sep  3  2007 findVoipAccess.pl
$
</pre>
</div>
<div class="aaa_code_section">
<p>After finishing my work in the rates directory, I want to get back to what I was doing, but I can&#8217;t remember exactly what where I was before I got interrupted.  So I enter the &#8216;d&#8217; command which displays the stack of directories.  Every time I used the &#8216;cd&#8217; command, the system pushed the directory I was in onto a stack.  The &#8216;d&#8217; command displays the stack and prompts me for an entry. If I enter a number, it pushes the directory that&#8217;s at that position in the stack to the top, and enters that directory.</p>
<pre class="brush: bash;">
$ d
 0  ~/tc/config/rates
 1  ~/Projects/projects/taskforest/lib/TaskForest
 2  ~/Documents/Training/qt/ch1
 3  ~
#: 2
$ pwd
/Users/aijaz/Documents/Training/qt/ch1
$ d
 0  ~/Documents/Training/qt/ch1
 1  ~/tc/config/rates
 2  ~/Projects/projects/taskforest/lib/TaskForest
 3  ~
#: q
$
</pre>
<p>You can see that when I entered &#8217;2&#8242; above, the &#8216;d&#8217; command pushed the &#8216;~/Documents/Training/qt/ch1&#8242; directory to the top of the stack and entered that directory.  You can see the modified directory stack above.  I entered &#8216;d&#8217; again to view the directory stack, but this time entered &#8216;q&#8217; to do nothing.</p>
</div>
<div class="aaa_code_section">
<p>I&#8217;ve also created the &#8216;p&#8217; command, which pops the current directory off the top of the stack and enters the directory that was under it.</p>
<pre class="brush: bash;">
$ p
$ pwd
/Users/aijaz/tc/config/rates
$ d
 0  ~/tc/config/rates
 1  ~/Projects/projects/taskforest/lib/TaskForest
 2  ~
#: q
$
</pre>
</div>
<p>Now let&#8217;s have a look at the code that makes this work.  You can copy and paste this code directly into your <em>.bashrc</em> file.</p>
<pre class="brush: bash;">
# An enhanced 'cd' - push directories
# onto a stack as you navigate to it.
#
# The current directory is at the top
# of the stack.
#
function stack_cd {
    if [ $1 ]; then
        # use the pushd bash command to push the directory
        # to the top of the stack, and enter that directory
        pushd &quot;$1&quot; &gt; /dev/null
    else
        # the normal cd behavior is to enter $HOME if no
        # arguments are specified
        pushd $HOME &gt; /dev/null
    fi
}
# the cd command is now an alias to the stack_cd function
#
alias cd=stack_cd

# Swap the top two directories on the stack
#
function swap {
    pushd &gt; /dev/null
}
# s is an alias to the swap function
alias s=swap

# Pop the top (current) directory off the stack
# and move to the next directory
#
function pop_stack {
    popd &gt; /dev/null
}
alias p=pop_stack

# Display the stack of directories and prompt
# the user for an entry.
#
# If the user enters 'p', pop the stack.
# If the user enters a number, move that
# directory to the top of the stack
# If the user enters 'q', don't do anything.
#
function display_stack
{
    dirs -v
    echo -n &quot;#: &quot;
    read dir
    if [[ $dir = 'p' ]]; then
        pushd &gt; /dev/null
    elif [[ $dir != 'q' ]]; then
        d=$(dirs -l +$dir);
        popd +$dir &gt; /dev/null
        pushd &quot;$d&quot; &gt; /dev/null
    fi
}
alias d=display_stack
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.aijazansari.com/2010/02/20/navigating-the-directory-stack-in-bash/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
