Thu May 30, 2024

Using the hucksh database

Home » Hucksh(ell) » Hucksh Documentation » Using the hucksh database

Hucksh has a database where it saves all the commands you run, and all their output. To make full use of the product, understanding the database is key.


The distribution has a default huckshrc included. That file has several functions in it that invoke hucksh tab or hucksh sql, or both, to manipulate the current list of commands in the current tab. The default install scripts copy the default huckshrc to $HOME/.huckshrc (if it doesn’t exist already), so you should have one in your home.

Adding and removing commands from the current tab

hucksh tab --add and hucksh tab --remove both take a list of command IDs and add them to the current tab, or remove them from the current tab. Example: hucksh tab --add 1234 or hucksh tab --remove 2345.

There are two functions in huckshrc, cmds-add and cmds-rm that wrap hucksh tab --add|-remove and all they want is that list of IDs. Example: cmds-add 1234 or cmds-rm 2345.

There’s also hucksh tab --replace, which replaces the commands shown in the current tab with the given list of commands. It’s wrapped by the function cmds-list. Example: hucksh tab --replace 1234 2345 would replace all the commands in the current tab with just those two commands. cmds-list 1234 2345 would do the same, but the function also includes the command ID of the current command (that is, of cmds-list itself), so after it ran there’d be three commands in the tab: 1234, 2354, and the invocation of cmds-list 1234 2354 itself. The current command ID is set as an environment variable in every hucksh command: $HUCKSH_CMD_ID. So cmds-list is just

hucksh tab --replace "$@" $HUCKSH_CMD_ID

Generating a list of IDs

So how do you get that all-important list of IDs? Another query, of course.

hucksh sql

The hucksh sql command connects directly to the SQLite database file (that is, unlike most hucksh commands, it doesn’t go through the hucksh server) and runs sql against it. And as mentioned above, there are various functions in huckshrc that wrap it and make some of its functions easier to use or remember.


This function wraps a query against the command_history table and pulls out IDs of all commands that match a given SQL expression. It looks like this

function cmd-ids-where {
  hucksh sql \
    "select id
    from command_history
    where ($1)
      and command not like 'cmds-%'
      and command not like 'hucksh %popout%'" \
    2> /dev/null


This function builds on cmd-ids-where to return all IDs from commands that were run in the given directory.

function cmd-ids-from-dir {
  cmd-ids-where "directory = '$1'"


And finally, this function builds on cmd-ids-from-dir to replace commands in the current tab with commands run from the current directory.

function cmds-here {
  hucksh tab --replace $(cmd-ids-from-dir $PWD) $HUCKSH_CMD_ID

After running cmds-here, the tab should have all (and only) commands run from the current directory.


This function wraps a call to hucksh tab --replace and cmd-ids-where.

function cmds-where {
  hucksh tab --replace $(cmd-ids-where "$1") $HUCKSH_CMD_ID

So it takes a SQL expression, gets the IDs that match it, and replaces the commands in the current tab with those commands, including the cmds-where invocation itself.


The previous functions give you commands based on where you ran them. cmds-like gives you commands based on the text of the command run.

function cmds-like {
  cmds-where "command like '%$*%'"


  • Show commands that have make in them: cmds-like make
  • Show commands that have hucksh in them: cmds-like hucksh

You get the idea.

Since this is SQL, use ? to match a single wildcard character, or % to match 1-or-more characters.

Technically, cmds-like and functions like it are vulnerable to “sql injection” attacks. But it’s your query, your database, and your data; you’d only be “attacking” yourself. Given that you could also just rm $HUCKSH_DBNAME, worrying about a sql injection attack seems moot.

The hucksh schema

The two most important tables to know about are command_history and command_output.


CREATE TABLE command_history (
   id INTEGER PRIMARY KEY, -- alias for rowid
   stop DATETIME,
   duration INTEGER, -- nanoseconds
   signal INTEGER,
   status INTEGER,
   err TEXT,
   finished BOOLEAN DEFAULT 0,
   directory TEXT NOT NULL,
   command TEXT NOT NULL

The three most important columns in that table are id, command, and directory. id we’ve already discussed. command has the text of the command, and directory has where it ran.


To query based on the output of a command, look at the text column of this table.

CREATE TABLE "command_output" (
   fg INTEGER, -- 32 bits, r, g, b, a; null == default?
   bg INTEGER, -- same
   -- bit field: bit 0 first: 
	-- bold, italic, dim, underline, strikethrough, blink, inverse, hidden
   -- So bold is 0x01, italic is 0x02, dim is 0x04, etc.
   attr INTEGER,
   text TEXT

I don’t query command_output very often and so don’t have any functions that wrap it, but as an example, I once wanted to see every time a Go program had panicked, so I opened a new tab ran this query:

cmds-where "id in (select cmd_id from command_output where text like '%panic: runtime error%')"

The full schema

To view the full schema, run the schema function. To view only tables (schema shows indexes, too), run schema-tables. Check the huckshrc file for the full usage of either function.

Further exploration

Check the huckshrc file for other functions. Each has an accompanying comment documenting its use.

Here’s a full list, as of this writing:

  • cmds-add
  • cmds-rm
  • running
  • cmds-running
  • num-running
  • cmds-all
  • cmds-list
  • refresh-tab
  • cmds-here
  • cmds-in-tree
  • cmds-like
  • cmds-glob
  • cmds-likeg
  • cmds-regex
  • cmds-regexp
  • cmds-liker
  • cmds-where
  • cmd-ids-from-dir
  • cmd-ids-where
  • schema
  • schema-tables
  • show-tabs
  • show-tab-cmd-count
  • sql-columns
  • reset-tab-counts
  • set-config

Home » Hucksh(ell) » Hucksh Documentation » Using the hucksh database