The UNIX shell as an IDE: look stuff up with sed

Recently I have been working on nissy, my Rubik’s cube solver written in C. It is a faily large project for me, consisting of multiple files for a total of ~8k lines.

Something that I need to do quite often is quickly checking a structure’s or a function’s definition. Using a simple text editor without any plugin, my workflow for this at the moment is the following:

This is not too bad, but I can do better using a short sed script!

Coding style

I write my functions like this:

static int
do_thing(int var)
{
    function body...
}

The important part is that the function’s name is at the start of the line. In this way when I search for the function’s definition I can type /^do_thing. Here ^ stands for the beginning of the line, and it is fairly standard across UNIX tools (sed, grep, ed…), so all other uses of the funciton in the same file are ignored. The other important thing is that the closing } is also at the beginning of the line, but everyone in their right mind does that (I hope).

The sed command

If you are like me, 99% of the time you use sed it is to replace some text with something like sed 's/old text/new text/g. But this classic program can actually do more: it parses the input line by line, applies a series of commands to each line that matches the given address, and then prints the result. For example

$ sed '5,10 p' file.c

prints (p) the lines from 5 to 10 of file.c. Well, kind of: it prints the whole file, but the lines from 5 to 10 are duplicated. This is because the default behavior, applied to every line, is to do nothing and print the (unmodified) input. We can change this behavior with the -n option:

$ sed -n '5,10 p' file.c

To print our do_thing function, we can find its address in the file using the / search. The following command:

$ sed -n '/^do_/,/^}/ p' file.c

prints all the lines between one that starts with /^do_/ and the first one after that that starts with }. If you have another function called do_other_thing, it will print that one too.

Turning it into a script

Of course typing all of this every time we want to check out a function from our file is too complicated. So we want to turn this into a script that we can easily call. We will call it cth, for “see thing’, where the c also reminds us that it is based on C’s syntax.

We may start with something like this:

#!/bin/sh

sed -n "/^$1/,/^}/ p"

Using double quotes instead of single quotes is necessary to have the $1 expand to the first argument. After saving our script to cth and making it executable with chmod +x cth, we can call it with

$ ./cth do_ < file.c

We have to use < to redirect the standard input, because our script does not read any other argument that could be interpreted as a file name. To do this, we can do:

#!/bin/sh

name=$1
shift
sed -n "/^$name/,/^}/ p" $@

This will save the first argument to a variable called name, “shift” the list of arguments and pass every remaining argument to sed with $@. In this way we can pass any number of file names. For example if we know our file is in the src directory, but we do not remember what its name is, we can glob it with:

$ cth do_ src/*

And it works! You can now find this script among my other scripts.

Remark: in bash one can simply do sed -n "/^$1/,/^}/ p" ${@:2} to match every argument from the second to the last, but this does not work in other shells such as ksh.