sort -k

TIL, when you call sort -k3, you’re not just sorting by the third field, but by whatever the value between the third field up to the end of the line is.
Not only that, in the case of ties, by default it will use also the first field.

Consider this example.

$ cat data
theta AAA 2
gamma AAA 2
alpha BBB 2
alpha AAA 3

Sorting with -k2 gives:

$ sort data -k2 --debug
sort: using simple byte comparison
gamma AAA 2
     ______
___________
theta AAA 2
     ______
___________
alpha AAA 3
     ______
___________
alpha BBB 2 
     _______
____________

Notice I’ve also added --debug, to show which parts are used in the comparisons.
So, first comes “AAA 2”, then “AAA 3”.
Also, for the two lines that have “AAA 2”, the first field is used, so “gamma” comes before “theta”.

Forget about the ties for now.
To consider field 2 only, rather than field 2 and all following fields, you need to specify a stop. This is done by adding “,2” to the -k switch. More in general, -km,n means “sort by field m up to n, boundaries included”.

$ sort data -k2,2 --debug
sort: using simple byte comparison
alpha AAA 3
     ____
___________
gamma AAA 2
     ____
___________
theta AAA 2
     ____
___________
alpha BBB 2 
     ____
____________

As you can see, field 2 only is taken into account at first.
“AAA 3” comes before “AAA 2” because, being a tie, the first field is used as a second comparison.

Taking this a step further, to actually only consider field 2 and resort to the original order in case of ties, that is, to have a stable sort, you need to pass the -s switch.

$ sort data -k2,2 -s --debug
sort: using simple byte comparison
theta AAA 2
     ____
gamma AAA 2
     ____
alpha AAA 3
     ____
alpha BBB 2 
     ____

This look similar to the first snippet, but actually the first two lines in the output are swapped. Here they appear in the original order.

Increase your Vi delete and paste power

deleting (cutting), yanking (copying) and pasting.
You already know those Vi commands.

But what if you have to cut and paste two distinct pieces of text? Sure you can d, scroll around, then p, then scroll back, d, then scroll around again to finally p, but that’s cumbersome, let alone efficient. In fact, there’s a better way — one that leaves you with all the cut/copied text available for later pasting.

Enter the registers.
There are 9 numbered registers: you can access them by typing all the numbers " followed by any digit from 1 to 9.
Registers work as a LIFO queue and reflect your cutting/copying history, which means that if you delete lines 35 and 42 (two separate actions), you’ll end up with line 42 in register "1 and line 35 in register "2.
To paste lines 42 and 35 (in that order), needless to say, you’d do: "1p "2p.

There are also 26 named registers, to use which you just need to type " followed by any of the 26 letters on your keyboard.

Pro tip, to become more proficient, stick a set -o vim in your .bashrc and you’ll activate Vi mode in your shell (and deactivate Emacs mode, which is usually on by default).

Bonus link: if you’re just starting with Vim, here’s some other practical advice.

Foreground and background (boy you turn me)

I’m sure Diana Ross would have named so her song, had she been a huge *nix fun.

What are we talking about? Job control. It’s simple if you already know it, but today I learnt some people didn’t know about putting shell jobs in background or restoring them in foreground.

The basics

When you run a command in a shell, it will take over the shell input until it’s done. And that’s called foreground.

Append an & at the end of the command line and the job will run in background, leaving the shell input free for other tasks. The job number will appear between square brackets.

To bring a foreground job in background, suspend it (Ctrl-Z) and issue bg.

To bring it back on foreground, type fg.

To see the list of jobs running in background, use the builtin jobs.

More fun

To reference a job in particular, you can use %n where n is the job number. So you could do, fg %3 or kill %7.

Alternatively, you can use %name where name is the command name used (for instance if you do man bash &, then you can refer to the job as %man).

? can be used to partially match strings: in the previous example, fg %?n or fg %?m would have referenced man bash.

jobs‘ output also tells you something more than just the list of jobs. A + is appended to the current job (last job stopped) and a - is appended to the previous job (i.e. that run before the current).
Guess what, you can use both signs to retrieve those jobs: enter %+ and %-.

For reasons I can’t explain, also % and %% refer to the current job, so watchout for typos.

Finally, % can also be used to run commands. In other words: %2 & is equivalent to bg %2 and %3 is equivalent to fg %3.

Change directory like a pro – 5 minutes intro

pushd and popd: it might take a bit to get used to them, but it’s worth it.

The basics

pushd some/path will simply take you to that directory (just as cd some/path does), with the added bonus that the old directory is kept in a FIFO queue.
popd will take you to the last path that was pushed to the queue.

The list of paths populating the queue will be output as soon as you hit either command.
Bonus: use dirs to list the entries in the queue without changing directory.

Sample session:

you@box:~> pwd
/home/you
you@box:~> pushd ..
/home ~
you@box:/home> dirs
/home ~
you@box:/home> pushd ~/bin/
~/bin /home ~
you@box:~/bin> popd
/home ~
you@box:/home>

Additional tips and tricks

  • If you push the same path multiple times… the same path will appear multiple times.
  • Don’t want to see the output? Alias the commands and redirect the output to /dev/null
  • Want to save a few keystrokes? Alias the commands to something like p and o
  • Want to impress your friends? Move around with p [+-]n where n is the number of entries to skip in the queue. Example:
    you@box:~> dirs
    ~ ~/bin ~/bin /home
    you@box:~> p +3
    /home ~ ~/bin ~/bin
    you@box:/home>

    (explanation: with the first command you can see that a) you find yourself in ~, b) the second and third entry is ~/bin, and c) /home is in fourth position. Count 3 from where you are, and you know you’ll land on /home).

Here a nice page that gives you more details on the subject. (I stole the aliases from there :)

Debugging shell scripts (Bash)

New job, different technologies, same me, with my head that sometimes can’t remember simple things such as…

The flag to use in order to debug Bash scripts. Here it is:

-x

All it does is echoing back the commands it runs (for those who think it’s not a big deal, remember it expands the variables – one day, when running your script with -x you’ll go “ooh, I didn’t mean to include all those files!”).

Simples. And yet I keep forgetting it. And keep trying random flags (was it -w? Maybe it’s -e…).