<?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>BASH Cures Cancer &#187; script</title>
	<atom:link href="http://bashcurescancer.com/category/script/feed" rel="self" type="application/rss+xml" />
	<link>http://bashcurescancer.com</link>
	<description>Learn the UNIX/Linux command line</description>
	<lastBuildDate>Tue, 25 Oct 2011 18:09:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Processing XML on the Command Line</title>
		<link>http://bashcurescancer.com/processing-xml-on-the-command-line.html</link>
		<comments>http://bashcurescancer.com/processing-xml-on-the-command-line.html#comments</comments>
		<pubDate>Fri, 25 Apr 2008 04:08:44 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[script]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xsl]]></category>
		<category><![CDATA[xsltproc]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/?p=149</guid>
		<description><![CDATA[The other day on the cURL email list, someone asked: Could someone please tell me (preferably with an example) of how I could parse and xml like the following: &#60;?xml version=&#8221;1.0&#8243; encoding=&#8221;ISO-8859-1&#8243; ?&#62; &#60;FileRetriever&#62; &#60;FileList&#62; &#60;File name=&#8221;AMERI08.D4860.ZIP&#8221; /&#62; &#60;File name=&#8221;DTCCRSF.D4861.ZIP&#8221; /&#62; &#60;File name=&#8221;DTGSS01.D4862.ZIP&#8221; /&#62; &#60;File name=&#8221;DTGSS02.D4863.ZIP&#8221; /&#62; &#60;File name=&#8221;DTGSS03.D4864.ZIP&#8221; / &#60;/FileList&#62; &#60;/FileRetriever&#62; This is not [...]]]></description>
			<content:encoded><![CDATA[<p>The other day on the cURL email list, someone asked:</p>
<blockquote><p>Could someone please tell me (preferably with an example) of how I could parse and xml like the following:</p>
<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;ISO-8859-1&#8243; ?&gt;<br />
&lt;FileRetriever&gt;<br />
&lt;FileList&gt;<br />
&lt;File name=&#8221;AMERI08.D4860.ZIP&#8221; /&gt;<br />
&lt;File name=&#8221;DTCCRSF.D4861.ZIP&#8221; /&gt;<br />
&lt;File name=&#8221;DTGSS01.D4862.ZIP&#8221; /&gt;<br />
&lt;File name=&#8221;DTGSS02.D4863.ZIP&#8221; /&gt;<br />
&lt;File name=&#8221;DTGSS03.D4864.ZIP&#8221; /<br />
&lt;/FileList&gt;<br />
&lt;/FileRetriever&gt;</p></blockquote>
<p>This is not appropriate for the cURL list, but I thought a fair question.  You could do this:</p>
<pre>$ grep '&lt;File ' config.xml  | awk -F'"' '{print $2}' | xargs -l -I {} echo curl -I "http://bashcurescancer.com/{}"
curl -I http://bashcurescancer.com/AMERI08.D4860.ZIP
curl -I http://bashcurescancer.com/DTCCRSF.D4861.ZIP
curl -I http://bashcurescancer.com/DTGSS01.D4862.ZIP
curl -I http://bashcurescancer.com/DTGSS02.D4863.ZIP
curl -I http://bashcurescancer.com/DTGSS03.D4864.ZIP</pre>
<p>Or, you could use the xsltproc command with an associated style sheet. This is really the correct method and much more effective when your processing complex XML or XML that is not easily grep&#8217;able:</p>
<pre>$ xsltproc --nonet config.xsl config.xml | xargs -l -I {} echo curl -I "http://bashcurescancer.com/{}"
curl -I http://bashcurescancer.com/AMERI08.D4860.ZIP
curl -I http://bashcurescancer.com/DTCCRSF.D4861.ZIP
curl -I http://bashcurescancer.com/DTGSS01.D4862.ZIP
curl -I http://bashcurescancer.com/DTGSS02.D4863.ZIP
curl -I http://bashcurescancer.com/DTGSS03.D4864.ZIP</pre>
<p>Links to <a href="http://bashcurescancer.com/media/using-xsl-on-the-command-line/config.xml">config.xml</a> and <a href="http://bashcurescancer.com/media/using-xsl-on-the-command-line/config.xsl">config.xsl</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/processing-xml-on-the-command-line.html/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>using kill to see if a process is alive</title>
		<link>http://bashcurescancer.com/using-kill-to-see-if-a-process-is-alive.html</link>
		<comments>http://bashcurescancer.com/using-kill-to-see-if-a-process-is-alive.html#comments</comments>
		<pubDate>Thu, 10 Apr 2008 04:43:55 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[Brock's Tools]]></category>
		<category><![CDATA[Good Practice]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[kill]]></category>
		<category><![CDATA[process]]></category>
		<category><![CDATA[ps]]></category>
		<category><![CDATA[ps -ef]]></category>
		<category><![CDATA[ps faux]]></category>
		<category><![CDATA[ps grep]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/?p=141</guid>
		<description><![CDATA[I am making some changes to the moreutils sponge command. Sponge provides a method of prepending which is less specialized than my prepend util. However, it has trouble with large amounts of input. Regardless, while testing my changes, I want to watch it operate. Normally, you would just do so from a second terminal. That [...]]]></description>
			<content:encoded><![CDATA[<p>I am making some changes to the <a href="http://kitenet.net/~joey/code/moreutils/">moreutils</a> sponge command.  Sponge provides a method of prepending which is less specialized than my <a href="http://bashcurescancer.com/new-command-prepend.html">prepend</a> util. However, it has trouble with large amounts of input.</p>
<p>Regardless, while testing my changes, I want to watch it operate. Normally, you would just do so from a second terminal. That is a pain. kill -0 can be very useful for this. After backgrounding the command, I assign the pid (via the variable $!) to $pid using eval. eval is needed to stop BASH from expanding $! until after the background operation.</p>
<p>After that, I enter a while loop on kill -0 $pid, which will not kill $pid, but will return successfully until $pid has died:</p>
<pre># cat large-file-GB | ./sponge large-file-GB-copy &amp; eval 'pid=$!'; while kill -0 $pid; do sleep 10; ls -lh large-file* /tmp/sponge.*; echo;done
[1] 7937
-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw------- 1 root root 128M 2008-04-09 17:23 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw------- 1 root root 384M 2008-04-09 17:23 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw------- 1 root root 877M 2008-04-09 17:24 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw-r--r-- 1 root root  20M 2008-04-09 17:24 large-file-GB-copy
-rw------- 1 root root 896M 2008-04-09 17:24 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw-r--r-- 1 root root 413M 2008-04-09 17:25 large-file-GB-copy
-rw------- 1 root root 896M 2008-04-09 17:24 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw-r--r-- 1 root root 836M 2008-04-09 17:25 large-file-GB-copy
-rw------- 1 root root 896M 2008-04-09 17:24 /tmp/sponge.JMsBWG

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw-r--r-- 1 root root 920M 2008-04-09 17:25 large-file-GB-copy
[1]+  Done                    cat large-file-GB | ./sponge large-file-GB-copy
ls: cannot access /tmp/sponge.*: No such file or directory

-rw-r--r-- 1 root root 977M 2008-04-09 16:18 large-file-GB
-rw-r--r-- 1 root root 977M 2008-04-09 17:25 large-file-GB-copy
-bash: kill: (7937) - No such process
# md5sum large-file-GB*
b5c667a723a10a3485a33263c4c2b978  large-file-GB
b5c667a723a10a3485a33263c4c2b978  large-file-GB-copy</pre>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/using-kill-to-see-if-a-process-is-alive.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>New command: prepend</title>
		<link>http://bashcurescancer.com/new-command-prepend.html</link>
		<comments>http://bashcurescancer.com/new-command-prepend.html#comments</comments>
		<pubDate>Mon, 07 Apr 2008 02:44:37 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[Brock's Tools]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/new-command-prepend.html</guid>
		<description><![CDATA[I am utilizing Google&#8217;s project hosting to host software which I create and feel is useful or want to keep track of. I called the project Brock&#8217;s Tools. The code that led me to create this project was a command I am calling prepend 1.1. (UPDATE: See this post on sponge as its a better [...]]]></description>
			<content:encoded><![CDATA[<p>I am utilizing Google&#8217;s project hosting to host software which I create and feel is useful or want to keep track of. I called the project <a href="http://code.google.com/p/brockstools/">Brock&#8217;s Tools</a>. The code that led me to create this project was a command I am calling <a href="http://brockstools.googlecode.com/files/prepend-1.1.tar.gz">prepend 1.1</a>. (UPDATE: See <a href="http://bashcurescancer.com/prepend-to-a-file-with-sponge-from-moreutils.html">this post on sponge</a> as its a better general case tool.)</p>
<p>prepend, prepend&#8217;s files or standard input to a file. For example,  you have three files:</p>
<pre>$ echo BROCK &gt; a
$ echo DAVID &gt; b
$ echo NOLAND &gt; c</pre>
<p>And you want to combine them into one file:</p>
<pre>$ echo "My name is:" | prepend - a b c
$ cat c
My name is:
BROCK
DAVID
NOLAND</pre>
<p>Or lets say you just want to append a file to itself:</p>
<pre>$ cat a
BROCK
$ cat a &gt;&gt; a
cat: a: input file is output file</pre>
<p>prepend does this:</p>
<pre>$ prepend a
$ cat a
BROCK
BROCK</pre>
<p>I come across the a situation where this would be useful quite often. Of course prepend&#8217;ing can be done in the shell:</p>
<pre>$ { echo "My name is:"; cat a b c; } &gt; tmp &amp;&amp; mv -f tmp c
$ cat c
My name is:
BROCK
DAVID
NOLAND</pre>
<p>However, that is unsafe and I have lost data that way. I perform this operation most often when dealing with XML. In this example, its trivial to open the file in an editor, but with a large file, its quite nasty to do so:</p>
<pre>$ cat something.xml
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 1&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 2&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 3 &lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 4&lt;/more&gt;&lt;/entry&gt;
$ echo "&lt;/entries&gt;" &gt;&gt; something.xml
$ cat something.xml
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 1&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 2&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 3 &lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 4&lt;/more&gt;&lt;/entry&gt;
&lt;/entries&gt;
$ echo "&lt;entries&gt;" | prepend - something.xml
$ cat something.xml
&lt;entries&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 1&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 2&lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 3 &lt;/more&gt;&lt;/entry&gt;
&lt;entry&gt;&lt;blah/&gt;&lt;more&gt;stuff 4&lt;/more&gt;&lt;/entry&gt;
&lt;/entries&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/new-command-prepend.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Exposing command line programs as web services</title>
		<link>http://bashcurescancer.com/exposing-command-line-programs-as-web-services.html</link>
		<comments>http://bashcurescancer.com/exposing-command-line-programs-as-web-services.html#comments</comments>
		<pubDate>Thu, 27 Mar 2008 23:01:30 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[guest post]]></category>
		<category><![CDATA[Ideas]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[webservice]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/exposing-command-line-programs-as-web-services.html</guid>
		<description><![CDATA[The web services paradigm of development is based on the Unix philosophy of &#8220;small is good&#8221;.  Web services should do one job, and do it well, allowing users to develop complex solutions by combining small, reliable and proven services. Why not then, expose the power of familiar Unix commands like sort, grep, gzip&#8230; to the [...]]]></description>
			<content:encoded><![CDATA[<p>The web services paradigm of development is based on the Unix philosophy of &#8220;small is good&#8221;.  Web services should do one job, and do it well, allowing users to develop complex solutions by combining small, reliable and proven services.<br />
Why not then, expose the power of familiar Unix commands like sort, grep, gzip&#8230; to the web?</p>
<p>Here is a <a href="http://bashcurescancer.com/media/scripts/to_web.py.txt">proof of concept python script</a> (<a href="http://bashcurescancer.com/media/scripts/to_web2_3.py.txt">Python 2.3 version</a>) to demonstrate.</p>
<p><span style="font-family: arial,helvetica,sans-serif;">Start services:</span></p>
<pre><span style="font-family: courier new,monospace;">$ ./to_web.py -p8008 sort &amp;
Thu Mar 27 13:45:54 2008 sort server started - 8008</span><span style="font-family: courier new,monospace;">
$ ./to_web.py -p8009 gzip &amp;
Thu Mar 27 13:46:29 2008 gzip server started - 8009</span></pre>
<p><span style="font-family: courier new,monospace;"><span style="font-family: arial,helvetica,sans-serif;">Use the services:</span><br />
</span></p>
<pre><span style="font-family: courier new,monospace;">$ for i in {1..10}; do echo ${RANDOM:0:2}; done | \
&gt; curl --data-binary @- "<a href="http://swat:8008/sort+-nr" target="_blank">http://swat:8008/sort+-nr</a>" | \
&gt; curl --data-binary @- "<a href="http://swat:8009/gzip" target="_blank">http://swat:8009/gzip</a>" | \
&gt; gunzip
97
37
23
23
21
18
11
11
10
10</span></pre>
<p>In my position, we have a database with host information &#8211; which has a command line interface. This tool has dependencies which are a painful to resolve. With <a href="http://bashcurescancer.com/media/scripts/to_web.py.txt">to_web.py</a>, we can turn the command line tool into a web service and access the data without having to satisfy those additional dependencies.</p>
<p><em>This is guest post by my esteemed colleague <strong>Adam Fokken</strong>. He can be reached here: <img src="http://spamdefeator.com/u/1ea" alt="" />Sadly, he does not have a blog. </em></p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/exposing-command-line-programs-as-web-services.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Wrapping dynamic languages in shell without an extra script</title>
		<link>http://bashcurescancer.com/wrapping-dynamic-languages-in-shell-without-an-extra-script.html</link>
		<comments>http://bashcurescancer.com/wrapping-dynamic-languages-in-shell-without-an-extra-script.html#comments</comments>
		<pubDate>Tue, 25 Mar 2008 23:16:30 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[cx_Oracle]]></category>
		<category><![CDATA[LD_LIBRARY_PATH]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/wrapping-dynamic-languages-in-shell-without-an-extra-script.html</guid>
		<description><![CDATA[There are situations where, if you want a Python, PERL, PHP, etc script to be portable among a few different servers, it makes sense to wrap the script in shell. A few years ago I was trying to use the Python cx_Oracle module. This module is a wrapper for the native Oracle database driver. However, [...]]]></description>
			<content:encoded><![CDATA[<p>There are situations where, if you want a Python, PERL, PHP, etc script to be portable among a few different servers, it makes sense to wrap the script in shell. A few years ago I was trying to use the Python cx_Oracle module. This module is a wrapper for the native Oracle database driver. However, it requires the driver library directory be in the LD_LIBRARY_PATH environment variable.</p>
<p>No problem I thought. I&#8217;ll use the os.environ dict to set the variable.  Example script:</p>
<pre>$ cat python-only.sh
#!/usr/bin/python
import sys, os
sys.path.append("/usr/local/lib/python2.4/site-packages/")
if not os.environ.has_key('LD_LIBRARY_PATH'):
        os.environ['LD_LIBRARY_PATH'] = "/home/noland/oracle-lib"
else:
        os.environ['LD_LIBRARY_PATH'] = "/home/noland/oracle-lib:" + os.environ['LD_LIBRARY_PATH']
print "LD_LIBRARY_PATH looks OK in Python: LD_LIBRARY_PATH = ", os.environ['LD_LIBRARY_PATH']
os.system('echo LD_LIBRARY_PATH looks OK via os.system: LD_LIBRARY_PATH = $LD_LIBRARY_PATH')
try:
        import cx_Oracle
        print "Imported cx_Oracle! LD_LIBRARY_PATH was set correctly."
except ImportError, e:
        print "Woops, LD_LIBRARY_PATH was not set correctly: ", e</pre>
<p>This method does not work:</p>
<pre>$ ./python-only.sh
LD_LIBRARY_PATH looks OK in Python: LD_LIBRARY_PATH =  /home/noland/oracle-lib
LD_LIBRARY_PATH looks OK via os.system: LD_LIBRARY_PATH = /home/noland/oracle-lib
Woops, LD_LIBRARY_PATH was not set correctly:  libclntsh.so.10.1: cannot open shared object file: No such file or directory</pre>
<p>This seems to be a <a href="http://mail.python.org/pipermail/python-list/2006-July/394301.html">common problem</a>. However, when I was dealing with this a few years ago, I could not find a good resource on Google. I bite the bullet and wrote a separate shell script wrapper &#8211; hating invocation of the shell script. However, there is absolutely no reason I needed a separate shell script. I could have embedded the Python within a shell script. Example:</p>
<pre>$ cat python-and-bash.sh
#/bin/bash
export LD_LIBRARY_PATH=/home/noland/oracle-lib:$LD_LIBRARY_PATH
/usr/bin/python&lt;&lt;END_OF_PYTHON
import sys
sys.path.append("/usr/local/lib/python2.4/site-packages/")
try:
        import cx_Oracle
        print "Imported cx_Oracle! LD_LIBRARY_PATH was set correctly."
except ImportError, e:
        print "Woops, LD_LIBRARY_PATH was not set correctly: ", e
END_OF_PYTHON</pre>
<p>Ahh, much better:</p>
<pre>$ ./python-and-bash.sh
Imported cx_Oracle! LD_LIBRARY_PATH was set correctly.</pre>
<p>Of course I could have just set this variable in my profile. However, this creates an additional external dependency &#8211; which is what I was trying to avoid.</p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/wrapping-dynamic-languages-in-shell-without-an-extra-script.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Process Substitution</title>
		<link>http://bashcurescancer.com/process-substitution.html</link>
		<comments>http://bashcurescancer.com/process-substitution.html#comments</comments>
		<pubDate>Sun, 23 Mar 2008 17:54:52 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[dd]]></category>
		<category><![CDATA[Good Practice]]></category>
		<category><![CDATA[process]]></category>
		<category><![CDATA[read part of file]]></category>
		<category><![CDATA[sheel script]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/process-substitution.html</guid>
		<description><![CDATA[Quite some time ago, someone wrote me to ask about a possible article on process substitution. Sadly, I could not find the email so I cannot credit them. As you likely have guessed, I am finally writing a post on process substitution. Many times I have used pipelines and temporary files when process substitution would [...]]]></description>
			<content:encoded><![CDATA[<p>Quite some time ago, someone wrote me to ask about a possible article on <a href="http://tldp.org/LDP/abs/html/process-sub.html" target="_blank">process substitution</a>. Sadly, I could not find the email so I cannot credit them. As you likely have guessed, I am finally writing a post on process substitution.</p>
<p>Many times I have used pipelines and temporary files when process substitution would be a much cleaner solution.</p>
<p>First, I am going to create two test files:</p>
<pre>$ dd if=/dev/urandom of=file-small <strong>count=750001</strong>
$ dd if=/dev/urandom of=file-large <strong>count=1000000</strong>
$ ls -l file-*
-rw-r--r-- 1 noland noland 512000000 Mar 23 08:53 file-large
-rw-r--r-- 1 noland noland 384000512 Mar 23 08:49 file-small</pre>
<p>I thought of writing this article while writing <a href="http://bashcurescancer.com/media/scripts/ftp-file-locking-test.sh.txt">a script to test ftp servers and file locking</a>. As such I will upload the small file to a file named <em>append-example</em>:</p>
<pre>$ curl -T file-small --user noland ftp://localhost/append-example
Enter host password for user 'noland':
$ ls -l append-example
-rw-r--r-- 1 noland noland 384000512 Mar 23 11:52 append-example</pre>
<p>Now I will append  the large file:</p>
<pre>$ curl -s -a -T file-large --user noland ftp://localhost/append-example
Enter host password for user 'noland':
$ ls -l append-example
-rw-r--r-- 1 noland noland 896000512 Mar 23 11:54 append-example</pre>
<p>I am going to use dd and process substituion to caculate the MD5 hash of the first upload:</p>
<pre>$ md5sum file-small &lt;(dd if=append-example <strong>count=750001</strong> status=noxfer)
dfabff7441bd814145a804e03d333864  file-small
1000000+0 records in
1000000+0 records out
dfabff7441bd814145a804e03d333864  /dev/fd/63</pre>
<p>Now the portion that was appended:</p>
<pre>$ md5sum file-large &lt;(dd if=append-example  <strong>skip=750001</strong> status=noxfer)
1b8daed9e435fc90b4a49d74b55f96f4  file-large
1000000+0 records in
1000000+0 records out
1b8daed9e435fc90b4a49d74b55f96f4  /dev/fd/63</pre>
<p>When you place a command inside &lt;( ) the shell sets standard output of the command to pipe inside /dev/fd/ and replaces the command with that pipe. Here is the classic example:</p>
<pre>$ echo &lt;(echo) &lt;(echo) &lt;(echo) &lt;(echo)
/dev/fd/63 /dev/fd/62 /dev/fd/61 /dev/fd/60</pre>
<p>In my script I use process substitution as below (effectively) which feels exeedingly clean:</p>
<pre>$ read hash name &lt; &lt;(md5sum &lt;(dd if=append-example <strong>skip=750001</strong> status=noxfer))
1000000+0 records in
1000000+0 records out
$ printf "hash=%s name=%s\n" $hash $name
hash=1b8daed9e435fc90b4a49d74b55f96f4 name=/dev/fd/63</pre>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/process-substitution.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Keeping your SSH sessions alive with NOOP</title>
		<link>http://bashcurescancer.com/keeping-your-ssh-sessions-alive-with-noop.html</link>
		<comments>http://bashcurescancer.com/keeping-your-ssh-sessions-alive-with-noop.html#comments</comments>
		<pubDate>Wed, 12 Mar 2008 23:45:01 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/keeping-your-ssh-sessions-alive-with-noop.html</guid>
		<description><![CDATA[In the past, my SSH sessions died due to inactivity. In order to solve this, I used to: while true; do uptime; sleep 5;done Obviously, this eventually clears your terminal history. BASH to rescue! My noop script solves this problem. (Please see comments, there maybe a better solution, thanks David!) noop, standing for no operation, [...]]]></description>
			<content:encoded><![CDATA[<p>In the past, my SSH sessions died due to inactivity.  In order to solve this, I used to:</p>
<pre>while true; do uptime; sleep 5;done</pre>
<p>Obviously, this eventually clears your terminal history. BASH to rescue! My <a href="http://bashcurescancer.com/media/scripts/noop.txt">noop script</a> solves this problem. (Please see comments, there maybe a better solution, thanks David!) noop, standing for no operation, is a processor instruction and is common in protocols. You may find it interesting, that exploit code is filled with NOP&#8217;s. The operation increases your chances of exploiting <a href="http://en.wikipedia.org/wiki/Buffer_overflow#Nop_sled_technique">buffer overflows</a></p>
<p>The source:</p>
<pre>$ cat /usr/bin/noop
#!/bin/bash
backspace() {
        echo -e "\b\c"
}
cleanup() {
        backspace
        exit
}
trap "cleanup" 2
while :
do
        num=${RANDOM:0:1}
        printf $num
        sleep ".$num"
        backspace
done</pre>
<p>For the hell of it, I made a <a href="http://www.youtube.com/watch?v=BeBvp5gEyGU">video of noop in action</a>.</p>
<p>If your wondering how the script works, here is a quick explanation. The script defines two functions. backspace and cleanup. Backspace prints the special characters \b and \c.  Backslash b is a backspace, and backslash c, stops echo from printing a trailing newline:</p>
<pre>backspace() {
        echo -e "\b\c"
}</pre>
<p>The cleanup function prints a backspace and then exits.  The cleanup function is run by trap when it receives a SIGINT (2):</p>
<pre>cleanup() {
        backspace
        exit
}
trap "cleanup" 2</pre>
<p>The main body of the script, is an infinite loop which generates, a random number using the special variable $RANDOM. This random is assigned to the variable <em>num</em>, <a href="http://bashcurescancer.com/10-steps-to-beautiful-shell-scripts.html">utilizing only the first digit</a>. After printing that number, the script sleeps <em>num</em> tenths of seconds, and the backspace function is called:</p>
<pre>while :
do
        num=${RANDOM:0:1}
        printf $num
        sleep ".$num"
        backspace
done</pre>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/keeping-your-ssh-sessions-alive-with-noop.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>rpm2tgz &#8211; web interface and web service</title>
		<link>http://bashcurescancer.com/rpm2tgz-web-interface-and-web-service.html</link>
		<comments>http://bashcurescancer.com/rpm2tgz-web-interface-and-web-service.html#comments</comments>
		<pubDate>Sat, 23 Feb 2008 23:05:46 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/rpm2tgz-web-interface-and-web-service.html</guid>
		<description><![CDATA[My favorite site to convert rpm&#8217;s to tar gzip files appears to have shut down. As such, I wrote my own tool. It has a web interface: Convert a RPM to a tgz and (keeping inline with my thoughts on software) can be used from the command line. Five usage examples: $ wget -q "http://bashcurescancer.com/rpm2tgz.ws?url=http://bashcurescancer.com/media/rpm2tgz/telnet-0.17-39.el5.i386.rpm" [...]]]></description>
			<content:encoded><![CDATA[<p> My favorite site to convert rpm&#8217;s to tar gzip files appears to have shut down. As such, I wrote my own tool. It has a web interface: <a href="http://bashcurescancer.com/rpm2tgz.ws">Convert a RPM to a tgz</a> and (keeping inline with my thoughts on software) can be used from the command line.</p>
<p>Five usage examples:</p>
<pre>$ wget -q "http://bashcurescancer.com/rpm2tgz.ws?url=http://bashcurescancer.com/media/rpm2tgz/telnet-0.17-39.el5.i386.rpm"
$ ls -l telnet-0.17-39.el5.i386.tgz
-rw-r--r-- 1 noland noland 49804 Feb 23 17:09 telnet-0.17-39.el5.i386.tgz</pre>
<pre>$ curl -s -F "rpm=@telnet-0.17-39.el5.i386.rpm" \
"http://bashcurescancer.com/rpm2tgz.ws" &gt;telnet-0.17-39.el5.i386.tgz.1</pre>
<pre>$ curl -s -F "url=http://bashcurescancer.com/media/rpm2tgz/telnet-0.17-39.el5.i386.rpm" \
 http://bashcurescancer.com/rpm2tgz.ws &gt; telnet-0.17-39.el5.i386.tgz.2</pre>
<pre>$ curl -s "http://bashcurescancer.com/rpm2tgz.ws?url=ttp://bashcurescancer.com/media/rpm2tgz/telnet-0.17-39.el5.i386.rpm" \
&gt; telnet-0.17-39.el5.i386.tgz.3</pre>
<pre>$ wget -q -O telnet-0.17-39.el5.i386.tgz.4 \
"http://bashcurescancer.com/rpm2tgz.ws?url=http://bashcurescancer.com/media/rpm2tgz/telnet-0.17-39.el5.i386.rpm"</pre>
<p>Needless to say, if you abuse this, I will block your ip address from accessing the service. If there is an error the script will either return 404 File Not Found or 500 Internal Server Error and an empty body.  As such, you should be able to the -s expression of test, [, and [[ to check the validity of the file.</p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/rpm2tgz-web-interface-and-web-service.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Which comparator, test, bracket, or double bracket, is fastest?</title>
		<link>http://bashcurescancer.com/which-comparator-test-bracket-or-double-bracket-is-fastest.html</link>
		<comments>http://bashcurescancer.com/which-comparator-test-bracket-or-double-bracket-is-fastest.html#comments</comments>
		<pubDate>Thu, 24 Jan 2008 07:24:09 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[Beginners]]></category>
		<category><![CDATA[Good Practice]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[why?]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/which-comparator-test-bracket-or-double-bracket-is-fastest.html</guid>
		<description><![CDATA[The other day, I began wondering which comparator, test, [, or [[, was fastest? Here are the results: $ time for i in {1..100000}; do [[ -d . ]];done real 0m1.256s user 0m1.018s sys 0m0.238s $ time for i in {1..100000}; do [ -d . ];done real 0m3.407s user 0m2.704s sys 0m0.703s $ time for [...]]]></description>
			<content:encoded><![CDATA[<p>The other day, I began wondering which comparator, test, [, or [[, was fastest?  Here are the results:</p>
<pre>$ time for i in {1..100000}; do [[ -d . ]];done</pre>
<pre>real    0m1.256s
user    0m1.018s
sys     0m0.238s</pre>
<pre>
$ time for i in {1..100000}; do [ -d . ];done</pre>
<pre>real    0m3.407s
user    0m2.704s
sys     0m0.703s</pre>
<pre>
$ time for i in {1..100000}; do test -d .;done

real    0m3.223s
user    0m2.607s
sys     0m0.616s</pre>
<p>The double bracket is a "compound command" where as test and the single bracket are shell built-ins (and in actuality are the same command).  Thus, the single bracket and double bracket execute different code.</p>
<p>The test and single bracket are the most portable as they exist as separate and external commands.  However, if your using any remotely modern version of BASH, the double bracket is supported.</p>
<p>Here is the performance numbers on the external version of test and single bracket:</p>
<pre>$ time for i in {1..100000}; do /usr/bin/test -d .;done

real    5m49.324s
user    0m51.771s
sys     4m48.013s</pre>
<pre>$ time for i in {1..100000}; do /usr/bin/[ -d . ];done

real    5m45.728s
user    0m52.536s
sys     4m46.259s</pre>
<p>Wow! This shows the high cost of process creation!</p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/which-comparator-test-bracket-or-double-bracket-is-fastest.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>dssh &#8211; executing an arbitrary command in parallel on an arbitrary number of hosts</title>
		<link>http://bashcurescancer.com/dssh-executing-an-arbitrary-command-in-parallel-on-an-arbitrary-number-of-hosts.html</link>
		<comments>http://bashcurescancer.com/dssh-executing-an-arbitrary-command-in-parallel-on-an-arbitrary-number-of-hosts.html#comments</comments>
		<pubDate>Tue, 22 Jan 2008 02:05:22 +0000</pubDate>
		<dc:creator>Brock Noland</dc:creator>
				<category><![CDATA[script]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://bashcurescancer.com/dssh-executing-an-arbitrary-command-in-parallel-on-an-arbitrary-number-of-hosts.html</guid>
		<description><![CDATA[I asked &#8220;What do you want&#8221; and you said scripting. Which is good, because I have felt like scripting lately! I help a website hosting company, Idologic, on the weekends. (Side note: I highly recommend Idologic. I have worked with and been a customer of many other hosting companies. I really doubt you will find [...]]]></description>
			<content:encoded><![CDATA[<p>I asked &#8220;<a href="http://bashcurescancer.com/what-do-you-want.html">What do you want</a>&#8221; and you said scripting.  Which is good, because I have felt like scripting lately!</p>
<p>I help a website hosting company, <a href="http://idologic.com">Idologic,</a> on the weekends. (Side note: I highly recommend Idologic. I have worked with and been a customer of many other hosting companies. I really doubt you will find better <a href="http://www.serviceuntitled.com/">customer service</a> elsewhere.) Like many businesses these days, Idologic has quite a few Linux servers.  When presented with many servers, I typically want to parallelize my work.</p>
<p>As such, I have written a script called <a href="http://bashcurescancer.com/media/scripts/distributed-shell-scripts/dssh.sh">dssh</a> (<a href="http://bashcurescancer.com/media/scripts/distributed-shell-scripts/dssh-0.1.sh">previous version</a>), which allows you to execute commands on n hosts, in parallel. This can be used to find information on the hosts, such as load average, number of processes by user, number of processes by process name, etc.</p>
<p>There are other options such as <a href="http://www.theether.org/pssh/docs/0.2.3/pssh-HOWTO.html" target="_blank">pssh</a> and <a href="http://www.tuxrocks.com/Projects/p-run/">p-run</a>, however I wanted to create a shell solution which could be easily and simply &#8220;installed&#8221;. Dssh reads standard input. It expects one host per line. Host specific ssh options are supported. Here is my sample hosts file:</p>
<pre>$ cat hosts
mojito
-l noland kodiak
mojito
kodiak
-C mojito
-i /home/noland/.ssh/id_rsa kodiak</pre>
<p>There is nothing restricting you from generating this output from some type of meta data (I.E. database). Here are some examples of output:</p>
<pre>$ ./dssh.sh "uptime" &lt; hosts
First time huh? Think your cmd over and then try again.
$ ./dssh.sh "uptime" &lt; hosts
mojito:O:0:19:16:45 up 3 days, 14 min,  5 users,  load average: 0.22, 0.22, 0.20
kodiak:O:0:13:24:00 up 20:00,  1 user,  load average: 0.42, 0.16, 0.05
mojito:O:0:19:16:45 up 3 days, 14 min,  5 users,  load average: 0.22, 0.22, 0.20
kodiak:O:0:13:24:00 up 20:00,  1 user,  load average: 0.42, 0.16, 0.05
mojito:O:0:19:16:45 up 3 days, 14 min,  5 users,  load average: 0.22, 0.22, 0.20
kodiak:O:0:13:24:00 up 20:00,  1 user,  load average: 0.42, 0.16, 0.0</pre>
<pre>$ ./dssh.sh "pgrep -u noland | wc -w" &lt; hosts
mojito:O:0:60
kodiak:O:0:5
mojito:O:0:60
kodiak:O:0:5
mojito:O:0:60
kodiak:O:0:5</pre>
<pre>$ ./dssh.sh "ls not_a_file" &lt; hosts
mojito:E:2:ls: not_a_file: No such file or directory
kodiak:E:2:ls: not_a_file: No such file or directory
mojito:E:2:ls: not_a_file: No such file or directory
kodiak:E:2:ls: not_a_file: No such file or directory
mojito:E:2:ls: not_a_file: No such file or directory
kodiak:E:2:ls: not_a_file: No such file or directory</pre>
<p>Notes:</p>
<ol>
<li>With great power comes even greater responsibility. Running <strong>rm -rf /</strong> as root with this script would do exactly that.</li>
<li>I don&#8217;t reccomend doing anything with this script that &#8220;changes state&#8221;.</li>
<li>I make no warranties or promises.</li>
<li>You need <a href="http://bashcurescancer.com/setting_up_ssh_keys_for_access_without_password.html">ssh keys</a> to use this. I recommend using ssh-agent.</li>
<li>By default dssh will execute 10 children in parallel. If you have a large host, increase this.</li>
<li>When looping through the hosts, if the maximum number of children are still processing, the script will sleep 500ms. If your version of sleep does not support fractional seconds, you will need to change this.</li>
</ol>
<p>Here is an outline of the script:</p>
<ol>
<li>Read from standard input a list of hosts</li>
<li>Configure trap to remove temporary files on exit</li>
<li>For each host
<ol>
<li>Sleep while we have more children than the maximum number of children</li>
<li>Generate three temporary files, one for each of
<ol>
<li>Standard Output</li>
<li>Standard Error</li>
<li>Exit value</li>
</ol>
</li>
<li>Create a child process saving stdin, stderr, and the exit value in their respective files.</li>
</ol>
</li>
<li>Wait for all children to exit</li>
<li>For each host
<ol>
<li>If the standard output or error files are of size greater than zero, print the content, prefacing each line with the hostname, standard error/output indicator, and exit status.</li>
<li>Else print something to indicate we executed a process and have an exit value.</li>
</ol>
</li>
</ol>
<p>Once again, <a href="http://bashcurescancer.com/media/scripts/distributed-shell-scripts/dssh.sh">here is the script I am calling dssh.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://bashcurescancer.com/dssh-executing-an-arbitrary-command-in-parallel-on-an-arbitrary-number-of-hosts.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.293 seconds -->

