<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.0.4" -->
<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/"
	>

<channel>
	<title>Steven Kroon</title>
	<link>http://blog.stevenkroon.com</link>
	<description>Simplicity is the ultimate sophistication</description>
	<pubDate>Mon, 24 Dec 2007 08:30:17 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.4</generator>
	<language>en</language>
			<item>
		<title>Rails Tunnel plugin</title>
		<link>http://blog.stevenkroon.com/2007/12/23/rails-tunnel-plugin/</link>
		<comments>http://blog.stevenkroon.com/2007/12/23/rails-tunnel-plugin/#comments</comments>
		<pubDate>Sun, 23 Dec 2007 01:37:57 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Home</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2007/12/23/rails-tunnel-plugin/</guid>
		<description><![CDATA[Today I wanted to show someone a preview of some code I was writing for my Rails application, however didn&#8217;t feel like doing al the cumbersome work to transfer the files to my webserver and launch the application from there. I&#8217;ve been working on some ruby on rails facebook code lately and used the reverse [...]]]></description>
			<content:encoded><![CDATA[<p>Today I wanted to show someone a preview of some code I was writing for my Rails application, however didn&#8217;t feel like doing al the cumbersome work to transfer the files to my webserver and launch the application from there. I&#8217;ve been working on some ruby on rails facebook code lately and used the reverse tunnel configuration to test it out.</p>

<p>I figured it was easy to have a reverse tunnel for more application and especially the one i wanted to quickly show my friend.</p>

<p><a id="more-37"></a></p>

<p>Perhaps a plugin is a bit of overkill for just a rake task but what the heck here it is.</p>

<p>In order to install the plugin in your rails app just run</p>

<pre><code>$ ./script/plugin install http://svn.stevenkroon.com/plugins/tunnel
</code></pre>

<p>Now you should have access the specific tunnel rake tasks, you can run</p>

<pre><code>$ rake -T
</code></pre>

<p>From your rails root, and discover new tunnel specific tasks.</p>

<pre><code>rake tunnel:create_config            # Create reverse tunnel default config
rake tunnel:start                    # Starts a reverse tunnel
rake tunnel:status                   # Check if reverse tunnel is running
</code></pre>

<p>First thing todo is to create the tunnel config file, the easiest way is to run the create_config rake tastk.</p>

<pre><code>$ rake tunnel:create_config
</code></pre>

<p>Now you will have a config file called ./config/tunnel.yml, change this file according to your needs.</p>

<pre><code>remote_user: steven
remote_host: rails.stevenkroon.com
remote_port: 9999
local_port: 3000
</code></pre>

<p>The remote_user should be your ssh login name on the remote_host. If you just change the remote_user and remote_host configs, the only thing left todo is.</p>

<pre><code>$ rake tunnel:start
(in /Users/steven/svn/railstt)
* Tunneling rails.stevenkroon.com:9999 to 127.0.0.1:3000
* press ctrl-c to quit the tunnel
</code></pre>

<p>If you haven&#8217;t setup ssh authorization keys you will be prompted for the password of your remote_user. As the message states, a reverse tunnel on the remote_host on port remote_port is started, meaning that if you would connect against this url, in my case http://rails.stevenkroon.com:9999 you will get the output of whatever is running on 127.0.0.1:3000, in my case a ruby on rails project.</p>

<p>So if you launch your Rails application you can now see this application when going to the external hosts url.</p>

<p>Now this is just for quick test and should not be seen as a deployment for your rails app, just a easy way to have a external entry point into your application running on your localhost also this is needed when developing facebook application since the call back url need to point to your running application.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2007/12/23/rails-tunnel-plugin/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>scheduling tasks with at</title>
		<link>http://blog.stevenkroon.com/2007/03/26/scheduling-tasks-with-at/</link>
		<comments>http://blog.stevenkroon.com/2007/03/26/scheduling-tasks-with-at/#comments</comments>
		<pubDate>Mon, 26 Mar 2007 12:13:46 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Shell</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2007/03/26/scheduling-tasks-with-at/</guid>
		<description><![CDATA[In my next article i would like to get into at and batch. Instead of describing every available command line option and syntax there is, lets show some examples and nice ways to use both to schedule tasks from the command line.



There are a couple of commands which we are going to use in order [...]]]></description>
			<content:encoded><![CDATA[<p>In my next article i would like to get into <em>at</em> and <em>batch</em>. Instead of describing every available command line option and syntax there is, lets show some examples and nice ways to use both to schedule tasks from the command line.</p>

<p><a id="more-36"></a></p>

<p>There are a couple of commands which we are going to use in order the schedule the tasks, lets walk through all of them one at a time.</p>

<h1>at</h1>

<p>At alllows a fairly complex time format, but lets stick with the obvious format (at least which i find obvious).</p>

<pre><code>$ at now + 5 minutes
</code></pre>

<p>now at will accept commands from standard input, you will get a shell like prompt where you can type in your commands.</p>

<pre><code>at&gt; date &gt; /tmp/date
at&gt;
</code></pre>

<p>Now press CTRL+D, after that you will be dropped back to the shell and at will report to you at which time the command will be executed.</p>

<pre><code>at&gt; &lt;EOT&gt;
job 9 at Mon Mar 25 10:43:00 2007
</code></pre>

<p>Here you see that the command will be executed at 10:43:00, now that&#8217;s a coincident, it look like we typed our at command <em>exactly</em> within the first second of the 38th minute.</p>

<p>Let&#8217;s double check if it really works like this.</p>

<pre><code>$ echo 'echo "scheduling tasks in linux" &gt; /tmp/banner.txt' &gt; /tmp/schedule; \
date; \
at now + 1 minute -f /tmp/schedule
Mon Mar 26 10:49:54 CEST 2007
warning: commands will be executed using /bin/sh
job 12 at Mon Mar 26 10:50:00 2007
</code></pre>

<p>Here we use <strong>at</strong> a little different instead of letting <strong>at</strong> read our command from standard input, we use the -f command line option to let <strong>at</strong> read our command from a file. As you can see we create this file in the beginning then we print the date and then run at.</p>

<p>I&#8217;m consolidating this 3 separate commands on one line in order to be sure that the three almost happen instantly, so we don&#8217;t have much time skew here.</p>

<p>As you can see in the output we enter our at schedule at &#8220;10:49:54&#8243; you might have expected the execution of the at schedule to run at &#8220;10:50:54&#8243; since we did the &#8220;now + 1 minute&#8221;. However it runs the at schedule at &#8220;10:50:00&#8243;, so be aware that it will execute it at the full minute.</p>

<p>Also there is another thing to note in our output &#8220;warning: commands will be executed using /bin/sh&#8221;, what this means is that. When at invokes the commands in our at schedule it will spawn a new shell for this. So don&#8217;t expect to see output come bouncing back to your shell where you invoked the at schedule. However standard output and standard error will be e-mailed to shell user invoking the at schedule. These mail message will have a subject line like</p>

<p>Output from your job   42</p>

<p>In this case the mail body will contain the Output form at job 42.</p>

<p>Sometimes however you would also like to get notified if a job has run, when there is no output given you can do this with the -m parameter, e.g.</p>

<pre><code>$ echo 'date &gt; /dev/null' &gt; /tmp/jobs
$ at 10pm tomorrow -f /tmp/jobs -m
</code></pre>

<p>Even though this job will not output anything, at least it will be redirected to /dev/null, it will e-mail you about it.</p>

<p>Also you can see an other time format &#8220;10pm tomorrow&#8221;. Tomorrow is a easy way of specifying that a task as to run tomorrow, instead of looking at the exact date. There is also &#8220;today&#8221; if you want to specify today.</p>

<p>Lets show some other time formats, they are actually really simple to memorize because the almost read like a normal sentence.</p>

<pre><code>$ at march 29 2007 -f /tmp/jobs
</code></pre>

<p>We just tell it the month, day and year. If you specify it like this, the task will be executed on march 29 2007 and at the hour and minute you run at. If you want a different time you can specify this as well.</p>

<pre><code>$ at 6pm january 1 2008 -f /tmp/jobs
</code></pre>

<p>There is also a syntax which i use pretty often and that i using offsets. So let&#8217;s say you started a benchmark today and what to run it for a week you could do something like</p>

<pre><code>$ at 4pm + 7 days -f /tmp/stop-benchmark
</code></pre>

<p>This will run the commands in /tmp/stop-benchmark, however you can even write this much better.</p>

<pre><code>$ at 4pm + 1 week -f /tmp/stop-bencmark
</code></pre>

<h1>atq</h1>

<p>Okay now we have a tasks scheduled, now how do we see which tasks are actually scheduled? The atq command lists all the pending scheduled tasks. You could also use &#8220;at -l&#8221; to see the same results. Lets see it in action.</p>

<pre><code>$ atq
25      Mon Mar 26 23:05:00 2007 a steven
26      Mon Apr  2 18:00:00 2007 a steven
</code></pre>

<p>Here we see i&#8217;ve got two scheduled tasks pending, the first scheduled for March 26 at 23:05 and the later on April 2 at 18:00. Now i can&#8217;t even remember what the first task was, so lets look at what it actually does.</p>

<pre><code>$ at -c 25
#!/bin/sh
# atrun uid=1000 gid=1000
# mail steven 0
umask 22
USER=steven; export USER
MAIL=/var/mail/steven; export MAIL
PATH=/usr/sbin:/usr/bin:/sbin:/bin:export PATH
PWD=/home/steven; export PWD
LANG=en_US.UTF-8; export LANG
HISTCONTROL=ignoredups; export HISTCONTROL
SHLVL=1; export SHLVL
HOME=/home/steven; export HOME
LOGNAME=steven; export LOGNAME
cd /home/steven || {
         echo 'Execution directory inaccessible' &gt;&amp;2
         exit 1
}
date &gt; /dev/null
</code></pre>

<p>Here you can see that at records all the SHELL ENVIRONMENT variables at the time when at was invoked. So you can set environment variables when invoking at and it will record them so they are still available when the job start running.</p>

<h1>atrm</h1>

<p>All the way at the bottom of the previous output we see the actual command &#8220;date > /dev/null&#8221;. This was just a bogus job, since i used it only to test out some stuff. Lets remove it right away</p>

<pre><code>$ atrm 25
</code></pre>

<p>And it should be gone, lets verify</p>

<pre><code>$ atq
26      Mon Apr  2 18:00:00 2007 a steven
</code></pre>

<p>Yep job 25 is gone.</p>

<h1>batch</h1>

<p>Lets say we need to run some maintenance scripts todo some house keeping, but currently the system is under high load, so we don&#8217;t want to stress the server out even more with our maintenance jobs. We can however schedule this commands to be run whenever the load average drops below 1.5.</p>

<pre><code>$ batch
warning: commands will be executed using /bin/sh
at&gt; updatedb
at&gt; /usr/local/sbin/clean-database.rb
at&gt; &lt;EOT&gt;
job 32 at Mon Mar 26 14:02:00 2007
</code></pre>

<p>This 1.5 is the compiled in value, and you can change this value with the -l paramater of atd. You might want to change this value if you are in SMP environment.</p>

<p>Let&#8217;s look at the pending jobs.</p>

<pre><code>$ atq
32      Mon Mar 26 14:02:00 2007 b steven
26      Mon Apr  2 18:00:00 2007 a steven
</code></pre>

<p>There we see it, job number 32, notice that there is a &#8220;b&#8221; instead of a &#8220;a&#8221;, this column specifies in which Queue the job is. Queue a is the default queue &#8220;at&#8221; and Queue b is the default queue for &#8220;batch&#8221;.</p>

<p>There is also a special Queue called &#8220;=&#8221; this is queue is reserved for jobs which are currently running.</p>

<pre><code>$ at now + 1 minute
warning: commands will be executed using /bin/sh
at&gt; sleep 300
at&gt; &lt;EOT&gt;
job 33 at Mon Mar 26 14:08:00 2007
</code></pre>

<p>Now if we wait a little and check the running queue we can see it running.</p>

<pre><code>$ atq
32      Mon Mar 26 14:02:00 2007 b steven
26      Mon Apr  2 18:00:00 2007 a steven
33      Mon Mar 26 14:08:00 2007 = steven
</code></pre>

<p>That&#8217;s about it. There are some more advantaged features however these are the once i use the most and which seems to be the most practical once.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2007/03/26/scheduling-tasks-with-at/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Debian sapt</title>
		<link>http://blog.stevenkroon.com/2006/09/12/debian-sapt/</link>
		<comments>http://blog.stevenkroon.com/2006/09/12/debian-sapt/#comments</comments>
		<pubDate>Tue, 12 Sep 2006 17:56:11 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Debian</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2006/09/12/debian-sapt/</guid>
		<description><![CDATA[Do you find your self struggling with typing apt-cache search the whole time. It&#8217;s too time consuming and its easy to make a typo, typing in the whole string. There are quicker and easier ways accomplishing the same thing.



There should be a shortcut to this command if you ask me, nice thing is we can [...]]]></description>
			<content:encoded><![CDATA[<p>Do you find your self struggling with typing <em>apt-cache search</em> the whole time. It&#8217;s too time consuming and its easy to make a typo, typing in the whole string. There are quicker and easier ways accomplishing the same thing.</p>

<p><a id="more-31"></a></p>

<p>There should be a shortcut to this command if you ask me, nice thing is we can create it ourselfs. It would be nice just to be able to type in something simple like <em>search-apt</em> or even simpler <em>sapt packagename</em>, in fact it is pretty easy to make something like this.</p>

<p>There are a couple of ways doing the same thing. Here are a few ways of doing it.</p>

<h2>Alias</h2>

<p>The first method is using the aliasing mechanism. You can put this alias in your /etc/profile or perhaps in your ~/.profile or your what ever your shell reads upon login e.g. ~/.bashrc, what ever suites you best.</p>

<pre><code>$ alias sapt='apt-cache search $*'

$ sapt irb
irb - Interactive Ruby (irb)
irb1.6 - Interactive Ruby (irb) 1.6.x
lg-issue88 - Issue 88 of the Linux Gazette.
irb1.8 - Interactive Ruby (for Ruby 1.8)
</code></pre>

<p>As we can see it works perfectly, now lets put it in the /etc/profile file.</p>

<pre><code>$ echo -e "\nalias sapt='apt-cache search \$*'" |sudo tee -a /etc/profile

# Alias 'apt-cache search' into a single sapt command
alias sapt='apt-cache search $*'
</code></pre>

<h2>Bash Script</h2>

<p>You could also create a bash script, and place it in something like /usr/local/sbin/sapt, ofcourse make sure that /usr/local/sbin is in your $PATH environment variable.</p>

<pre><code>$ sudo tee /usr/local/sbin/sapt &lt;&lt; EOF
&gt; #!/bin/sh
&gt; apt-cache search \$*
&gt; EOF
#!/bin/sh
apt-cache search $* 
$ sudo chmod +x /usr/local/sbin/sapt
</code></pre>

<p>Now you can do:</p>

<pre><code>$ sapt irb
irb - Interactive Ruby (irb)
irb1.6 - Interactive Ruby (irb) 1.6.x
lg-issue88 - Issue 88 of the Linux Gazette.
irb1.8 - Interactive Ruby (for Ruby 1.8)
</code></pre>

<p>While I&#8217;m a pretty fast typer, but this still saved me a lot of time.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/09/12/debian-sapt/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Dig it!</title>
		<link>http://blog.stevenkroon.com/2006/09/12/dig-it/</link>
		<comments>http://blog.stevenkroon.com/2006/09/12/dig-it/#comments</comments>
		<pubDate>Tue, 12 Sep 2006 00:00:00 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Shell</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/1970/01/02/dig-it/</guid>
		<description><![CDATA[Resolving domain names can be very simple, besides what is so fascinating about looking up an ip address that belongs to a domain name? Well the domain naming system is a pretty complex piece of technology that you might take for granted. There are nice tools which are able to let you interact with this [...]]]></description>
			<content:encoded><![CDATA[<p>Resolving domain names can be very simple, besides what is so fascinating about looking up an ip address that belongs to a domain name? Well the domain naming system is a pretty complex piece of technology that you might take for granted. There are nice tools which are able to let you interact with this domain name system, one of them is dig, which is a acronym for <em>domain information groper</em>.</p>

<p>This tool can do more then just resolve domain names to ip addresses or visa versa. Lets look more closely into the world of domain name resolution and explorer the possibilites with dig. We will quickly run through the basics and at the end look at some nice features of dig.</p>

<p><a id="more-28"></a></p>

<h2>Basic query</h2>

<p>Let&#8217;s get straight to work, first we will do a basic ip address lookup. Lets say we would like to know which ip address is associated with <em>www.stevenkroon.com</em>. I&#8217;ve got a local name server with ip address 192.168.7.254, so i&#8217;ll be performing the query on this machine.</p>

<pre><code>$ dig @192.168.7.254 www.stevenkroon.com | cat -b

 1  ; &lt;&lt;&gt;&gt; DiG 9.2.4 &lt;&lt;&gt;&gt; @192.168.7.254 www.stevenkroon.com
 2  ;; global options:  printcmd
 3  ;; Got answer:
 4  ;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 55392
 5  ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 2

 6  ;; QUESTION SECTION:
 7  ;www.stevenkroon.com.           IN      A

 8  ;; ANSWER SECTION:
 9  www.stevenkroon.com.    86376   IN      CNAME   stevenkroon.com.
10  stevenkroon.com.        86376   IN      A       80.247.216.241

11  ;; AUTHORITY SECTION:
12  stevenkroon.com.        86376   IN      NS      ns1.bitrey.nl.
13  stevenkroon.com.        86376   IN      NS      ns2.bitrey.nl.

14  ;; ADDITIONAL SECTION:
15  ns1.bitrey.nl.          86376   IN      A       80.247.216.241
16  ns2.bitrey.nl.          86376   IN      A       80.247.216.247

17  ;; Query time: 2 msec
18  ;; SERVER: 192.168.7.254#53(192.168.7.254)
19  ;; WHEN: Sun Sep 10 21:30:13 2006
20  ;; MSG SIZE  rcvd: 144
</code></pre>

<p>As you can see i&#8217;ve run dig through <a href="http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/" title="dog is better than cat">cat</a> so we get some line numbering, which makes it easier to discuss certains parts of the output. These line numbers are not included when using dig. If you would like to read all about <a href="http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/" title="dog is better than cat">cat</a> please read <a href="http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/" title="dog is better than cat">dog is better than cat</a>.</p>

<p>As you can see the basic syntax is</p>

<pre><code>dig @server hostname type
</code></pre>

<p>Where <em>server</em> is the name or ip address of the name server you want to query and <em>name</em> is the resource record that is to lookup and finally the <em>type</em>, which can be ANY, A, MX, SIG, etc. You can omit the type, in this case it will look up a &#8220;A&#8221; record. &#8220;A&#8221; stands for &#8220;Address&#8221; which is just what we are looking for, so we dont need to specify it.</p>

<h2>Sections</h2>

<p>DNS packets are composed of five sections</p>

<p>The <strong>HEADER SECTION</strong> is present in every query and response, we will talk about this section later on.</p>

<p>The <strong>QUESTION SECTION</strong> tell us what we are doing, if you look at line 6 and 7 of the output, you see that in our case we are looking for the A record of <em>www.stevenkroon.com</em>. Maybe a good way to read this is query is <em>&#8220;We are looking for the address of www.stevenkroon.com&#8221;</em>.</p>

<p>On line 8 to 10 we have the <strong>ANSWER SECTION</strong>, this tells us what we asked for. There is a twist on line 9 though, the name server looked up the address but found out that it was not a &#8220;A&#8221; record, instead it was a CNAME to a other domain name. In this case the CNAME refers to <em>stevenkroon.com</em>. A CNAME record maps an alias to its canonical name, so line 9 can be read as <em>&#8220;www.stevenkroon.com maps to the ip address belonging to stevenkroon.com&#8221;. Because we were looking for the address associated with *www.stevenkroon.com</em> the name server also tries to resolve the A record of <em>stevenkroon.com</em>, this is what happens on line 10. So the answers to our query is <em>&#8220;www.stevenkroon.com has the same ip address as the domain stevenkroon.com which in turn has an ip address of 80.247.216.241&#8243;</em>.</p>

<p>The <strong>AUTHORITY SECTION</strong> tells us which name servers can give is a authoritative answers to our questions. The name servers that can give us these for &#8220;www.stevenkroon.com&#8221; are listed on line 12 and 13. So this means that if we query these name servers directly we can assume the this data is correct and not outdated because of caching on local name server. We will get to this issue later on.</p>

<p>And the <strong>ADDITIONAL SECTION</strong> adds information that may complete information included in other sections. For instance name servers that are listed in the authority section.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/09/12/dig-it/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>VMware DNS bug</title>
		<link>http://blog.stevenkroon.com/2006/09/04/vmware-dns-bug/</link>
		<comments>http://blog.stevenkroon.com/2006/09/04/vmware-dns-bug/#comments</comments>
		<pubDate>Mon, 04 Sep 2006 01:00:00 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>VMware</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2006/09/12/vmware-dns-bug/</guid>
		<description><![CDATA[While working with VMware ESX 3 lately me and a college discovered a bug. Thing was we could not connect the ESX nodes to Virtual Control Center. It had something todo with DNS lookups, lets look at what it was.



After a while of head scratching we thought lets try resolving the Virtual Control Center from [...]]]></description>
			<content:encoded><![CDATA[<p>While working with VMware ESX 3 lately me and a college discovered a bug. Thing was we could not connect the ESX nodes to Virtual Control Center. It had something todo with DNS lookups, lets look at what it was.</p>

<p><a id="more-32"></a></p>

<p>After a while of head scratching we thought lets try resolving the Virtual Control Center from one of the ESX nodes.</p>

<pre><code>$ dig vcc.test.stevenkroon.com
;; Truncated, retrying in TCP mode.
;; Connection to 192.168.7.254#53(192.168.7.254) for 
   vcc.test.stevenkroon.com failed: connection refused.
</code></pre>

<p>Aha! That&#8217;s strange, it can&#8217;t resolve the Virtual Control Centers ip address, probably ESX tries to resolve the hostname of the Virtual Control Center machine machine and can&#8217;t resolve it. But why is that?</p>

<p>If you know a little bit about DNS (if not you might consider reading <a href="http://blog.stevenkroon.com/2006/09/12/dig-it/">Dig it!</a> which gives a basic overview of DNS) you know that queries are send over UDP per default however, if there tend to be too much data to send back, resolvers drop the UDP packet and retry in TCP mode. Lets just ignore the truncation, and just receive the UDP packet and blindly accept its data was not mangled in transit.</p>

<pre><code>$ dig vcc.test.stevenkroon.com +ignore

; &lt;&lt;&gt;&gt; DiG 9.2.4 &lt;&lt;&gt;&gt; vcc.test.stevenkroon.com +ignore
;; global options:  printcmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 42395
;; flags: qr aa tc rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 23, ADDITIONAL: 0

;; QUESTION SECTION:
;vcc.test.stevenkroon.com.      IN      A

;; ANSWER SECTION:
vcc.test.stevenkroon.com. 86400 IN      A       192.168.7.2

;; AUTHORITY SECTION:
test.stevenkroon.com.   86400   IN      NS      ns10.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns11.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns12.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns13.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns14.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns15.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns16.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns17.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns18.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns19.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns20.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns21.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns22.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns23.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns24.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns25.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns26.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns27.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns28.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns29.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns30.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns31.test.stevenkroon.com.
test.stevenkroon.com.   86400   IN      NS      ns32.test.stevenkroon.com.

;; Query time: 5 msec
;; SERVER: 192.168.7.254#53(192.168.7.254)
;; WHEN: Tue Sep 12 20:11:57 2006
;; MSG SIZE  rcvd: 495
</code></pre>

<p>Ah so that does work, so the problem is related to DNS query that are done in TCP mode. Because this zone has so many NS records the size of the reply probably gets beyond the threshold to put this in a UDP packet, so our resolver tries to ask for the same query but then in TCP mode.  Lets look at the network traffic that gets send. From the nameserver I&#8217;ll be doing a tcpdump, just to look at what is happening out there.</p>

<pre><code>$ sudo tcpdump -qnei eth1 port 53 and host 192.168.7.3
 1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 2 listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
 3 14:32:40.339322 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 84: 
 . IP 192.168.7.3.32769 &gt; 192.168.7.254.53: UDP, length: 42
 4 14:32:40.343649 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 550: 
 . IP 192.168.7.254.53 &gt; 192.168.7.3.32769: UDP, length: 508
</code></pre>

<p>While the tcpdump was running I did a normal query for <em>vcc.test.stevenkroon.com</em>, as you can see on line number 3 and 4, these packets are UDP. However we don&#8217;t get a retry in TCP mode, we only see UDP packets on our nameserver. So why isn&#8217;t ESX sending us the TCP packets?</p>

<p>Firewalling could prevent us from sending out TCP DNS packets. Since this is a testing environment we can without troubles turn of the firewall.</p>

<pre><code>$ sudo /etc/init.d/firewall stop
Stopping firewall                                          [  OK  ]
</code></pre>

<p>With the firewall turn off lets try again.</p>

<pre><code>$ dig vcc.test.stevenkroon.com +short
;; Truncated, retrying in TCP mode.
192.168.7.2
</code></pre>

<p>Got &#8216;em! So there is something with this firewalling that prevents TCP DNS packets going out, we know this because we ware not receiving any TCP packets on our nameserver. Lets start the firewall again and look at the firewalling rules.</p>

<pre><code>$ sudo /etc/init.d/firewall start
Starting firewall                                          [  OK  ]
$ sudo /sbin/iptables -nL OUTPUT
Chain OUTPUT (policy DROP)
target     prot opt source          destination         
ACCEPT     all  --  0.0.0.0/0       0.0.0.0/0          
valid-tcp-flags tcp  --  0.0.0.0/0  0.0.0.0/0          
icmp-out   icmp --  0.0.0.0/0       0.0.0.0/0          
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp spts:1024:65535 dpt:53 
ACCEPT     all  --  0.0.0.0/0       0.0.0.0/0  state RELATED,ESTABLISHED 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpt:902 state NEW 
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp spts:67:68 dpts:67:68 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpts:2050:5000 state NEW 
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp dpts:2050:5000 state NEW 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpts:8042:8045 state NEW 
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp dpts:8042:8045 state NEW 
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp spt:427 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp spt:427 state NEW 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpt:27000 state NEW 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpt:27010 state NEW 
ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0  tcp dpt:21 ctstate NEW,RELATED 
ACCEPT     udp  --  0.0.0.0/0       0.0.0.0/0  udp dpt:902 state NEW 
REJECT     all  --  0.0.0.0/0       0.0.0.0/0  reject-with icmp-port-unreachable
</code></pre>

<p>Line number 6 on the output says:</p>

<pre><code>ACCEPT     udp  --  0.0.0.0/0        0.0.0.0/0  udp spts:1024:65535 dpt:53
</code></pre>

<p>This is the rule that allows UDP DNS packets going out, however there is no such rule for TCP packets, so this must be the root cause of why we are not getting any TCP DNS packets on our nameserver. Lets fix it!</p>

<pre><code>sudo /usr/sbin/esxcfg-firewall -o 53,tcp,out,dnsClientTCP
</code></pre>

<p>This will add the following line to the OUTPUT firewall chains:</p>

<pre><code>ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0          tcp dpt:53
</code></pre>

<p>That&#8217;s the theory, lets see if it actually works. The firwall is still turned on so we are good to go.</p>

<pre><code>$ dig vcc.test.stevenkroon.com +short
;; Truncated, retrying in TCP mode.
192.168.7.2
</code></pre>

<p>There we go! To wrap it up lets check the tcpdump output this time.</p>

<pre><code>$ sudo tcpdump -qnei eth1 port 53 and host 192.168.7.3
 1 15:06:38.178860 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 84:
 . IP 192.168.7.3.32769 &gt; 192.168.7.254.53: UDP, length: 42
 2 15:06:38.183241 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 549:
 . IP 192.168.7.254.53 &gt; 192.168.7.3.32769: UDP, length: 507
 3 15:06:38.184584 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 74:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 0
 4 15:06:38.184630 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 74:
 . IP 192.168.7.254.53 &gt; 192.168.7.3.33003: tcp 0
 5 15:06:38.184758 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 66:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 0
 6 15:06:38.184813 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 110:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 44
 7 15:06:38.184846 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 66:
 . IP 192.168.7.254.53 &gt; 192.168.7.3.33003: tcp 0
 8 15:06:38.189732 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 1235:
 . IP 192.168.7.254.53 &gt; 192.168.7.3.33003: tcp 1169
 9 15:06:38.190741 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 66:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 0
10 15:06:38.191177 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 66:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 0
11 15:06:38.191905 00:10:5a:37:15:ae &gt; 00:50:56:49:aa:45, IPv4, length 66:
 . IP 192.168.7.254.53 &gt; 192.168.7.3.33003: tcp 0
12 15:06:38.192035 00:50:56:49:aa:45 &gt; 00:10:5a:37:15:ae, IPv4, length 66:
 . IP 192.168.7.3.33003 &gt; 192.168.7.254.53: tcp 0
</code></pre>

<p>As you can see the first 2 lines are the orignal UDP packets, and after that are the TCP packets.</p>

<p>We talkd to the guys of VMware and agreed that this was indeed a bug, and it will be resolved in the upcoming versions of ESX 3.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/09/04/vmware-dns-bug/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Debian update-alternatives</title>
		<link>http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/</link>
		<comments>http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/#comments</comments>
		<pubDate>Tue, 29 Aug 2006 14:02:21 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Debian</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/</guid>
		<description><![CDATA[A real brilliant feature of Debian is the alternatives system. Couple of days ago i was playing with java. and I wanted both the Sun java and the Kaffe version installed on my system. The problem here is, how to easily tell wich java compiler to use, the sun version or kaffe? I&#8217;m a big [...]]]></description>
			<content:encoded><![CDATA[<p>A real brilliant feature of Debian is the <em>alternatives</em> system. Couple of days ago i was playing with java. and I wanted both the <a href="http://java.sun.com/" title="java.sun.com">Sun java</a> and the <a href="http://www.kaffe.org/" title="www.kaffe.org">Kaffe</a> version installed on my system. The problem here is, how to easily tell wich java compiler to use, the sun version or kaffe? I&#8217;m a big fan of the ruby language and i regularly switch between version of the ruby interpeter for testing. You could achieve this in a couple of ways, change the <a href="http://en.wikipedia.org/wiki/Shebang_%28Unix%29" title="wikipedia">shebang</a> to point to the correct version of the interpeter or don&#8217;t use the shebang but instead call the correct interpeter before executing each script or maybe you change the PATH and have the preferred interpeter somewhere in the beginning of your PATH. I don&#8217;t really like any of these solutions for various reasons, there is a solution and you might have guessed it &#8220;the alternatives system&#8221;.</p>

<p><a id="more-26"></a></p>

<p>NOTE: output of &#8220;ls -l&#8221; is edited in order to reduce the width on this page. Also command line commands might be truncated via the backslash character.</p>

<h2>Java</h2>

<p>Lets dive right in and start looking at the problems described above. The first problem we encountered was the java compiler. If you installed the sun java package via &#8220;java-package&#8221; package from debian then your all set, debian already configured the alternatives for you.</p>

<pre><code>$ java -version            
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)
</code></pre>

<p>This tells us that currently we are running the sun java version, also checkout the man page of java. Notice that NAME section reads.</p>

<pre><code>java - Java application launcher
</code></pre>

<p>If you scroll all the way to the bottom of the man page down to the SEE ALSO section, you see external links to the http://java.sun.com website. So clearly we are dealing with the sun java man pages as well. Like i said if you installed the &#8220;java-package&#8221; then debian has already setup the alternatives system for you. Let us inspect the java binary.</p>

<pre><code>$ which java
/usr/bin/java
$ ls -l /usr/bin/java
lrwxrwxrwx  /usr/bin/java -&gt; /etc/alternatives/java
</code></pre>

<p>As you can see the we tried to locate the java command we found that it was being execute from the /usr/bin path, however as you can see it&#8217;s a symbolic link and it links to /etc/alternatives/java. The /etc/alternatives directly is where all the alternatives are configured, let inspect a little further.</p>

<pre><code>$ ls -l /etc/alternatives/java
lrwxrwxrwx  /etc/alternatives/java -&gt; /usr/lib/j2re1.5-sun/bin/java
$ ls -l /usr/lib/j2re1.5-sun/bin/java
-rwxr-xr-x  /usr/lib/j2re1.5-sun/bin/java
</code></pre>

<p>There we go, another symbolic link, this time referring to /usr/lib/j2re1.5-sun/bin/java and a little digging afterwards reveals us that this is the real java executable. By now you might know how the alternatives system works or maybe you find it very inconvenient to have all these symlinks pointing to other symlinks and so on. What the alternatives system does is that it will link the executable in the default path to the appropriate file in /etc/alternatives and this will finally link to the executable we actually want to use. Because of this it becomes really easy to just update the symlink in alternatives directory and symlink it to the executable we want to use. We don&#8217;t do this linking by hand, there is a nice tool for us that manages the symlinks called &#8220;update-alternatives&#8221;.</p>

<p>Using update-alternatives we could quickly figure out which alternatives are currently configured for a certain executable. Let us look at the current setup of java.</p>

<pre><code>$ /usr/sbin/update-alternatives --display java
java - status is auto.
link currently points to /usr/lib/j2re1.5-sun/bin/java
/usr/lib/kaffe/bin/java - priority 300
slave java.1.gz: /usr/share/man/man1/java.kaffe.1.gz
/usr/lib/j2re1.5-sun/bin/java - priority 315
slave java.1.gz: /usr/lib/j2re1.5-sun/man/man1/java.1.gz
Current `best' version is /usr/lib/j2re1.5-sun/bin/java.
</code></pre>

<p>As you can see the current link point to /usr/lib/j2re1.5-sun/bin/java as we already discovered. There is another alternative which is /usr/lib/kaffe/bin/java and it has a priority of 300, the priority is important we will get to that shortly. The priority of /usr/lib/j2re1.5-sun/bin/java is 315. Did you notice the &#8220;java - status is auto.&#8221; on top? This means that the alternatives system will look at which package as the highest priority and uses that executable. Because of this the last line says that the current best priority link is /usr/lib/j2re1.5-sun/bin/java.</p>

<p>Now if we want to use kaffe instead, we can tell update-alternatives to use kaffe instead, let us do this by using the interactive mode.</p>

<pre><code>$ sudo /usr/sbin/update-alternatives --config java 

There are 2 alternatives which provide `java'.

Selection    Alternative
-----------------------------------------------
      1        /usr/lib/kaffe/bin/java
*+    2        /usr/lib/j2re1.5-sun/bin/java

Press enter to keep the default[*], or type selection number: 1
Using `/usr/lib/kaffe/bin/java' to provide `java'.
</code></pre>

<p>In interactive mode we see al the available alternatives for java. We already knew by looking at the &#8211;display output that there where only two option. Now we can select which option we want and as you can see i selected select number 1. No let&#8217;s look at the output of display again.</p>

<pre><code>$ /usr/sbin/update-alternatives --display java
java - status is manual.
link currently points to /usr/lib/kaffe/bin/java
/usr/lib/kaffe/bin/java - priority 300
slave java.1.gz: /usr/share/man/man1/java.kaffe.1.gz
/usr/lib/j2re1.5-sun/bin/java - priority 315
slave java.1.gz: /usr/lib/j2re1.5-sun/man/man1/java.1.gz
Current `best' version is /usr/lib/j2re1.5-sun/bin/java.
</code></pre>

<p>There we got &#8220;link currently points to /usr/lib/kaffe/bin/java&#8221; so let&#8217;s do the same checking as we did before.</p>

<pre><code>$ which java
/usr/bin/java
$ ls -l /usr/bin/java
lrwxrwxrwx  /usr/bin/java -&gt; /etc/alternatives/java
$ ls -l /etc/alternatives/java
lrwxrwxrwx  /etc/alternatives/java -&gt; /usr/lib/kaffe/bin/java
$ java -version
Kaffe Virtual Machine

Copyright (c) 1996-2004 Kaffe.org project contributors (please see
  the source code for a full list of contributors).  All rights reserved.
Portions Copyright (c) 1996-2002 Transvirtual Technologies, Inc.

The Kaffe virtual machine is free software, licensed under the terms of
the GNU General Public License.  Kaffe.org is a an independent, free software
community project, not directly affiliated with Transvirtual Technologies,
Inc.  Kaffe is a Trademark of Transvirtual Technologies, Inc.  Kaffe comes
with ABSOLUTELY NO WARRANTY.

Engine: Just-in-time v3   Version: 1.1.5   Java Version: 1.1
</code></pre>

<p>Only the link within the /etc/alternatives got changed just as we expected. When looking at the java version we see that it&#8217;s using the Kaffe Virtual Machine, great!</p>

<p>It gets even better, look at the man page of java. The NAME section now reads &#8220;kaffe - a virtual machine to execute Java(tm) bytecode&#8221;. So it not only changed the binary executable but also the man page. You might wonder how it knows this, if you paid attention to the output of &#8211;display you might have noticed the lines starting with <em>slave</em>.</p>

<pre><code>$ /usr/sbin/update-alternatives --display java
java - status is manual.
link currently points to /usr/lib/kaffe/bin/java
/usr/lib/kaffe/bin/java - priority 300
slave java.1.gz: /usr/share/man/man1/java.kaffe.1.gz
/usr/lib/j2re1.5-sun/bin/java - priority 315
slave java.1.gz: /usr/lib/j2re1.5-sun/man/man1/java.1.gz
Current `best' version is /usr/lib/j2re1.5-sun/bin/java.
</code></pre>

<p>With update-alternatives it&#8217;s possible to create a group of files which all have a relation with each other, just like our java.kaffe manpages having a relation with the kaffe java executable. This is done with slaves, looking at the &#8211;display output you can see that java.1.gz is a slave to the master file /usr/lib/kaffe/bin/java. So when the master file is changed so is the slave file.</p>

<p>You can also setup your own alternatives, let&#8217;s do this with our second problem which is having &#8220;different ruby interpeters&#8221;.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>dog is better than cat</title>
		<link>http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/</link>
		<comments>http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/#comments</comments>
		<pubDate>Thu, 24 Aug 2006 00:41:42 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Shell</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2006/08/23/dog-is-better-than-cat/</guid>
		<description><![CDATA[System Administrators are always looking for ways to make life easier. The command line is full of nice little features that can save you tons of time. Ever wondered how to remove all blank lines from a file or how to translate all uppercase characters to lowercase. In this article we will be focussing on [...]]]></description>
			<content:encoded><![CDATA[<p>System Administrators are always looking for ways to make life easier. The command line is full of nice little features that can save you tons of time. Ever wondered how to remove all blank lines from a file or how to translate all uppercase characters to lowercase. In this article we will be focussing on how to easily parse input or output.</p>

<p><a id="more-25"></a></p>

<h2>cat</h2>

<p>Everyone uses cat, cat stand for <em>catenate</em> or <em>concatenate</em>. www.answers.com says the following about the two words.</p>

<ol>
<li><em>To connect in a series of ties or links; form into a chain.</em></li>
<li><em>Computer Science. To arrange (strings of characters) into a chained list.</em></li>
</ol>

<p>So we can <strong>link</strong> or <strong>tie</strong> files together with cat, away for doing this would be.</p>

<pre><code>$ cat file1 file2
This is file1
This is file2
</code></pre>

<p>This would output the two files to standard output, we could also merge/catenate/link them into a single file.</p>

<pre><code>$ cat file1 file2 &gt; bothfiles
$ cat bothfiles
This is file1
This is file2
</code></pre>

<p>Lot&#8217;s of people use cat just for this. However there are more nice tricks to cat then just catenate. Lets dive into a couple of handy features. Sometimes text files contain a lot of white-lines after another. In order to reduce al those multiple white-lines into a single line you can use the &#8211;squeeze-blank option. First we will create a nice playground. As you might know cat can also read from standard input, for instance.</p>

<pre><code>$ echo -e "Hello world,\n\nWelcome to my blog." | cat
Hello world,

Welcome to my blog.
</code></pre>

<p>A bit useless you might think however it&#8217;s nice for the examples that will get to shortly. I used the -e option to echo which enables interpretation of the backslash-escaped characters, like \n to print a newline.</p>

<h3>Line numbers</h3>

<p>In order to print the line numbers we can use &#8211;number option to cat.</p>

<pre><code>$ echo -e "Hello world,\n\nWelcome to my blog." | cat -n
    1  Hello world,
    2
    3  Welcome to my blog.
</code></pre>

<h3>Squeeze</h3>

<p>I used the short option to &#8211;number which is -n. To get back to our &#8211;squeeze-blank subject let&#8217;s insert an extra \n to our text.</p>

<pre><code>$ echo -e "Hello world,\n\n\nWelcome to my blog." | cat -n
    1  Hello world,
    2
    3
    4  Welcome to my blog.
</code></pre>

<p>As you can see line 2 and line 3 both are white-lines. Image we have like 10 or even more consecutive white-lines. Using cat to read the file contents then these white-lines because useless let&#8217;s now squeeze them into a singe white-line.</p>

<pre><code>$ echo -e "Hello world,\n\n\nWelcome to my blog." | cat -n -s
    1  Hello world,
    2
    3  Welcome to my blog.
</code></pre>

<p>Here i also use the short option -s instead of the long &#8211;squeeze-blank. As you can see instead of 4 lines of text we get 3.</p>

<h3>Nonblank</h3>

<p>The &#8211;number option is really nice, it allows you to quickly identify a line with in a file. If your looking at a file with some other people you can easily talk about a certain line. If however you are not interested in all the white-lines you can also use the &#8211;number-nonblank option.</p>

<pre><code>$ echo -e "Hello world,\n\n\nWelcome to my blog." | cat -
    1  Hello world,


    2  Welcome to my blog.
</code></pre>

<h3>Line endings, TAB endings, etc</h3>

<p>Yep -b is the short option to &#8211;number-nonblank. Sometimes is really handy to know exactly where a line ends. For instance if you dont want any extra blank space at the end of a line &#8211;show-ends to the rescue.</p>

<pre><code>$ echo -e "Hello world,\n\n\nWelcome to my blog." | cat -n -E
    1  Hello world,$
    2  $
    3  $
    4  Welcome to my blog.$
</code></pre>

<p>Where -E is the short option for &#8211;show-ends. The same thing applies to tabs, if you wan to know if a certain piece of text uses tabs you can use the &#8211;show-tabs or -T which is the short option.</p>

<pre><code>$ echo -e "Steven\tKroon\n\nWelcome\t\t\t\tTo\nMy    Blog." | cat -n
    1  Steven  Kroon
    2
    3  Welcome                         To
    4  My    Blog.
</code></pre>

<p>Now lets look at the tabs.</p>

<pre><code>$ echo -e "Steven\tKroon\n\nWelcome\t\t\t\tTo\nMy    Blog." | cat -n -T
    1  Steven^IKroon
    2
    3  Welcome^I^I^I^ITo
    4  My    Blog.
</code></pre>

<p>As you can see the tabs are now replace by ^I, notice that line 4 does not contain a tab, although it looks like it in the output, it just contains 4 spaces instead of a tab. There is also a way to look for non-printable characters this can be done with &#8211;show-nonprinting. If you would like to look at all these things at once you can use the &#8211;show-all option to enable these flags at once.</p>

<pre><code>$ echo -e "Steven\tKroon\n\nWelcome\t\t\t\tTo\nMy    Blog." | cat -n -A
    1  Steven^IKroon$
    2  $
    3  Welcome^I^I^I^ITo$
    4  My    Blog.$
</code></pre>

<p>And -A being the short option. Well thats about it with the handy features for cat, lets get into a more advanced cat called dog.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/08/24/dog-is-better-than-cat/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>less is more</title>
		<link>http://blog.stevenkroon.com/2006/08/23/less-is-more/</link>
		<comments>http://blog.stevenkroon.com/2006/08/23/less-is-more/#comments</comments>
		<pubDate>Tue, 22 Aug 2006 23:24:27 +0000</pubDate>
		<dc:creator>steven</dc:creator>
		
	<dc:subject>Shell</dc:subject>
		<guid isPermaLink="false">http://blog.stevenkroon.com/2006/08/21/less-is-more/</guid>
		<description><![CDATA[Looking at file content is a trivial task, most people use more or less and take there usage for granted.  However there are some nice features that these utilities have to offer. Let&#8217;s start looking at some of them.



In the following descriptions, ^X means control-X.  ESC stands for the ESCAPE key; for example [...]]]></description>
			<content:encoded><![CDATA[<p>Looking at file content is a trivial task, most people use <em>more</em> or <em>less</em> and take there usage for granted.  However there are some nice features that these utilities have to offer. Let&#8217;s start looking at some of them.</p>

<p><a id="more-24"></a></p>

<p>In the following descriptions, ^X means control-X.  ESC stands for the ESCAPE key; for example ESC-v means the two character sequence &#8220;ESCAPE&#8221;, then &#8220;v&#8221;.</p>

<h2>more</h2>

<p>More is a filter for paging through text one screen at a time. There are two ways of using <em>more</em>.
You can use it from the command line and you can use <em>more</em> in interactive mode.</p>

<p>A nice feature of more is you can make it search for a certain keyword directly from the command line.
Lets say we where looking for the word <em>wowbagger</em> in a text file called <em>h2g2.txt</em> we could do.</p>

<pre><code>more +/wowbagger h2g2.txt
</code></pre>

<p>This will directly scroll to the first occurrence of wowbagger.</p>

<p>If would like to start reading at line number 50 we could just say.</p>

<pre><code>more +50 h2g2.txt
</code></pre>

<p>This would take us to line number 50.</p>

<p>The most important interactive command is <strong>h</strong> or <strong>?</strong> this displays a summary of interactive commands.  You can forget all the other commands, just remember this one.</p>

<p>Most people i know use complain about <em>more</em> because they think it cannot skip backwords, however this possible with the <strong>b</strong> or <strong>^B</strong> command. If you would like to know on which line number you are press <strong>=</strong>, this can give you a quick identification where you are.</p>

<p>Searching for patterns is probably the most import thing you would like todo, searching with <em>more</em> is really easy. Within interactive mode just type <strong>/</strong> and then the pattern you would like to search. So lets use our <em>h2g2.txt</em> file again.</p>

<pre><code>more h2g2.txt
</code></pre>

<p>Now within interactive mode type</p>

<pre><code>/wowbagger
</code></pre>

<p>This will scroll you down to the first occurrence of <em>wowbagger</em>. If you would like to search for the next occurrence just press the <strong>n</strong> command.</p>

<p>Ever happend that you where in the middle of a more session, searching for patterns etc, then all of a sudden you need to type a command in order to look something up. You can do a couple of things. Press <strong>q</strong> and do the command from the shell, loosing all your work within your <em>more</em> session. Open a new terminal, but if you are like me you probably all ready have a dozen of other terminals open. There is another alternative, say we would like to list the contents in the directory <em>/etc/apache</em>, within interactive mode just do the following</p>

<pre><code>!ls /etc/apache
</code></pre>

<p>This will list the contents from the <em>/etc/apache</em> directory in your more session. Sometimes this leave you with the output of your command scrambled through your <em>more</em> text. You can fix this by doing a <strong>^L</strong>, this will redraw the screen.</p>

<p>More is great however <em>more</em> is really primitive. That is why most people these days use <em>less</em> which we will get to right now.</p>
]]></content:encoded>
			<wfw:commentRSS>http://blog.stevenkroon.com/2006/08/23/less-is-more/feed/</wfw:commentRSS>
		</item>
	</channel>
</rss>
