<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title type="text">good coders code, great reuse</title>
  <id>http://www.catonmat.net/feed</id>
  <updated>2013-04-17T16:20:28Z</updated>
  <link href="http://www.catonmat.net" />
  
  <author>
    <name>Peteris Krumins</name>
    <uri>http://www.catonmat.net/about</uri>
    <email>peter@catonmat.net</email>
  </author>
  <subtitle type="text">Peteris Krumins' blog about programming, hacking, software reuse, software ideas, computer security, google and technology.</subtitle>
  <icon>http://www.catonmat.net/favicon.ico</icon>
  <generator uri="http://www.catonmat.net" version="v1.0">catonmat blog</generator>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/catonmat" /><feedburner:info uri="catonmat" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>catonmat</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry xml:base="http://www.catonmat.net/feed">
    <title type="text">I published another 10 of my projects to GitHub</title>
    <id>383</id>
    <updated>2013-04-17T16:20:28Z</updated>
    <published>2013-04-11T16:55:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/JHj_3SYOYRI/i-published-another-10-of-my-projects-to-github" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Remember my previous two blog posts about publishing &lt;a href="http://www.catonmat.net/blog/i-pushed-30-of-my-projects-to-github/"&gt;30&lt;/a&gt; and &lt;a href="http://www.catonmat.net/blog/i-pushed-20-more-of-my-projects-to-github/"&gt;20&lt;/a&gt; of my projects to github? Here are another 10 projects in no particular order that I've written since then.&lt;/p&gt;
&lt;p&gt;I really love writing open source projects. Everyone should publish all their projects to github. Good or bad. Like &lt;a href="https://twitter.com/substack"&gt;my friend&lt;/a&gt; just said: "Publish more open source, not less. "Too much noise" is a terrible excuse. Publish wisdom so we may use. Publish mistakes so we may learn."&lt;/p&gt;
&lt;p&gt;If you find my projects interesting, consider &lt;a href="https://github.com/pkrumins"&gt;following me on github&lt;/a&gt;! Thank you!&lt;/p&gt;
&lt;h2&gt;Shorten urls with bitly without api&lt;/h2&gt;
&lt;p&gt;This is a Perl module that shortens urls via bitly without using their API. I once had to shorten more than a few hundred urls quickly so I wrote this.&lt;/p&gt;
&lt;p&gt;Here's an example of how to use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;bitly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$bitly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitly&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitly&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;shorten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;http://www.url.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$bitly&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/bitly"&gt;bitly shortener on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Speak text files to wav via Microsoft Speech API&lt;/h2&gt;
&lt;p&gt;I once had this idea of converting my blog posts to mp3. So I wrote a C++ program that uses the Microsoft's speech api. It takes a txt file as input and produces a wav file output. &lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre &gt;
speak.exe &amp;lt;voice name&gt; &amp;lt;text file&gt; &amp;lt;wav file&gt;
-or-
speak.exe --list-voices
&lt;/pre&gt;
&lt;p&gt;Compile this project with Microsoft Visual Studio 2008 or later.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/speak-text-files-to-wav"&gt;speak-text-files-to-wav on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bonus: At first I tried using Loquendo SDK and created a &lt;a href="https://github.com/pkrumins/TextToWav"&gt;TextToWav&lt;/a&gt; project but their speech engine wasn't too great so I created speak-text-files-to-wav.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/TextToWav"&gt;TextToWav on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Load status server for Windows&lt;/h2&gt;
&lt;p&gt;This simple C++ program creates a single threaded TCP server that replies with information in JSON format about Window's CPU, Disk, and Memory usage. I created this because I had to monitor Windows servers at &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre &gt;
C:\bin\&gt; load-status-server.exe
Started server on port 7000
&lt;/pre&gt;
&lt;p&gt;Now if you connect to server.com:7000, it will send you JSON with the current server load info:&lt;/p&gt;
&lt;pre &gt;
$ nc server.com 7000
{
    "memory": {
        "usage": 71,
        "total_physical": 1068388352,
        "free_physical": 302112768,
        "total_paging_file": 3096842240,
        "free_paging_file": 2155446272,
        "total_virtual": 2147352576,
        "free_virtual": 2130919424,
        "free_extended_virtual": 0
    },
    "cpu": {
        "load": 5
    },
    "disk": {
        "free_user": 22858027008,
        "free_total": 22858027008,
        "total": 42947571712
    }
}
&lt;/pre&gt;
&lt;p&gt;Compile this project with Visual Studio or mingw. It uses just Win32 calls.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/load-status-server"&gt;load-status-server on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HWND finder&lt;/h2&gt;
&lt;p&gt;We started working on a new product at &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt; that takes screenshots so I wrote a bunch of code that finds browser window HWNDs. Then I decided to open source some parts of it and created HWND finder. The idea is to have something like jQuery's syntax for finding HWNDs. We delayed launching this screenshot product so I haven't made any updates.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="cp"&gt;#include &amp;quot;hwnd-finder.h&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;HwndFinder&lt;/span&gt; &lt;span class="n"&gt;hf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;HWND&lt;/span&gt; &lt;span class="n"&gt;rendererHwnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Chrome_WidgetWin_1 &amp;gt; Chrome_WidgetWin_0 &amp;gt; Chrome_RenderWidgetHostHWND&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This finds Chrome renderer's window handle. Here Chrome_RenderWidgetHostHWND is a child of Chrome_WidgetWin_0 is a child of Chrome_WidgetWin_1 which is the top window.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/hwnd-finder"&gt;hwnd-finder on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;node-number-range&lt;/h2&gt;
&lt;p&gt;This is a node.js module that streams number ranges. Here are all the ranges it supports:&lt;/p&gt;
&lt;pre &gt;
var range = require('number-range');

* range(10) - range from 0 to 9
* range(-10, 10) - range from -10 to 9 (-10, -9, ... 0, 1, ... 9)
* range(-10, 10, 2) - range from -10 to 8, skipping every 2nd element (-10, -8, ... 0, 2, 4, 6, 8)
* range(10, 0, 2) - reverse range from 10 to 1, skipping every 2nd element (10, 8, 6, 4, 2)
* range(10, 0) - reverse range from 10 to 1
* range('5..50') - range from 5 to 49
* range('50..44') - range from 50 to 45
* range('1,1.1..4') - range from 1 to 4 with increment of 0.1 (1, 1.1, 1.2, ... 3.9)
* range('4,3.9..1') - reverse range from 4 to 1 with decerement of 0.1
* range('[1..10]') - range from 1 to 10 (all inclusive)
* range('[10..1]') - range from 10 to 1 (all inclusive)
* range('[1..10)') - range grom 1 to 9
* range('[10..1)') - range from 10 to 2
* range('(1..10]') - range from 2 to 10
* range('(10..1]') - range from 9 to 1
* range('(1..10)') - range from 2 to 9
* range('[5,10..50]') - range from 5 to 50 with a step of 5 (all inclusive)
* range('10..') - infinite range starting from 10
* range('(10..') - infinite range starting from 11
&lt;/pre&gt;
&lt;p&gt;Very cool stuff. Especially the infinite ranges, which use the process.nextTick trick.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/node-number-range"&gt;node-number-range on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HTTP::Async::Retry&lt;/h2&gt;
&lt;p&gt;It's almost HTTP::Async::Retry. It's actually just a async_retry.pm file that you can drop into your project to do a quick hack. With a bit of effort it could be HTTP::Async::Retry.&lt;/p&gt;
&lt;p&gt;I once had to scrape a lot of information so I used my favorite language Perl and used the &lt;a href="http://search.cpan.org/~kaoru/HTTP-Async-0.13/lib/HTTP/Async.pm"&gt;HTTP::Async&lt;/a&gt; module. A lot of URLs would time out as I was creating thousands of connections per second. At first I simply copied the retry code from hack to hack but then at one moment I had enough so I simply wrote async_retry.pm that abstracts away the retries.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;HTTP::&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;async_retry&lt;/span&gt; &lt;span class="sx"&gt;qw/async_retry/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;http://www.google.com/1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;http://www.google.com/2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;http://www.google.com/3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;http://www.google.com/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;http://www.google.com/5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;async_retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;HTTP::&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@urls&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This code tries to get all those Google urls and retries to get them 5 times. If a url succeeds or fails after retries, it calls the callback with HTTP::Request and HTTP::Response objects.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/http-async-retry"&gt;http-async-retry on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HTML Keyboard Widget&lt;/h2&gt;
&lt;p&gt;This is just an on-screen keyboard widget for &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt;. I wrote it because people with weird keyboard layouts couldn't input various English characters in Browserling. We'll add it to Browserling soon (it's a planned feature.)&lt;/p&gt;
&lt;p&gt;Here's how it looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/keyboard.png"&gt;&lt;/p&gt;
&lt;p&gt;You can try a &lt;a href="http://www.catonmat.net/ftp/keyboard/"&gt;live demo here&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/keyboard"&gt;keyboard on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Cached browser badges&lt;/h2&gt;
&lt;p&gt;This project just creates cached browser badges for &lt;a href="http://www.testling.com"&gt;Testling&lt;/a&gt;, so that we don't have to generate them again as it's costly.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/testling/testling-ci-test-example-badge.png"&gt;&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/browser-badge-cached"&gt;browser-badge-cached on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;~/.ssh/authorized_keys ssh key manager&lt;/h2&gt;
&lt;p&gt;This project manages public ssh keys in ~/.ssh/authorized_keys file. We'll use this at &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt; to manage the ssh keys for tunnels so that you can add, remove and list the keys. (It's a planned feature.)&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sshManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ssh-key-manager&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;sshManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pkrumins&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ssh-rsa AAAAB3NzaC1y...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/ssh-key-manager"&gt;ssh-key-manager on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;node-tree-kill&lt;/h2&gt;
&lt;p&gt;This is a node.js module that kills all processes in the process tree, including the given root process.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;kill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tree-kill&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SIGKILL&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In this example we kill all the children processes of the process with pid 301, including the process with pid 301 itself.&lt;/p&gt;
&lt;p&gt;This module currently works on Linux only as it uses &lt;code&gt;ps -o pid --no-headers --ppid PID&lt;/code&gt; to find the parent pids of &lt;code&gt;PID&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/pkrumins/node-tree-kill"&gt;node-tree-kill on github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GitHub is awesome!&lt;/h2&gt;
&lt;p&gt;Push all your projects to github all the time! Don't let your project rot on your hard drive! Publish it to github! Publish wisdom so we may use. Publish mistakes so we may learn.&lt;/p&gt;
&lt;p&gt;And just another reminder, I'd love if you followed me on &lt;a href="http://www.github.com/pkrumins"&gt;github&lt;/a&gt; and &lt;a href="http://www.twitter.com/pkrumins"&gt;twitter&lt;/a&gt;! :)&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=JHj_3SYOYRI:g5YEcEQvUEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=JHj_3SYOYRI:g5YEcEQvUEA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=JHj_3SYOYRI:g5YEcEQvUEA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=JHj_3SYOYRI:g5YEcEQvUEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=JHj_3SYOYRI:g5YEcEQvUEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=JHj_3SYOYRI:g5YEcEQvUEA:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=JHj_3SYOYRI:g5YEcEQvUEA:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/JHj_3SYOYRI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/i-published-another-10-of-my-projects-to-github</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">A Simple LD_PRELOAD Tutorial</title>
    <id>381</id>
    <updated>2013-04-01T10:13:40Z</updated>
    <published>2013-03-31T23:00:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/imxB8BJCA0M/simple-ld-preload-tutorial" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;This is going to be a super short and super simple tutorial for beginners about LD_PRELOAD. If you're familiar with LD_PRELOAD, you'll learn nothing new. Otherwise keep reading!&lt;/p&gt;
&lt;p&gt;Did you know you could override the C standard library's functions (such as printf, fopen, etc) with your own version of these functions in any program? In this article I'll teach you how this can be done through the LD_PRELOAD environment variable.&lt;/p&gt;
&lt;p&gt;Let's start with a simple C program (prog.c):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Calling the fopen() function...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fopen() returned NULL&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fopen() succeeded&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The code above simply makes a call to the standard fopen function and then checks its return value. Now, let's compile and execute it:&lt;/p&gt;
&lt;pre &gt;
$ ls
prog.c  test.txt

$ gcc prog.c -o prog

$ ls
prog  prog.c  test.txt

$ ./prog
Calling the fopen() function...
fopen() succeeded
&lt;/pre&gt;
&lt;p&gt;Now let's write our own version of fopen and compile it as a shared library:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Always failing fopen&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let's call this file &lt;code&gt;myfopen.c&lt;/code&gt;, and let's compile it as a shared library:&lt;/p&gt;
&lt;pre &gt;
gcc -Wall -fPIC -shared -o myfopen.so myfopen.c
&lt;/pre&gt;
&lt;p&gt;Now we can simply modify LD_PRELOAD:&lt;/p&gt;
&lt;pre &gt;
$ LD_PRELOAD=./myfopen.so ./prog
Calling the fopen() function...
Always failing fopen
fopen() returned NULL
&lt;/pre&gt;
&lt;p&gt;As you can see the &lt;code&gt;fopen&lt;/code&gt; got replaced with our own version that is always failing. This is really handy if you've to debug or replace certain parts of libc or any other shared library.&lt;/p&gt;
&lt;p&gt;Next time I'll write about how the LD_PRELOAD works internally.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=imxB8BJCA0M:q1VzUQlDf-s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=imxB8BJCA0M:q1VzUQlDf-s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=imxB8BJCA0M:q1VzUQlDf-s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=imxB8BJCA0M:q1VzUQlDf-s:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=imxB8BJCA0M:q1VzUQlDf-s:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=imxB8BJCA0M:q1VzUQlDf-s:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=imxB8BJCA0M:q1VzUQlDf-s:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/imxB8BJCA0M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/simple-ld-preload-tutorial</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Visualization of Regular Expression Character Classes</title>
    <id>378</id>
    <updated>2013-02-25T19:28:13Z</updated>
    <published>2013-02-25T19:15:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/x_OSqh_DbD0/regex-char-classes" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;We all know the regular expression character classes, right? There are 12 standard classes:&lt;/p&gt;
&lt;pre &gt;
[:alnum:]  [:digit:]  [:punct:]
[:alpha:]  [:graph:]  [:space:]
[:blank:]  [:lower:]  [:upper:]
[:cntrl:]  [:print:]  [:xdigit:]
&lt;/pre&gt;
&lt;p&gt;But have you seen a visual representation of what these classes match? Probably not. Therefore I created a visualization that illustrates which part of the ASCII set each character class matches. Call it a cheat sheet if you like:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://www.catonmat.net/download/character-class-cheat-sheet-small.png"&gt;&lt;img src="http://www.catonmat.net/images/regex-char-classes/character-class-cheat-sheet-preview.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.catonmat.net/download/character-class-cheat-sheet-small.png"&gt;small version&lt;/a&gt;, &lt;a href="http://www.catonmat.net/download/character-class-cheat-sheet-large.png"&gt;large version&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;h2&gt;A bunch of programs that I used&lt;/h2&gt;
&lt;p&gt;Just for my own reference, in case I ever need them again, here are the one-liners I used to create this cheat sheet:&lt;/p&gt;
&lt;pre &gt;
perl -nle 'printf "%08b - %08b\n", map { hex "0x".(split / /)[0], hex "0x".(split / /)[1] } $_ '
perl -nle 'printf "%03o - %03o\n", map { (split / /)[0], (split / /)[1] } $_'
&lt;/pre&gt;
&lt;p&gt;And I used this perl program to generate and check the red/green matches:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;\e[31m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;\e[32m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$clear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;\e[0m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@ARGV&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;start or end not given&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;qw/alnum alpha blank cntrl digit graph lower print punct space upper xdigit/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;${green}1${clear}&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sr"&gt;/[[:$class:]]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;${red}0${clear}&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="sr"&gt;/[[:$class:]]/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;Credits&lt;/h2&gt;
&lt;p&gt;I was inspired to create this visualization when I saw a similar table for &lt;a href="http://en.cppreference.com/w/c/string/byte"&gt;C's ctype.h character classification functions&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x_OSqh_DbD0:Q4I35pJcgTY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x_OSqh_DbD0:Q4I35pJcgTY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=x_OSqh_DbD0:Q4I35pJcgTY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x_OSqh_DbD0:Q4I35pJcgTY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=x_OSqh_DbD0:Q4I35pJcgTY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x_OSqh_DbD0:Q4I35pJcgTY:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x_OSqh_DbD0:Q4I35pJcgTY:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/x_OSqh_DbD0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/regex-char-classes</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">TCP Traceroute</title>
    <id>361</id>
    <updated>2013-02-25T02:26:06Z</updated>
    <published>2013-02-24T19:20:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/p6lY8KhYQFQ/tcp-traceroute" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Did you know you could traceroute over the TCP protocol?&lt;/p&gt;
&lt;p&gt;The regular &lt;code&gt;traceroute&lt;/code&gt; usually uses either ICMP or UDP protocols. Unfortunately firewalls and routers often block the ICMP protocol completely or disallow the ICMP echo requests (ping requests), and/or block various UDP ports.&lt;/p&gt;
&lt;p&gt;However you'd rarely have firewalls and routers drop TCP protocol on port 80 because it's the web's port.&lt;/p&gt;
&lt;p&gt;Check this out. Let's try to traceroute www.microsoft.com using ICMP protocol:&lt;/p&gt;
&lt;pre &gt;
# traceroute -I www.microsoft.com  
traceroute to www.microsoft.com (65.55.57.27), 30 hops max, 60 byte packets
 1  50.57.125.2 (50.57.125.2)  0.552 ms  0.647 ms  0.742 ms
 2  core1-aggr701a-3.ord1.rackspace.net (184.106.126.50)  0.415 ms  0.555 ms  0.653 ms
 3  corea.ord1.rackspace.net (184.106.126.128)  0.707 ms  0.873 ms  0.984 ms
 4  bbr1.ord1.rackspace.net (184.106.126.147)  1.345 ms  1.341 ms  1.337 ms
 5  * * *
 6  204.152.140.33 (204.152.140.33)  3.614 ms  3.747 ms  3.244 ms
 7  xe-0-2-0-0.ch1-96c-2b.ntwk.msn.net (207.46.46.49)  3.319 ms  4.019 ms  4.010 ms
 8  ge-7-0-0-0.co1-64c-1a.ntwk.msn.net (207.46.40.94)  53.543 ms  53.105 ms  53.074 ms
 9  xe-5-2-0-0.co1-96c-1b.ntwk.msn.net (207.46.40.165)  52.942 ms  52.710 ms  52.670 ms
10  * * *
11  * * *
12  * * *
13  * * *
&lt;/pre&gt;
&lt;p&gt;We get lots of &lt;code&gt;* * *&lt;/code&gt; and we've no idea how the packets reach www.microsoft.com.&lt;/p&gt;
&lt;p&gt;Now let's try UDP traceroute:&lt;/p&gt;
&lt;pre &gt;
# traceroute -U www.microsoft.com
traceroute to www.microsoft.com (65.55.57.27), 30 hops max, 60 byte packets
 1  50.57.125.2 (50.57.125.2)  0.529 ms  0.599 ms  0.662 ms
 2  core1-aggr701a-3.ord1.rackspace.net (184.106.126.50)  0.480 ms  0.571 ms  0.658 ms
 3  corea.ord1.rackspace.net (184.106.126.128)  0.507 ms corea.ord1.rackspace.net (184.106.126.124)  0.463 ms  0.569 ms
 4  bbr1.ord1.rackspace.net (184.106.126.145)  1.345 ms  1.322 ms  1.290 ms
 5  * * *
 6  * 204.152.140.35 (204.152.140.35)  2.697 ms *
 7  xe-0-2-0-0.ch1-96c-2b.ntwk.msn.net (207.46.46.49)  3.665 ms ge-7-0-0-0.co1-64c-1a.ntwk.msn.net (207.46.40.94)  53.363 ms  52.597 ms
 8  xe-3-1-0-0.co1-96c-1b.ntwk.msn.net (207.46.33.190)  52.284 ms  52.643 ms xe-0-1-0-0.co1-96c-1a.ntwk.msn.net (207.46.33.177)  52.665 ms
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
&lt;/pre&gt;
&lt;p&gt;Same. Finally let's try traceroute over TCP protocol port 80:&lt;/p&gt;
&lt;pre &gt;
# traceroute -T -p 80 www.microsoft.com
traceroute to www.microsoft.com (65.55.57.27), 30 hops max, 60 byte packets
 1  50.57.125.2 (50.57.125.2)  0.540 ms  0.629 ms  0.709 ms
 2  core1-aggr701a-3.ord1.rackspace.net (184.106.126.50)  0.486 ms  0.604 ms  0.691 ms
 3  corea.ord1.rackspace.net (184.106.126.128)  0.511 ms corea.ord1.rackspace.net (184.106.126.124)  0.564 ms  0.810 ms
 4  bbr1.ord1.rackspace.net (184.106.126.147)  1.339 ms  1.310 ms bbr1.ord1.rackspace.net (184.106.126.145)  1.307 ms
 5  chi-8075.msn.net (206.223.119.27)  3.619 ms  2.560 ms  2.528 ms
 6  * 204.152.140.35 (204.152.140.35)  3.640 ms *
 7  ge-7-0-0-0.co1-64c-1a.ntwk.msn.net (207.46.40.94)  52.523 ms xe-0-2-0-0.ch1-96c-2b.ntwk.msn.net (207.46.46.49)  3.825 ms xe-1-2-0-0.ch1-96c-2b.ntwk.msn.net (207.46.46.53)  3.355 ms
 8  xe-0-1-0-0.co1-96c-1a.ntwk.msn.net (207.46.33.177)  61.042 ms  61.032 ms  60.457 ms
 9  * * xe-5-2-0-0.co1-96c-1b.ntwk.msn.net (207.46.40.165)  100.069 ms
10  65.55.57.27 (65.55.57.27)  53.868 ms  53.038 ms  52.097 ms
&lt;/pre&gt;
&lt;p&gt;A full network path to www.microsoft.com!&lt;/p&gt;
&lt;p&gt;There are various different traceroute implementations and if your system doesn't have one that supports tcp protocol, I suggest you either get &lt;a href="http://traceroute.sourceforge.net/"&gt;the new modern implementation of traceroute&lt;/a&gt;, or get the &lt;a href="http://michael.toren.net/code/tcptraceroute/"&gt;tcptraceroute&lt;/a&gt; by Michael Toren.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=p6lY8KhYQFQ:nhwZng059n8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=p6lY8KhYQFQ:nhwZng059n8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=p6lY8KhYQFQ:nhwZng059n8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=p6lY8KhYQFQ:nhwZng059n8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=p6lY8KhYQFQ:nhwZng059n8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=p6lY8KhYQFQ:nhwZng059n8:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=p6lY8KhYQFQ:nhwZng059n8:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/p6lY8KhYQFQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/tcp-traceroute</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Browserling now has Internet Explorer 10!</title>
    <id>363</id>
    <updated>2013-01-22T21:44:08Z</updated>
    <published>2013-01-22T21:45:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/d3JEo7JI3FQ/browserling-now-has-ie10" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Just a quick update on &lt;a href="http://browserling.com"&gt;Browserling&lt;/a&gt;. We just launched IE 10s! IE 10s are available to all our paying customers. The free browserling version offers IE 9.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://www.catonmat.net/images/browserling-ies/ie10-full.png" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/browserling-ies/ie10.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.catonmat.net/images/browserling-ies/ie10-full.png"&gt;Internet Explorer 10.0.9200.16466&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Next we're getting Mac OSX browsers and iPhone emulators. Stay tuned! Follow us on twitter for updates - &lt;a href="http://twitter.com/browserling"&gt;@browserling&lt;/a&gt;, &lt;a href="http://twitter.com/testling"&gt;@testling&lt;/a&gt;, &lt;a href="http://twitter.com/substack"&gt;@substack&lt;/a&gt;, &lt;a href="http://twitter.com/pkrumins"&gt;@pkrumins&lt;/a&gt;.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://browserling.com" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/browserling.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://browserling.com"&gt;Try Browserling!&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Browserling is an interactive cross-browser testing tool. It lets you test your website in older Internet Explorers such as IE 6, IE 7, IE 8 and IE 9, IE 10, Firefox, Chrome, Opera and Safari!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=d3JEo7JI3FQ:Uba1NGsyAcw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=d3JEo7JI3FQ:Uba1NGsyAcw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=d3JEo7JI3FQ:Uba1NGsyAcw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=d3JEo7JI3FQ:Uba1NGsyAcw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=d3JEo7JI3FQ:Uba1NGsyAcw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=d3JEo7JI3FQ:Uba1NGsyAcw:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=d3JEo7JI3FQ:Uba1NGsyAcw:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/d3JEo7JI3FQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/browserling-now-has-ie10</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Idea for later - a 1:1 teaching meetup network</title>
    <id>370</id>
    <updated>2013-01-21T18:01:59Z</updated>
    <published>2013-01-21T17:10:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/ULTS6LwCUGE/one-to-one-teaching-meetup-network" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;I thought I'd share this idea I've had for a while and that I want to build in the future. It's a 1:1 teaching network where people meet up and have 1:1 sessions teaching each other things they don't know. I've found that 1:1 teaching sessions are much more effective than a group teaching session or learning on your own. In a 1:1 teaching session you can keep asking the other person questions instantly and infinitely and you can learn really advanced topics really quickly.&lt;/p&gt;
&lt;p&gt;Here's an example of how this meetup network would work. Let's say I'm an expert in Python. And let's say you're an expert in Ruby. And let's say you want to master Python and I want to master Ruby. So we schedule a meet up and I teach you Python for a few hours, and you teach me Ruby for a few hours. And we rescheduling meetups whenever we're both available.&lt;/p&gt;
&lt;p&gt;The way I imagine it could be built is having a website where you indicate where you're at, what you're a master at, indicate what you want to master, and indicate the time that you've available. The system then matches you with someone and suggests a meetup.&lt;/p&gt;
&lt;p&gt;I'd teach and learn and teach and learn forever this way!&lt;/p&gt;
&lt;p&gt;There are so many other ideas that I want to build and I'll just keep sharing them in my "ideas for later" blog post series! See ya!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=ULTS6LwCUGE:Q3XQK-kb31k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=ULTS6LwCUGE:Q3XQK-kb31k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=ULTS6LwCUGE:Q3XQK-kb31k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=ULTS6LwCUGE:Q3XQK-kb31k:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=ULTS6LwCUGE:Q3XQK-kb31k:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=ULTS6LwCUGE:Q3XQK-kb31k:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=ULTS6LwCUGE:Q3XQK-kb31k:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/ULTS6LwCUGE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/one-to-one-teaching-meetup-network</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">How to write Testling-CI tests</title>
    <id>362</id>
    <updated>2013-01-19T00:32:46Z</updated>
    <published>2013-01-18T23:35:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/BhJhm3DlRoI/howto-write-testling-ci-tests" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Writing &lt;a href="http://www.catonmat.net/blog/announcing-testling-ci/"&gt;testling-ci&lt;/a&gt; tests is super easy. The only thing your test runner needs to do is to produce &lt;a href="http://testanything.org/"&gt;TAP output&lt;/a&gt; on console.log or process.stdout.&lt;/p&gt;
&lt;p&gt;Let's create a new node module called &lt;a href="https://github.com/pkrumins/testling-ci-test-example"&gt;testling-ci-test-example&lt;/a&gt; and let's add cross-browser tests to it. Once the tests run, you get a badge like this that shows in which browsers your code works:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a class="nohover" href="http://ci.testling.com/pkrumins/testling-ci-test-example"&gt;&lt;img src="http://www.catonmat.net/images/testling/testling-ci-test-example-badge.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;If you click the badge you go to the test status page.&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;First, let's create index.js that exports a few functions, some of which work in some browsers and fail in others:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="c1"&gt;// doesn&amp;#39;t work in IE&amp;lt;9&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timesTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// works everywhere&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timesThree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now let's write tests for this module. We'll put tests in &lt;code&gt;tests/test.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tape&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;exampleLib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;../index.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;timesTwo test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exampleLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timesTwo&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;timesThree test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exampleLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timesThree&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The tests use &lt;a href="https://github.com/substack/tape"&gt;tape&lt;/a&gt; module that &lt;code&gt;console.log&lt;/code&gt;'s TAP formatted output.&lt;/p&gt;
&lt;p&gt;Now let's add &lt;code&gt;testling&lt;/code&gt; field to &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="s2"&gt;&amp;quot;testling&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;test/*.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;browsers&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;ie&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;ff&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;16.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;17.0&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;chrome&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;safari&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mf"&gt;5.1&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;opera&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Finally, let's setup the github hook and point it to &lt;code&gt;git.testling.com&lt;/code&gt;. First go to the settings of the repository,&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/testling/howto-1-settings.png"&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Next, go to the service hooks,&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/testling/howto-2-service-hooks.png"&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Then, choose WebHook URLs,&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/testling/howto-3-webhooks.png"&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Finally, type &lt;code&gt;git.testling.com&lt;/code&gt; in the webhook URL field and press update settings,&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/testling/howto-4-git-testling-com.png"&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;And we're done. If we visit &lt;a href="http://ci.testling.com/pkrumins/testling-ci-test-example"&gt;http://ci.testling.com/pkrumins/testling-ci-test-example&lt;/a&gt; we'll see the badge and which browsers the tests succeeded and in which browsers the code failed:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a class="nohover" href="http://ci.testling.com/pkrumins/testling-ci-test-example"&gt;&lt;img src="http://www.catonmat.net/images/testling/testling-ci-test-example-badge.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;We can instantly see that the code fails in IE6, IE7, and IE8 because these versions of IE don't have &lt;code&gt;Array.prototype.map&lt;/code&gt;, and that the code works everywhere else. So awesome!&lt;/p&gt;
&lt;p&gt;For more information about testling-ci see &lt;a href="http://ci.testling.com"&gt;ci.testling.com&lt;/a&gt;.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://ci.testling.com" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/testling/testling-ci.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://ci.testling.com"&gt;ci.testling.com&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;h2&gt;About Browserling&lt;/h2&gt;
&lt;p&gt;Our mission at Browserling Inc is to make the developers' life easier. Follow us on twitter for updates - &lt;a href="http://twitter.com/browserling"&gt;@browserling&lt;/a&gt;, &lt;a href="http://twitter.com/testling"&gt;@testling&lt;/a&gt;, &lt;a href="http://twitter.com/substack"&gt;@substack&lt;/a&gt;, &lt;a href="http://twitter.com/pkrumins"&gt;@pkrumins&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BhJhm3DlRoI:VY2qYQvIBtY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BhJhm3DlRoI:VY2qYQvIBtY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=BhJhm3DlRoI:VY2qYQvIBtY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BhJhm3DlRoI:VY2qYQvIBtY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=BhJhm3DlRoI:VY2qYQvIBtY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BhJhm3DlRoI:VY2qYQvIBtY:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BhJhm3DlRoI:VY2qYQvIBtY:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/BhJhm3DlRoI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/howto-write-testling-ci-tests</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Announcing Testling-CI</title>
    <id>346</id>
    <updated>2013-02-27T01:00:47Z</updated>
    <published>2013-01-16T17:25:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/gYsWH3vHkZk/announcing-testling-ci" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;We at Browserling are proud to announce Testling-CI! Testling-CI lets you write continuous integration cross-browser tests that run on every &lt;u&gt;git push&lt;/u&gt;!&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://ci.testling.com" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/testling/testling-ci.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://ci.testling.com"&gt;ci.testling.com&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;There are a ton of modules on npm and github that aren't just for node.js but for browsers, too. However, figuring out which browsers these modules work with can be tricky. It's often that case that some module used to work in browsers but has accidentally stopped working because the developer hadn't checked that their code still worked recently enough. If you use npm for frontend and backend modules, this can be particularly frustrating.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ci.testling.com"&gt;Testling-CI&lt;/a&gt; (&lt;a href="http://ci.testling.com"&gt;http://ci.testling.com&lt;/a&gt;) is a service for running your browser tests on every commit. Just add a "testling" field to your package.json like this:&lt;/p&gt;
&lt;pre &gt;
"testling" : {
    "files" : "test/*.js",
    "browsers" : {
        "iexplore" : [ "6.0", "7.0", "8.0", "9.0" ],
        "chrome" : [ "20.0" ],
        "firefox" : [ "10.0", "15.0" ],
        "safari" : [ "5.1" ],
        "opera" : [ "12.0" ]
    }
}
&lt;/pre&gt;
&lt;p&gt;Then add a &lt;a href="https://help.github.com/articles/post-receive-hooks"&gt;github webhook&lt;/a&gt; for &lt;code&gt;http://git.testling.com&lt;/code&gt; and your browser tests will be run on every commit in exactly the browsers you've specified!&lt;/p&gt;
&lt;p&gt;Once the tests run you get a badge you can put in your readme with the current browser test status. Here's how it looks:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a class="nohover" href="http://ci.testling.com/substack/node-falafel"&gt;&lt;img src="http://www.catonmat.net/images/testling/node-falafel-badge.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;If you click the badge you go to the test status page.&lt;/p&gt;
&lt;p&gt;All your tests need to do is output TAP-formatted text output. Many test harnesses already support this format and the protocol is simple enough that you can just console.log() valid output yourself.&lt;/p&gt;
&lt;p&gt;We recommend using &lt;a href="https://github.com/substack/tape"&gt;tape&lt;/a&gt; to output TAP or if you use Mocha, we've a &lt;a href="https://github.com/substack/mocha-testling-ci-example"&gt;testling-ci example using Mocha&lt;/a&gt;. We'll support many more test harnesses later.&lt;/p&gt;
&lt;p&gt;Your browser tests can even use node-style require()s bundled with &lt;a href="https://github.com/substack/node-browserify"&gt;browserify&lt;/a&gt; so that you can use exactly the same tests for node and the browser. If your browser tests aren't written the node way you can still run them with the "scripts" field. See &lt;a href="http://ci.testling.com/"&gt;testling-ci homepage&lt;/a&gt; for full documentation.&lt;/p&gt;
&lt;p&gt;This service is free for open source modules published to github. If you want to run this service on your private repos, &lt;a href="http://browserling.com/contact"&gt;contact us&lt;/a&gt; and we can enroll you in our testling professional edition beta!&lt;/p&gt;
&lt;p&gt;For full documentation and more examples visit &lt;a href="http://ci.testling.com/"&gt;ci.testling.com&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;About Browserling&lt;/h2&gt;
&lt;p&gt;Our mission at Browserling Inc is to make the developers' life easier. Testling-CI is our third product. Take a look our first two products &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt; and &lt;a href="http://www.testling.com"&gt;Testling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Browserling lets you do manual cross-browser testing in all major browsers, such as Internet Explorer 6, 7, 8, 9; Chrome; Safari; Firefox and Opera.&lt;/p&gt;
&lt;p&gt;Testling lets you do automated cross-browser JavaScript testing. You write your tests in JavaScript and we run them on the browsers and tell you the results. Testling-CI is built on top of Testling.&lt;/p&gt;
&lt;p&gt;We're also soon launching our fourth amazing product. Stay tuned! Follow us on twitter for updates - &lt;a href="http://twitter.com/browserling"&gt;@browserling&lt;/a&gt;, &lt;a href="http://twitter.com/testling"&gt;@testling&lt;/a&gt;, &lt;a href="http://twitter.com/substack"&gt;@substack&lt;/a&gt;, &lt;a href="http://twitter.com/pkrumins"&gt;@pkrumins&lt;/a&gt;.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;big&gt;&lt;strong&gt;Important Update:&lt;/strong&gt;&lt;/big&gt;&lt;/p&gt;
&lt;p&gt;&lt;big&gt;&lt;strong&gt;We've changed goals are we're not launching a fourth product.&lt;/strong&gt;&lt;/big&gt;&lt;/p&gt;
&lt;p&gt;&lt;big&gt;&lt;strong&gt;We've retired Testling as we built Testling-CI.&lt;/strong&gt;&lt;/big&gt;&lt;/p&gt;
&lt;p&gt;&lt;big&gt;&lt;strong&gt;All questions about Testling-CI: feedback@browserling.com&lt;/strong&gt;&lt;/big&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=gYsWH3vHkZk:ZL42wdYjr1E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=gYsWH3vHkZk:ZL42wdYjr1E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=gYsWH3vHkZk:ZL42wdYjr1E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=gYsWH3vHkZk:ZL42wdYjr1E:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=gYsWH3vHkZk:ZL42wdYjr1E:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=gYsWH3vHkZk:ZL42wdYjr1E:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=gYsWH3vHkZk:ZL42wdYjr1E:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/gYsWH3vHkZk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/announcing-testling-ci</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">The `sudo chroot /chroot su - user -c "cmd args"` trick</title>
    <id>365</id>
    <updated>2012-12-27T23:08:52Z</updated>
    <published>2012-12-24T16:40:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/7sCYjqVhgMc/chroot-su-sh-trick" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Ok, this is going to be an article for beginners but with a spin at the end even for the most advanced users. Let's say you want to run a command inside of chroot as another user all in a single command and be back at your shell. How do you do it? Turns out it can be easily done by combining several commands in a beautiful way:&lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot su - user -c "cmd args"
&lt;/pre&gt;
&lt;p&gt;It may seem a pretty crazy combination of commands but it's all really easy to undestand. First, let's take a look at &lt;code&gt;man chroot&lt;/code&gt;. It says, &lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot command
&lt;/pre&gt;
&lt;p&gt;Okay, so we can run &lt;code&gt;command&lt;/code&gt; inside of chroot as root, but how do we run the command inside of chroot as another user? How about using &lt;code&gt;su&lt;/code&gt; for &lt;code&gt;command&lt;/code&gt;? Let's try that:&lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot su - user
&lt;/pre&gt;
&lt;p&gt;This runs &lt;code&gt;su&lt;/code&gt; inside of chroot as &lt;code&gt;user&lt;/code&gt; but we get an interactive shell. Let's take a closer look at &lt;code&gt;man su&lt;/code&gt;. It says that we could try:&lt;/p&gt;
&lt;pre &gt;
sudo su - user -c "cmd args"
&lt;/pre&gt;
&lt;p&gt;This runs the &lt;code&gt;cmd args&lt;/code&gt; through the shell. Great! So let's use this together with &lt;code&gt;chroot&lt;/code&gt; again:&lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot su - user -c "cmd args"
&lt;/pre&gt;
&lt;p&gt;Excellent! Almost what we needed. &lt;strong&gt;However&lt;/strong&gt; there is still one small problem. If the &lt;code&gt;user&lt;/code&gt; has a custom environment (such as different &lt;code&gt;PATH&lt;/code&gt;s to executables or some other customizations), it won't get initialized, so we've to source the initialization file(s) ourselves:&lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot su - user -c ". ~/.bash_profile; cmd args"
&lt;/pre&gt;
&lt;p&gt;This does what we wanted and runs &lt;code&gt;cmd args&lt;/code&gt; inside of chroot located at &lt;code&gt;/new-root-path&lt;/code&gt; as &lt;code&gt;user&lt;/code&gt; and after running the command it quits and we're back at our shell.&lt;/p&gt;
&lt;p&gt;What a beautiful way to combine commands!&lt;/p&gt;
&lt;h2&gt;On Sourcing ~/.bash_profile&lt;/h2&gt;
&lt;p&gt;Some people couldn't understand why I was sourcing &lt;code&gt;~/.bash_profile&lt;/code&gt;. The reason is because I was unable to find another way to invoke the login shell and have the environment initialized. &lt;/p&gt;
&lt;p&gt;I tried this:&lt;/p&gt;
&lt;pre &gt;
sudo chroot /chroot su -l user -c "cmd args"
&lt;/pre&gt;
&lt;p&gt;And it just &lt;b&gt;wouldn't&lt;/b&gt; execute &lt;code&gt;~/.bash_profile&lt;/code&gt;. Su's man page says that &lt;code&gt;-l&lt;/code&gt; invokes a login shell, however I don't see that happening. Here's the transcript that demonstrates it:&lt;/p&gt;
&lt;pre &gt;
pkrumins$ pwd
/chroot

pkrumins$ sudo cat ./home/testuser1/.bash_profile 
echo "moo"
PATH="/test/bin"

pkrumins$ sudo chroot /chroot su -l testuser1 -c 'echo $PATH'
/bin:/usr/bin

pkrumins$ sudo chroot /chroot su -l testuser1 
moo

testuser1$ echo $PATH
/test/bin

testuser1$ ^D
logout

pkrumins$ sudo chroot /chroot su -l testuser1 -c '. ~/.bash_profile; echo $PATH'       
moo
/test/bin

pkrumins$ sudo chroot /chroot su -l testuser1
moo

testuser1$ /bin/bash -l -c 'echo $PATH'
moo
/test/bin
&lt;/pre&gt;
&lt;p&gt;This definitely looks like a bug in &lt;code&gt;su&lt;/code&gt; to me when &lt;code&gt;-l&lt;/code&gt; and &lt;code&gt;-c&lt;/code&gt; are used together. So the only way to get the environment loaded is by sourcing the initialization files yourself.&lt;/p&gt;
&lt;h2&gt;Update&lt;/h2&gt;
&lt;p&gt;I went through &lt;code&gt;su&lt;/code&gt;'s source code (can be found in &lt;a href="http://www.kernel.org/pub/linux/utils/util-linux/"&gt;util-linux&lt;/a&gt; package) and it turns out it's &lt;strong&gt;not a bug&lt;/strong&gt; in &lt;code&gt;su&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Here are the arguments that &lt;code&gt;su&lt;/code&gt; passes to &lt;code&gt;execv&lt;/code&gt; when I run &lt;code&gt;su user -c 'echo $PATH'&lt;/code&gt; (see &lt;code&gt;run_shell&lt;/code&gt; function in &lt;code&gt;su.c&lt;/code&gt;):&lt;/p&gt;
&lt;pre &gt;
shell: /bin/bash
args[0]: -bash
args[1]: -c
args[2]: echo $PATH
&lt;/pre&gt;
&lt;p&gt;As you can see, &lt;code&gt;args[0][0]&lt;/code&gt; is &lt;code&gt;-&lt;/code&gt;, which makes bash a login shell, so bash should be executing the startup files, but it does not!&lt;/p&gt;
&lt;p&gt;To figure out what was happening, I built a custom version of bash and added a bunch of debugging statements. I found that there are two different login-shell states! Who'd have thought? One that you get when you've set &lt;code&gt;args[0][0]&lt;/code&gt; to &lt;code&gt;-&lt;/code&gt;, the other that you get when you've used the &lt;code&gt;-l&lt;/code&gt; argument (to bash, not su!).&lt;/p&gt;
&lt;p&gt;In case &lt;code&gt;args[0][0]&lt;/code&gt; is &lt;code&gt;-&lt;/code&gt;, and you're using &lt;code&gt;-c&lt;/code&gt; to execute code, bash will not execute startup files because it's in this "non-interactive positive-login-shell" state. However if you use &lt;code&gt;-l&lt;/code&gt; and &lt;code&gt;-c&lt;/code&gt;, it goes into "non-interactive negative-login-shell" state, and it will execute startup files (see &lt;code&gt;run_startup_files&lt;/code&gt; function in bash's &lt;code&gt;shell.c&lt;/code&gt; source file).&lt;/p&gt;
&lt;p&gt;That was one hell of an adventure debugging this. So if you want bash to execute startup files through &lt;code&gt;su&lt;/code&gt;, use my ". ~/.bash_profile" sourcing trick! (Or define &lt;code&gt;NON_INTERACTIVE_LOGIN_SHELLS&lt;/code&gt; when building bash).&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=7sCYjqVhgMc:U2zOPvbHNH4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=7sCYjqVhgMc:U2zOPvbHNH4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=7sCYjqVhgMc:U2zOPvbHNH4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=7sCYjqVhgMc:U2zOPvbHNH4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=7sCYjqVhgMc:U2zOPvbHNH4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=7sCYjqVhgMc:U2zOPvbHNH4:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=7sCYjqVhgMc:U2zOPvbHNH4:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/7sCYjqVhgMc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/chroot-su-sh-trick</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Bash One-Liners Explained, Part V: Navigating around</title>
    <id>335</id>
    <updated>2012-11-27T18:24:23Z</updated>
    <published>2012-11-27T17:00:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/Klm8zg850RM/bash-one-liners-explained-part-five" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;This is the fifth part of the &lt;strong&gt;Bash One-Liners Explained&lt;/strong&gt; article series. In this part I'll teach you how to quickly navigate around the command line in bash using emacs-style keyboard shortcuts. That's right, emacs-style keyboard shortcuts. It might surprise you but by default bash uses emacs-style keyboard shortcuts for navigating around the command line. Keep reading to learn more!&lt;/p&gt;
&lt;p&gt;See the &lt;a href="http://www.catonmat.net/blog/bash-one-liners-explained-part-one/"&gt;first part&lt;/a&gt; of the series for introduction. After I'm done with the series I'll release an ebook (similar to my ebooks on &lt;a href="http://www.catonmat.net/blog/awk-book/"&gt;awk&lt;/a&gt;, &lt;a href="http://www.catonmat.net/blog/sed-book/"&gt;sed&lt;/a&gt;, and &lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;perl&lt;/a&gt;), and also bash1line.txt (similar to my &lt;a href="http://www.catonmat.net/download/perl1line.txt"&gt;perl1line.txt&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Also see my other articles about working fast in bash:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/"&gt;Definitive Guide to Bash Command Line History&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/"&gt;Working Productively in Bash's Vi Command Line Editing Mode (comes with a cheat sheet)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Parts of this post are based on my earlier post &lt;a href="http://www.catonmat.net/blog/bash-emacs-editing-mode-cheat-sheet/"&gt;Working Productively in Bash's Emacs Command Line Editing Mode&lt;/a&gt;. Check it out, too!&lt;/p&gt;
&lt;p&gt;And grab &lt;a href="http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf"&gt;the emacs keyboard shortcut cheat sheet&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Let's start.&lt;/p&gt;
&lt;h2&gt;Part V: Navigating around in emacs mode&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;0. Introduction to input editing modes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Bash uses the &lt;a href="http://www.gnu.org/software/readline/"&gt;readline library&lt;/a&gt; for input editing. The readline library supports emacs style key bindings, vi style key bindings as well as custom key bindings. By default readline will use the emacs style key bindings but you can easily switch to vi editing mode or customize them.&lt;/p&gt;
&lt;p&gt;You can switch between the emacs and vi editing modes through &lt;code&gt;set -o emacs&lt;/code&gt; and &lt;code&gt;set -o vi&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;The key bindings can be customized through the &lt;code&gt;~/.inputrc&lt;/code&gt; file or the &lt;code&gt;bind&lt;/code&gt; command. For example, &lt;code&gt;bind '"\C-f": "ls\n"'&lt;/code&gt; binds CTRL+f to execute &lt;code&gt;ls&lt;/code&gt; command. You can learn more about readline's key binding syntax by consulting the readline section of the bash man page.&lt;/p&gt;
&lt;p&gt;I'll cover the emacs editing mode in this article. In the next two articles I'll cover the vi editing mode and customizing readline.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. Move to the beginning of the line&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-a.png" alt="Press Ctrl+a"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+a moves the cursor to the beginning of the line. Here's an illustration. Let's say you've typed &lt;code&gt;cd info&lt;/code&gt; in the terminal:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-a-before.gif" alt="Before pressing Ctrl+a"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+a moves the cursor to the beginning of the line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-a-after.gif" alt="After pressing Ctrl+a"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. Move to the end of the line&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-e.png" alt="Press Ctrl+e"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+e moves the cursor to the end of the line. Here's an illustration. Let's say you've typed &lt;code&gt;mkdir foo bar baz&lt;/code&gt; in the terminal and your cursor is somewhere in the middle:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-e-before.gif" alt="Before pressing Ctrl+e"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+e moves the cursor to the end of the line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-e-after.gif" alt="After pressing Ctrl+e"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. Move one word backward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-b.png" alt="Press Esc+b or Alt+b"&gt;&lt;/p&gt;
&lt;p&gt;Esc+b or Alt+b moves the cursor one word backward. You'll often see Meta+b but there is no such key on the keyboards anymore. Therefore either Esc+b or Alt+b will work, depending on how your terminal is configured.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you've typed &lt;code&gt;echo 'hello world'&lt;/code&gt; in the terminal and your cursor is after &lt;code&gt;hello&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-b-before.gif" alt="Before pressing Meta+b"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Esc+b or Alt+b moves the cursor one word backward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-b-after.gif" alt="After pressing Meta+b"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. Move one word forward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-f.png" alt="Press Esc+f or Alt+f"&gt;&lt;/p&gt;
&lt;p&gt;Esc+f or Alt+f moves the cursor one word forward. Here's an illustration. Let's say you've typed &lt;code&gt;echo 'hello world'&lt;/code&gt; in the terminal and your cursor is before &lt;code&gt;hello&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-f-before.gif" alt="Before pressing Meta+f"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Esc+b or Alt+b moves the cursor one word forward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-f-after.gif" alt="After pressing Meta+f"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. Delete the last word&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-w.png" alt="Press Ctrl+w"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+w deletes the last word. Deleting a word is also known as killing a word. Each killed word gets stored in the kill ring buffer. If you accidentally killed a word press &lt;code&gt;Ctrl+y&lt;/code&gt; to paste it back. Pasting from the kill ring buffer is also known as yanking.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you've typed &lt;code&gt;cd /foo&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-w-before.gif" alt="Before pressing Ctrl+w"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+w deletes &lt;code&gt;/foo&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-w-after.gif" alt="After pressing Ctrl+w"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. Paste the deleted word(s) back&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-y.png" alt="Press Ctrl+y"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+y pastes whatever is in the kill buffer back to the terminal. Here's an illustration. Let's say you had typed &lt;code&gt;cd /foo&lt;/code&gt; (see the previous example), and you killed the last word, which is &lt;code&gt;/foo&lt;/code&gt; so your command line looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-y-before.gif" alt="Before pressing Ctrl+y"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+y brings &lt;code&gt;/foo&lt;/code&gt; back:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-y-after.gif" alt="After pressing Ctrl+y"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;7. Move one character backward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-b.png" alt="Press Ctrl+b"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+b moves the cursor one char backward. Here's an illustration. Let's say you had typed &lt;code&gt;echo foo bar baz&lt;/code&gt; on the command line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-b-before.gif" alt="Before pressing Ctrl+b"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+b moves the cursor one character backward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-b-after.gif" alt="After pressing Ctrl+b"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;8. Move one character forward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-f.png" alt="Press Ctrl+f"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+f moves the cursor one char forward. Here's an illustration. Let's say you moved one character backward (as in the previous example):&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-f-before.gif" alt="Before pressing Ctrl+f"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+f moves the cursor one character forward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-f-after.gif" alt="After pressing Ctrl+f"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;9. Delete the whole line&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-u.png" alt="Press Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+u kills the whole line and puts it in the kill buffer. Same as with killed words, you can paste the whole line back by pressing &lt;code&gt;Ctrl+y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you've typed &lt;code&gt;echo moo&lt;/code&gt; in your command line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-u-before.gif" alt="Before pressing Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+u deletes the whole line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-u-after.gif" alt="After pressing Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;10. Search the history backward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-r.png" alt="Press Ctrl+r"&gt;&lt;/p&gt;
&lt;p&gt;This is probably one of the most used keyboard shortcuts in bash. Pressing &lt;code&gt;Ctrl+r&lt;/code&gt; searches the command history backwards. For example, you can press &lt;code&gt;Ctrl+r&lt;/code&gt; and then type the first few characters of some command that you executed earlier to quickly find it.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you had executed a complicated command such as this one:&lt;/p&gt;
&lt;pre &gt;
joinlines () { sed ':a; N; s/\n/'"$1"'/; ba'; }
&lt;/pre&gt;
&lt;p&gt;And now you wish to modify it but you don't want to keep going through the history to find it. Press &lt;code&gt;Ctrl+r&lt;/code&gt; and type something you remember from the command like &lt;code&gt;joi&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-r-after.gif" alt="After pressing Ctrl+r"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;11. Search the history forward&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-s.png" alt="Press Ctrl+s"&gt;&lt;/p&gt;
&lt;p&gt;If you press &lt;code&gt;Ctrl+s&lt;/code&gt;, most likely your terminal will freeze because by default your terminal interprets &lt;code&gt;Ctrl+s&lt;/code&gt; as the stop-flow signal. When I was less experienced this was driving me crazy. I'd accidentally press &lt;code&gt;Ctrl+s&lt;/code&gt; and my terminal would freeze. And I had no idea what was happening. Later I learned that I can press &lt;code&gt;CTRL+q&lt;/code&gt; to unfreeze the terminal (&lt;code&gt;Ctrl+q&lt;/code&gt; starts the flow again.)&lt;/p&gt;
&lt;p&gt;The right way to go is to change the terminal behavior for &lt;code&gt;Ctrl+s&lt;/code&gt; via the &lt;code&gt;stty&lt;/code&gt; command:&lt;/p&gt;
&lt;pre &gt;
$ stty stop 'undef'
&lt;/pre&gt;
&lt;p&gt;This will undefine the key binding for the stop-flow signal and you'll be able to use bash's &lt;code&gt;Ctrl+s&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl+s&lt;/code&gt; comes handy when you've searched too far with &lt;code&gt;Ctrl+r&lt;/code&gt;. Then you can just simply reverse the search direction by pressing &lt;code&gt;Ctrl+r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you typed &lt;code&gt;awk&lt;/code&gt; and pressed &lt;code&gt;Ctrl+r&lt;/code&gt; a few times and you skipped past the &lt;code&gt;awk&lt;/code&gt; command that you wanted to find:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-s-before.gif" alt="Before pressing Ctrl+s"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+s&lt;/code&gt; reverses the history search direction:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-s-after.gif" alt="After pressing Ctrl+s"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;12. Exchange two adjacent characters quickly&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-t.png" alt="Press Ctrl+t"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+t transposes two characters (exchanges them) and moves the cursor one character forward. Here's an illustration. Let's say you've mistyped &lt;code&gt;echo&lt;/code&gt; in &lt;code&gt;ehco bar baz&lt;/code&gt; and your cursor is at the letter &lt;code&gt;c&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-t-before.gif" alt="Before pressing Ctrl+t"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+t&lt;/code&gt; exchanges &lt;code&gt;c&lt;/code&gt; with &lt;code&gt;h&lt;/code&gt; and moves the cursor one char forward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-t-after.gif" alt="After pressing Ctrl+t"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;13. Exchange two adjacent words quickly&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-t.png" alt="Press Esc+t or Alt+t"&gt;&lt;/p&gt;
&lt;p&gt;Esc+t or Alt+t transposes two words (exchanges them) and moves the cursor one word forward. Here's an illustration. Let's say you've typed &lt;code&gt;foo bar baz&lt;/code&gt; and your cursor is at the word &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-t-before.gif" alt="Before pressing Meta+t"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Esc+t&lt;/code&gt; or &lt;code&gt;Alt+t&lt;/code&gt; exchanges &lt;code&gt;foo&lt;/code&gt; with &lt;code&gt;bar&lt;/code&gt; and moves the cursor one word forward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-t-after.gif" alt="After pressing Meta+t"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;14. Uppercase the rest of the word&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-u.png" alt="Press Esc+u or Alt+u"&gt;&lt;/p&gt;
&lt;p&gt;Esc+u or Alt+u uppercases the rest of the word. Here's an illustration. Let's say you've typed &lt;code&gt;foo bar baz&lt;/code&gt; and your cursor is at the beginning of &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-u-before.gif" alt="Before pressing Meta+u"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Esc+u&lt;/code&gt; or &lt;code&gt;Alt+u&lt;/code&gt; uppercases the whole word and &lt;code&gt;bar&lt;/code&gt; becomes &lt;code&gt;BAR&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-u-after.gif" alt="After pressing Meta+u"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;15. Lowercase the rest of the word&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-l.png" alt="Press Esc+l or Alt+l"&gt;&lt;/p&gt;
&lt;p&gt;Esc+t or Alt+t uppercases the rest of the word. Here's an illustration. Let's say you've typed &lt;code&gt;foo BAR baz&lt;/code&gt; and your cursor is at the beginning of &lt;code&gt;BAR&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-l-before.gif" alt="Before pressing Meta+l"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Esc+l&lt;/code&gt; or &lt;code&gt;Alt+l&lt;/code&gt; lowercases the whole word and &lt;code&gt;BAR&lt;/code&gt; becomes &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-l-after.gif" alt="After pressing Meta+l"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;16. Capitalize a word&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-c.png" alt="Press Esc+c or Alt+c"&gt;&lt;/p&gt;
&lt;p&gt;Esc+c or Alt+c properly capitalizes a word. Here's an illustration. Let's say you've typed &lt;code&gt;foo bar baz&lt;/code&gt; and your cursor is at the beginning of &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-c-before.gif" alt="Before pressing Meta+c"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Esc+c&lt;/code&gt; or &lt;code&gt;Alt+c&lt;/code&gt; capitalizes the first letter of the word and &lt;code&gt;bar&lt;/code&gt; becomes &lt;code&gt;Bar&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-c-after.gif" alt="After pressing Meta+c"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;17. Insert a raw character (such as TAB or Ctrl+c)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-v.png" alt="Press Ctrl+v"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+v inserts the next character typed verbatim. For example, Ctrl+v followed by &amp;lt;TAB&amp;gt; would insert a literal tab in the command line, or Ctrl+v followed by Ctrl+m would insert a Windows newline (aka carriage return CR). &lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you've typed &lt;code&gt;echo foo&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-v-before.gif" alt="Before pressing Ctrl+v"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+v&lt;/code&gt; followed by &lt;code&gt;Ctrl+m&lt;/code&gt; inserts a literal &lt;code&gt;Ctrl+m&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-v-after.gif" alt="After pressing Ctrl+v Ctrl+m"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;18. Comment the current line (append # at the beginning quickly)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-hash.png" alt="Press Esc+# or Alt+#"&gt;&lt;/p&gt;
&lt;p&gt;Esc+# or Alt+# quickly comments the line. Here's an illustration. Let's say you typed &lt;code&gt;echo foo bar baz&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-hash-before.gif" alt="Before pressing Meta+#"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+#&lt;/code&gt; inserts the comment symbol &lt;code&gt;#&lt;/code&gt; at the beginning of the line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-hash-after.gif" alt="After pressing Meta+#"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;19. Open the current command in a text editor quickly&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-x-ctrl-e.png" alt="Press Ctrl+x, Ctrl+e"&gt;&lt;/p&gt;
&lt;p&gt;Pressing CTRL+x followed by CTRL+e opens the current command in your favorite text editor. Exiting the editor will execute the command.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;20. Delete a character to the left&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-h.png" alt="Press Ctrl+h"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+h deletes the character to the left of the cursor. Here's an illustration. Let's say you've typed &lt;code&gt;echo qwerty&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-h-before.gif" alt="Before pressing Ctrl+h"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+h&lt;/code&gt; deletes the character to the left:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-h-after.gif" alt="After pressing Ctrl+h"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;21. Delete a character to the right&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-d.png" alt="Press Ctrl+d"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+d deletes the character to the right of the cursor. Here's an illustration. Let's say you've typed &lt;code&gt;echo qwerty&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-d-before.gif" alt="Before pressing Ctrl+d"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+d&lt;/code&gt; deletes the character to the right:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-d-after.gif" alt="After pressing Ctrl+d"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;22. Incremental undo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-x-ctrl-u.png" alt="Press Ctrl+x, Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;Pressing Ctrl+x followed by Ctrl+u undoes a change. Here's an illustration. Let's say you typed &lt;code&gt;foo bar baz&lt;/code&gt; and then deleted &lt;code&gt;baz&lt;/code&gt; and typed &lt;code&gt;moo&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-x-ctrl-u-before.gif" alt="Before pressing Ctrl+x Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Ctrl+x, Ctrl+u&lt;/code&gt; a few times undoes the last changes and you end up with &lt;code&gt;foo bar baz&lt;/code&gt; again:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-x-ctrl-u-after.gif" alt="After pressing Ctrl+x Ctrl+u"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;23. Insert the last argument from the previous command&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-dot.png" alt="Press Esc+. or Alt+."&gt;&lt;/p&gt;
&lt;p&gt;Esc+. or Alt+. inserts the last argument from the previous command at the current cursor position. Here's an illustration. Let's say you had run &lt;code&gt;ls archive.tgz&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-dot-before.gif" alt="Before pressing Meta+."&gt;&lt;/p&gt;
&lt;p&gt;And now you want to extract the archive. So all you've to do is type &lt;code&gt;tar -xzf&lt;/code&gt; and press Esc+. or Alt+.:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-dot-after.gif" alt="Before pressing Meta+."&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;24. Undo all changes to the line&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-r.png" alt="Press Esc+r or Alt+r"&gt;&lt;/p&gt;
&lt;p&gt;Esc+r or Alt+r undoes all changes to the line. It's useful when you're going through the command history with &lt;code&gt;Ctrl+r&lt;/code&gt; and make changes. If you mess up, you can quickly revert back to the original command by pressing Esc+r or Alt+r.&lt;/p&gt;
&lt;p&gt;Here's an illustration. Let's say you searched for &lt;code&gt;grep&lt;/code&gt; in history:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-r-before.gif" alt="Before pressing Meta+r"&gt;&lt;/p&gt;
&lt;p&gt;And let's say you wanted to make some changes to the command but messed up:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-r-before-2.gif" alt="Before pressing Meta+r"&gt;&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;Esc+r&lt;/code&gt; or &lt;code&gt;Alt+r&lt;/code&gt; undoes all the changes and you end up with the original &lt;code&gt;grep&lt;/code&gt; command that was in the history:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/meta-r-after.gif" alt="After pressing Meta+r"&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;25. Clear the screen&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.catonmat.net/images/bash-emacs-mode/ctrl-l.png" alt="Press Ctrl+l"&gt;&lt;/p&gt;
&lt;p&gt;Ctrl+l clears the screen. Alternatively you can type &lt;code&gt;reset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;26. Change input mode to vi&lt;/b&gt;&lt;/p&gt;
&lt;pre &gt;
$ set -o vi
&lt;/pre&gt;
&lt;p&gt;This command changes the key bindings to vi's. If vi's your favorite editor, you'll love this. I'll cover the vi mode in more details in the next part of the article. &lt;/p&gt;
&lt;h2&gt;Cheat Sheet&lt;/h2&gt;
&lt;p&gt;I made a cheat sheet that lists all the default emacs mode keyboard shortcuts. &lt;a href="http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf"&gt;Download the emacs keyboard shortcut cheat sheet.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;Enjoy the article and let me know in the comments what you think about it!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Klm8zg850RM:wMhg2Spv-f4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Klm8zg850RM:wMhg2Spv-f4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Klm8zg850RM:wMhg2Spv-f4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Klm8zg850RM:wMhg2Spv-f4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Klm8zg850RM:wMhg2Spv-f4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Klm8zg850RM:wMhg2Spv-f4:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Klm8zg850RM:wMhg2Spv-f4:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/Klm8zg850RM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/bash-one-liners-explained-part-five</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">My favorite regex of all time</title>
    <id>354</id>
    <updated>2012-11-12T22:36:04Z</updated>
    <published>2012-11-12T19:10:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/AjFfpl2tX6g/my-favorite-regex" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;I thought I'd share my favorite regex of all time:&lt;/p&gt;
&lt;pre &gt;
[ -~]
&lt;/pre&gt;
&lt;p&gt;Any ideas what this regexp matches?&lt;/p&gt;
&lt;p&gt;It matches all ASCII characters from the space to the tilde. What are those characters? They're all printable characters!&lt;/p&gt;
&lt;p&gt;Take a look at the ASCII table. The printable characters start at the space and end at the tilde:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/favorite-regex/ascii-table.png"&gt;&lt;br&gt;
&lt;small&gt;&lt;code&gt;[ -~]&lt;/code&gt; matches all printable ascii characters (light blue background)&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;I love this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Would you like to wear this regular expression? I just had an idea to make it a t-shirt as this blog post is getting so popular. Check out this t-shirt that I made:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://teespring.com/ascii" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/favorite-regex/regex-shirt.png" width="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;This shirt is available through Teespring. Teespring is like Kickstarter for t-shirts. If 50 people buy the shirt, everyone gets their shirt. Otherwise no one gets charged and no one gets the shirt.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=AjFfpl2tX6g:gmEbL2ahrgg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=AjFfpl2tX6g:gmEbL2ahrgg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=AjFfpl2tX6g:gmEbL2ahrgg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=AjFfpl2tX6g:gmEbL2ahrgg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=AjFfpl2tX6g:gmEbL2ahrgg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=AjFfpl2tX6g:gmEbL2ahrgg:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=AjFfpl2tX6g:gmEbL2ahrgg:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/AjFfpl2tX6g" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/my-favorite-regex</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Monthly Catonmat Geek T-Shirt #2: a.pipe(b).pipe(a)</title>
    <id>355</id>
    <updated>2012-11-01T17:50:45Z</updated>
    <published>2012-11-01T17:50:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/-Kg4EKKRb2o/duplex-streams-tee" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;This month I'm presenting the limited-edition node.js duplex stream tees designed by the stream master and node.js wizard &lt;a href="http://twitter.com/substack"&gt;SubStack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This shirt is done in collaboration with &lt;a href="http://teespring.com/"&gt;Teespring&lt;/a&gt;. Teespring is basically Kickstarter for t-shirts. If enough people commit to buying a shirt, everyone gets their shirt. Otherwise nobody gets a shirt (and nobody gets charged).&lt;/p&gt;
&lt;p&gt;This tee illustrates the duplex stream pattern &lt;code&gt;a.pipe(b).pipe(a)&lt;/code&gt; that sends the messages around like a telephone.&lt;/p&gt;
&lt;p&gt;The shirt is available on Hanes tees and is priced at $15.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://teespring.com/pipe" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/monthly-geek-shirt/duplex-stream.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://teespring.com/pipe"&gt;Get Your Limited Edition Duplex Stream T-Shirt Now!&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;Do you love this shirt and want to get more geek shirts in the future? &lt;a href="http://www.catonmat.net/feed/"&gt;Subscribe to my blog&lt;/a&gt; and &lt;a href="http://twitter.com/pkrumins"&gt;follow me on twitter&lt;/a&gt; for updates!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=-Kg4EKKRb2o:guzTQBJlWkQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=-Kg4EKKRb2o:guzTQBJlWkQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=-Kg4EKKRb2o:guzTQBJlWkQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=-Kg4EKKRb2o:guzTQBJlWkQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=-Kg4EKKRb2o:guzTQBJlWkQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=-Kg4EKKRb2o:guzTQBJlWkQ:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=-Kg4EKKRb2o:guzTQBJlWkQ:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/-Kg4EKKRb2o" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/duplex-streams-tee</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">ASCII bit trick to convert lowercase to uppercase and back</title>
    <id>312</id>
    <updated>2012-10-22T21:06:56Z</updated>
    <published>2012-10-22T16:45:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/hCJMp0Hp9zw/ascii-case-conversion-trick" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;I just remembered that I had forgotten the ASCII trick to convert lowercase to uppercase and back. The trick is super simple, you xor the 6th bit (or 5th depending on how you count bits) and that changes the case!&lt;/p&gt;
&lt;p&gt;Check this out:&lt;/p&gt;
&lt;pre &gt;
a = 01100001
A = 01000001
&lt;/pre&gt;
&lt;p&gt;See, just the 6th bit changed.&lt;/p&gt;
&lt;p&gt;Why is it this way? Simply because the people who invented ASCII thought it was a great idea. If you look at characters &lt;code&gt;a..z&lt;/code&gt;, you'll see that all of them have the 6th bit set to 1. The ASCII inventors though, hey, let's set 6th bit to 0 for upper case letters &lt;code&gt;A..Z&lt;/code&gt;, then it will be super easy to change case. So they did.&lt;/p&gt;
&lt;pre &gt;
a = 01100001    A = 01000001 
b = 01100010    B = 01000010 
c = 01100011    C = 01000011 
d = 01100100    D = 01000100 
e = 01100101    E = 01000101 
f = 01100110    F = 01000110 
g = 01100111    G = 01000111 
h = 01101000    H = 01001000 
i = 01101001    I = 01001001 
j = 01101010    J = 01001010 
k = 01101011    K = 01001011 
l = 01101100    L = 01001100 
m = 01101101    M = 01001101 
n = 01101110    N = 01001110 
o = 01101111    O = 01001111 
p = 01110000    P = 01010000 
q = 01110001    Q = 01010001 
r = 01110010    R = 01010010 
s = 01110011    S = 01010011 
t = 01110100    T = 01010100 
u = 01110101    U = 01010101 
v = 01110110    V = 01010110 
w = 01110111    W = 01010111 
x = 01111000    X = 01011000 
y = 01111001    Y = 01011001 
z = 01111010    Z = 01011010 
&lt;/pre&gt;
&lt;p&gt;Also check this out, if you xor a character with a space, you invert the case:&lt;/p&gt;
&lt;pre &gt;
$ perl -le 'print "a"^" "'   
A
$ perl -le 'print "A"^" "' 
a
&lt;/pre&gt;
&lt;p&gt;Why is that? Because a space ' ' has the value 32, which is 1&amp;lt;&amp;lt;5, which is the 6th bit, which swaps the case!&lt;/p&gt;
&lt;h2&gt;Bonus&lt;/h2&gt;
&lt;p&gt;Here are the commands I used for this blog post:&lt;/p&gt;
&lt;pre &gt;
$ perl -e 'printf "%08b\n", ord("K")'
$ perl -e 'printf "%s = %08b    %s = %08b\n", $_, ord, uc, ord uc for a..z' 
&lt;/pre&gt;
&lt;p&gt;Simple articles best articles.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=hCJMp0Hp9zw:17S8FSlGMGw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=hCJMp0Hp9zw:17S8FSlGMGw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=hCJMp0Hp9zw:17S8FSlGMGw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=hCJMp0Hp9zw:17S8FSlGMGw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=hCJMp0Hp9zw:17S8FSlGMGw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=hCJMp0Hp9zw:17S8FSlGMGw:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=hCJMp0Hp9zw:17S8FSlGMGw:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/hCJMp0Hp9zw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/ascii-case-conversion-trick</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Browserling reaches 200 paying customers!</title>
    <id>349</id>
    <updated>2012-10-16T23:11:22Z</updated>
    <published>2012-10-16T23:10:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/SoP1ekHpe60/browserling-reaches-200-paying-customers" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;Amazing news everyone! &lt;a href="http://browserling.com/"&gt;Browserling&lt;/a&gt; just reached 200 paying customers! It took us 2 years to get to &lt;a href="http://www.catonmat.net/blog/browserling-reaches-100-paying-customers/"&gt;100 customers&lt;/a&gt;, and now it took just 5 months to get to 200 customers. We're looking forward to doubling our customer base again soon.&lt;/p&gt;
&lt;p&gt;Our new customers include companies such as:&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/browserling-200-customers-company-logos.png"&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.virtualnerd.com"&gt;VirtualNerd&lt;/a&gt;, &lt;a href="http://www.fluentconcepts.com"&gt;Fluent Concepts&lt;/a&gt;, &lt;a href="http://www.babyli.st"&gt;BabyList&lt;/a&gt;, &lt;a href="http://www.mapbox.com"&gt;MapBox&lt;/a&gt;, &lt;a href="http://www.helicoid.com"&gt;Helicoid&lt;/a&gt;, &lt;a href="http://www.dabapps.com"&gt;DabApps&lt;/a&gt;, &lt;a href="http://www.nextsocial.de"&gt;Next Social&lt;/a&gt;, &lt;a href="http://www.mybanktracker.com"&gt;My Bank Tracker&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;As well as many individuals.&lt;/p&gt;
&lt;p&gt;Thank you all!&lt;/p&gt;
&lt;p&gt;Browserling is an interactive cross-browser testing tool. It lets you test your website in older Internet Explorers such as IE 6, IE 7, IE 8 and IE 9, Firefox, Chrome, Opera and Safari!&lt;/p&gt;
&lt;center&gt;&lt;p&gt;&lt;a href="http://browserling.com" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/browserling.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://browserling.com"&gt;Try Browserling!&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=SoP1ekHpe60:PM7PEJ9gsGo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=SoP1ekHpe60:PM7PEJ9gsGo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=SoP1ekHpe60:PM7PEJ9gsGo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=SoP1ekHpe60:PM7PEJ9gsGo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=SoP1ekHpe60:PM7PEJ9gsGo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=SoP1ekHpe60:PM7PEJ9gsGo:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=SoP1ekHpe60:PM7PEJ9gsGo:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/SoP1ekHpe60" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/browserling-reaches-200-paying-customers</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Bash One-Liners Explained, Part IV: Working with history</title>
    <id>334</id>
    <updated>2012-10-13T16:43:40Z</updated>
    <published>2012-10-12T20:20:20Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/BTsR6NA3rgM/bash-one-liners-explained-part-four" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">&lt;p&gt;This is the fourth part of the &lt;strong&gt;Bash One-Liners Explained&lt;/strong&gt; article series. In this part I'll teach you how to work with bash history. I'll use only the best bash practices, various bash idioms and tricks. I want to illustrate how to get various tasks done with just bash built-in commands and bash programming language constructs.&lt;/p&gt;
&lt;p&gt;I'll break this part into several sub-parts as it's very tiring to write long articles, and I'd rather publish many short articles and make quick progress.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="http://www.catonmat.net/blog/bash-one-liners-explained-part-one/"&gt;first part&lt;/a&gt; of the series for introduction. After I'm done with the series I'll release an ebook (similar to my ebooks on &lt;a href="http://www.catonmat.net/blog/awk-book/"&gt;awk&lt;/a&gt;, &lt;a href="http://www.catonmat.net/blog/sed-book/"&gt;sed&lt;/a&gt;, and &lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;perl&lt;/a&gt;), and also bash1line.txt (similar to my &lt;a href="http://www.catonmat.net/download/perl1line.txt"&gt;perl1line.txt&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Also see my other articles about working fast in bash from 2007 and 2008:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.catonmat.net/blog/bash-emacs-editing-mode-cheat-sheet/"&gt;Working Productively in Bash's Emacs Command Line Editing Mode (comes with a cheat sheet)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/"&gt;Working Productively in Bash's Vi Command Line Editing Mode (comes with a cheat sheet)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Parts of this post are based on my earlier post &lt;a href="http://www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/"&gt;Definitive Guide to Bash Command Line History&lt;/a&gt;. Check it out, too!&lt;/p&gt;
&lt;p&gt;Let's start.&lt;/p&gt;
&lt;h2&gt;Part IV: Working with history&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Erase all shell history&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ rm ~/.bash_history
&lt;/pre&gt;
&lt;p&gt;Bash keeps the shell history in a hidden file called &lt;code&gt;.bash_history&lt;/code&gt;. This file is located in your home directory. To get rid of the history, just delete it.&lt;/p&gt;
&lt;p&gt;Note that if you logout after erasing the shell history, this last &lt;code&gt;rm ~/.bash_history&lt;/code&gt; command will be logged. If you want to hide that you erased shell history, see the next one-liner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Stop logging history for this session&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ unset HISTFILE
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;HISTFILE&lt;/code&gt; special bash variable points to the file where the shell history should be saved. If you unset it, bash won't save the history.&lt;/p&gt;
&lt;p&gt;Alternatively you can point it to &lt;code&gt;/dev/null&lt;/code&gt;,&lt;/p&gt;
&lt;pre &gt;
$ HISTFILE=/dev/null
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Don't log the current command to history&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just start the command with an extra space:&lt;/p&gt;
&lt;pre &gt;
$  command
&lt;/pre&gt;
&lt;p&gt;If the command starts with an extra space, it's not logged to history.&lt;/p&gt;
&lt;p&gt;Note that this only works if the &lt;code&gt;HISTIGNORE&lt;/code&gt; variable is properly configured. This variable contains &lt;code&gt;:&lt;/code&gt; separated values of command prefixes that shouldn't be logged.&lt;/p&gt;
&lt;p&gt;For example to ignore spaces set it to this:&lt;/p&gt;
&lt;pre &gt;
HISTIGNORE="[ ]*"
&lt;/pre&gt;
&lt;p&gt;My &lt;code&gt;HISTIGNORE&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre &gt;
HISTIGNORE="&amp;:[ ]*"
&lt;/pre&gt;
&lt;p&gt;The ampersand has a special meaning - don't log repeated commands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Change the file where bash logs command history&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ HISTFILE=~/docs/shell_history.txt
&lt;/pre&gt;
&lt;p&gt;Here we simply change the &lt;code&gt;HISTFILE&lt;/code&gt; special bash variable and point it to &lt;code&gt;~/docs/shell_history.txt&lt;/code&gt;. From now on bash will save the command history in that file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Add timestamps to history log&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S"
&lt;/pre&gt;
&lt;p&gt;If you set the &lt;code&gt;HISTTIMEFORMAT&lt;/code&gt; special bash variable to a valid date format (see &lt;code&gt;man 3 strftime&lt;/code&gt;) then bash will log the timestamps to the history log. It will also display them when you call the &lt;code&gt;history&lt;/code&gt; command (see the next one-liner).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Show the history&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ history
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;history&lt;/code&gt; command displays the history list with line numbers. If &lt;code&gt;HISTTIMEFORMAT&lt;/code&gt; is set, it also displays the timestamps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. Show the last 50 commands from the history&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ history 50
&lt;/pre&gt;
&lt;p&gt;If you specify a numeric argument, such as 50, to &lt;code&gt;history&lt;/code&gt;, it prints the last 50 commands from the history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. Show the top 10 most used commands from the bash history&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ history |
    sed 's/^ \+//;s/  / /' |
    cut -d' ' -f2- |
    awk '{ count[$0]++ } END { for (i in count) print count[i], i }' |
    sort -rn |
    head -10
&lt;/pre&gt;
&lt;p&gt;This one-liner combines bash with sed, cut, awk, sort and head. The perfect combination. Let's walk through this to understand what happens. Let's say the output of &lt;code&gt;history&lt;/code&gt; is:&lt;/p&gt;
&lt;pre &gt;
$ history
    1  rm .bash_history 
    2  dmesg
    3  su -
    4  man cryptsetup
    5  dmesg
&lt;/pre&gt;
&lt;p&gt;First we use the &lt;code&gt;sed&lt;/code&gt; command to remove the leading spaces and convert the double space after the history command number to a single space:&lt;/p&gt;
&lt;pre &gt;
$ history | sed 's/^ \+//;s/  / /'
1 rm .bash_history 
2 dmesg
3 su -
4 man cryptsetup
5 dmesg
&lt;/pre&gt;
&lt;p&gt;Next we use &lt;code&gt;cut&lt;/code&gt; to remove the first column (the history numbers):&lt;/p&gt;
&lt;pre &gt;
$ history |
    sed 's/^ \+//;s/  / /' |
    cut -d' ' -f2-

rm .bash_history 
dmesg
su -
man cryptsetup
dmesg
&lt;/pre&gt;
&lt;p&gt;Next we use &lt;code&gt;awk&lt;/code&gt; to record how many times each command has been seen:&lt;/p&gt;
&lt;pre &gt;
$ history |
    sed 's/^ \+//;s/  / /' |
    cut -d' ' -f2- |
    awk '{ count[$0]++ } END { for (i in count) print count[i], i }'

1 rm .bash_history 
2 dmesg
1 su -
1 man cryptsetup
&lt;/pre&gt;
&lt;p&gt;Then we sort the output numerically and reverse it:&lt;/p&gt;
&lt;pre &gt;
$ history |
    sed 's/^ \+//;s/  / /' |
    cut -d' ' -f2- |
    awk '{ count[$0]++ } END { for (i in count) print count[i], i }' |
    sort -rn

2 dmesg
1 rm .bash_history 
1 su -
1 man cryptsetup
&lt;/pre&gt;
&lt;p&gt;Finally we take the first 10 lines that correspond to 10 most frequently used commands:&lt;/p&gt;
&lt;pre &gt;
$ history |
    sed 's/^ \+//;s/  / /' |
    cut -d' ' -f2- |
    awk '{ count[$0]++ } END { for (i in count) print count[i], i }' |
    sort -rn |
    head -10
&lt;/pre&gt;
&lt;p&gt;Here is what my 10 most frequently used commands look like:&lt;/p&gt;
&lt;pre &gt;
2172 ls
1610 gs
252 cd ..
215 gp
213 ls -las
197 cd projects
155 gpu
151 cd
119 gl
119 cd tests/
&lt;/pre&gt;
&lt;p&gt;Here I've &lt;code&gt;gs&lt;/code&gt; that's an alias for &lt;code&gt;git status&lt;/code&gt;, &lt;code&gt;gp&lt;/code&gt; is &lt;code&gt;git push&lt;/code&gt;, &lt;code&gt;gpu&lt;/code&gt; is &lt;code&gt;git pull&lt;/code&gt; and &lt;code&gt;gl&lt;/code&gt; is &lt;code&gt;git log&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8. Execute the previous command quickly&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ !!
&lt;/pre&gt;
&lt;p&gt;That's right. Type two bangs. The first bang starts history substitution, and the second one refers to the last command. Here is an example:&lt;/p&gt;
&lt;pre &gt;
$ echo foo
foo
$ !!
foo
&lt;/pre&gt;
&lt;p&gt;Here the &lt;code&gt;echo foo&lt;/code&gt; command was repeated.&lt;/p&gt;
&lt;p&gt;It's especially useful if you wanted to execute a command through &lt;code&gt;sudo&lt;/code&gt; but forgot. Then all you've to do is run:&lt;/p&gt;
&lt;pre &gt;
$ rm /var/log/something
rm: cannot remove `/var/log/something': Permission denied
$
$ sudo !!   # executes `sudo rm /var/log/something`
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;9. Execute the most recent command starting with the given string&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ !foo
&lt;/pre&gt;
&lt;p&gt;The first bang starts history substitution, and the second one refers to the most recent command starting with &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;pre &gt;
$ echo foo
foo
$ ls /
/bin /boot /home /dev /proc /root /tmp
$ awk -F: '{print $2}' /etc/passwd
...
$ !ls
/bin /boot /home /dev /proc /root /tmp
&lt;/pre&gt;
&lt;p&gt;Here we executed commands &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, and then used &lt;code&gt;!ls&lt;/code&gt; to refer to the &lt;code&gt;ls /&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10. Open the previous command you executed in a text editor&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
$ fc
&lt;/pre&gt;
&lt;p&gt;Fc opens the previous command in a text editor. It's useful if you've a longer, more complex command and want to edit it.&lt;/p&gt;
&lt;p&gt;For example, let's say you've written a one-liner that has an error, such as:&lt;/p&gt;
&lt;pre &gt;
$ for wav in wav/*; do mp3=$(sed 's/\.wav/\.mp3/' &amp;lt;&amp;lt;&amp;lt; "$wav"); ffmpeg -i "$wav" "$m3p"; done
&lt;/pre&gt;
&lt;p&gt;And you can't see what's going on because you've to scroll around, then you can simply type &lt;code&gt;fc&lt;/code&gt; to load it in your text editor, and then quickly find that you mistyped &lt;code&gt;mp3&lt;/code&gt; at the end.&lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;Enjoy the article and let me know in the comments what you think about it. In the next sub-part I'll continue discussing history keyboard shortcuts, history shell options and more.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BTsR6NA3rgM:yw7y-XnGPKE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BTsR6NA3rgM:yw7y-XnGPKE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=BTsR6NA3rgM:yw7y-XnGPKE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BTsR6NA3rgM:yw7y-XnGPKE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=BTsR6NA3rgM:yw7y-XnGPKE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BTsR6NA3rgM:yw7y-XnGPKE:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=BTsR6NA3rgM:yw7y-XnGPKE:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/BTsR6NA3rgM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/bash-one-liners-explained-part-four</feedburner:origLink></entry>
</feed>
