awk

Know your system

What are the executables you daily use made of? Are they scripts or binaries?
What do developers use? Python? Java? Or perhaps Ruby?

It’s easy and funny to find it out, you just need a couple of bash lines with a pinch of awk:

Even to Odd converter

Here is an interesting problem: write a sed script to substitute every even number with the nearest odd number. I got this one from the list of the latest searches which bring the users to this site.
Let’s see how we can tackle this issue.

First of all, let me say that, for this type of tasks, I’d rather use awk because it has variables and strong and fast arithmetics capabilites. Here is how I’d do in awk:

$ echo "12 15 4 98 1123" | awk '{
for (i=1;i<=NF;i++)
if ($i ~ /^[0-9]*[02468]$/)
$i--
} 1'

The above command ignores numbers mixed with strings (i.e. foo12, 4bar2,etc.) and simply subtracts 1 from any even number (though you can easily add 1 by using $i++ in the place of $i–).

Keep track of the times a script is being run

The fact: you need to know how many times a given script has been run lately. This task is quite trivial if you keep the number in a given temporary file.

What I am going to show you instead, is how to store the number just directly in the same script.
Oh well, not that this is too hard to do but it’s a nice trick that may give you an idea of how self-extracting script do work (e.g. nvidia official drivers and common linux games are shipped with this type of container).

Let’s go to the core of the problem: in order to distinguish the code from the data, we need to put the first on top of the file and then tell the shell interpreter when it has to stop reading. How we can do this? With exit, of course

Check for duplicates

How to find those files that have different names but exactly the same content?

You could install the good fdupes or you could just reinvent the wheel with bash, md5sum and awk:

find path/ -type f | xargs md5sum | awk '{
sub("[^/]*/","",$2);
if (cache[$1])
print "Found: "cache[$1],$2;
else
cache[$1]=$2
}'

path is where you want to search for duplicates. You can limit the search with the find maxdepth option.

Reverse Dependence of a package

In Debian every package depends on others and thus every package has generally at least another one which depends on it. Every once in a while you could need to know why a given package is present in your Debian machine. Here is how:

Method 1: apt-cache
$ apt-cache rdepends package

Shows all the packages, no matter whether they are installed or not, which depends on package.

Method 2: aptitude

If you, like me, don’t use aptitude very often (i.e. never) you should first update its package db:

# aptitude update

Then:

$ aptitude search '~i~Dpackage'

This command shows all the installed packages which depend on package.

Add a timestamp to the output of a given command

Have you ever wanted to add a leading timestamp on each line of a given output?

That would make it a perfect professional syslog-like log!

Fortunately, it’s just a one-liner with gawk (the gnu version of the popular tool):

$ ./command | gawk '{print strftime("%b %d %T",systime()),$0;}'

For example, you can create a simple one-on-one IRC-like connection with:

$ nc -l -p 1234 | gawk '{print strftime("%b %d %T",systime()),$0;}'
set 16 18:25:27 Hi!
set 16 18:25:31 Are you there?
yes
set 16 18:25:41 Great!

The user you want to chat with, will have to run

Hexadecimal conversion in bash/awk

Let’s suppose we have a number expressed in given base (i.e. “E0″ in hexadecimal). How can we convert it to decimal using bash or other common Unix tools? And what if we need to perform an any-to-any base conversion?

First way: printf + hexdump

We can tell bash that a given string is just a disguised hexadecimal number by adding “\x” at the top of it and then using the built-in printf function to recover the number:

$ foo="6F"
$foo2="\x"$foo
$ printf "%b" $foo2 | hexdump -e '1/1 "%d" "\n"'
111
$ printf "%b" $foo2 | hexdump -e '1/1 "%o" "\n"'
157

Please notice that %d makes hexdumo to return a signed integer; if you need an unsigned integer just replace it with %u: