|| @iamidly
-- a blog about sham, unix and software design. also i rant.

sql blew my mind

i will not lie about it. sql did at one point blow my mind. at that time, the application developed at my job back then started to look like a bad case of the inner-platform effect. had they only reached for the power of stored procedures and sql views the entire software would have been exposed as smoke and mirrors.
but what really got to me about sql, was how consistently it delivered on its promises.

years later it was time for the nix shell. at that time i was not entirely unfamiliar with terminals. i had hacked a few things in windows batch, and also used bash on linux for quite some time. what i had missed though, was the raw promise of power in the pipes and filters paradigm. i watched a grand wizard do something unparalleled with git, and my mind was blown again. it was so smooth, so exploratory yet so elegant.
i asked myself, with all this power at the fingertips, how come programs like cp are not built in sh? so to answer the question, i did build it in bash. then i built mv, basename, tac and many more. eventually i attacked something of bigger complexity: an irc client.
when i connected to freenode the first time, i noticed that it would once in a while execute others' messages partly or in full. super bad. i was at that time definitely not a beginner in sh, still the quirks got me and i had to make peace with the fact, that where sql would mostly deliver on its promises, sh would mostly not.

it did not matter though. the main problem with sql was how terribly walled the whole experience of it was. you had the databases and sql, but the system remained out of reach. sh was the complete opposite, with unlimited access to the world, but with awful everything else. it became clear that marrying sql with sh would indeed create something special.
so that is what i have spent the last decade doing. i call the shell sham and the sql-like tools atools.

where sql has tables, we have files. where sql has an engine, we have linux. where sql has a script language, we have plenty. like a concatenative environment like forth has a dictionary of words, routines, so to do we have everything in /bin. and to tie it all together, we have sham.

#!/bin/sham

write 'spaces are no problem' 'nor is newline
see?' | ( read a b || exit $? "failed to read"
          echo a:$a b:$b
        )
@iamidly> sham /tmp/EXAMPLE_CODE_0_
a:spaces are no problem b:nor is newline
see?

sham does not have arrays, but it does have matrices. the table is an internal format to sham so it can keep track of number of fields, field names and such for us.

#!/bin/sham

//table is here a variable name. #string and #no are header names;
//none of these strings are types.
let table = [ #string      #no
            ;  foo          10
            ;  bar           9
            ;  baz          34
            ]

//notice that the foreach match fields by name, not by
//positional argument, so $no will be populated with field table.#no
//as expected
asort :no num <: $table
  | foreach :no :string {
      echo no:$no    string:$string
    }

echo $table[:string] and the lucky numbers are $table[:no]
@iamidly> sham /tmp/EXAMPLE_CODE_1_
no:9 string:bar
no:10 string:foo
no:34 string:baz
foo bar baz and the lucky numbers are 10 9 34

we can even set up a columnar filter with sham. the construct requires that we output the same number of rows for each column.

#!/bin/sham

let table = [ #string      #no
            ;  foo          10
            ;  bar           9
            ;  baz          34
            ]

// .. in |[ will force a pass through of the original columns
// in $table. we also add three additional columns. first two columns
//transform :no, squared and cubed respectively.
//the last column is a string concat of #string and #no
cat <: $table
  |[ ..
    :no  | acalc 'asv[no-squared] = [ :no ** 2 ]'
    :no  | acalc 'asv[no-cubed]   = [ :no ** 3 ]'
    :string,:no | { read ..
                    write #nostring
                    repeat { read a b || break
                             write $a$b
                           }
                  }
   ]
  | ./into-html-table
@iamidly> sham /tmp/EXAMPLE_CODE_2_
#string#no#no-squared#no-cubed#nostring
foo101001000foo10
bar981729bar9
baz34115639304baz34

and also funky things, to make command lines easier to build.

#!/bin/sham

let inc = [ #include
          ;  foo.lib
          ;  bar.lib
          ;  baz.lib
          ]

echo build -I$inc[:include]
@iamidly> sham /tmp/EXAMPLE_CODE_3_
build -Ifoo.lib -Ibar.lib -Ibaz.lib
|| come join me at #sham on irc.snoonet.net
</post>