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.
huckshrc
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.
cmd-ids-where
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
}
cmd-ids-from-dir
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'"
}
cmd-here
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.
cmds-where
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.
cmds-like
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 '%$*%'"
}
Examples:
- 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
.
command_history
CREATE TABLE command_history (
id INTEGER PRIMARY KEY, -- alias for rowid
start DATETIME NOT NULL,
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.
command_output
To query based on the output of a command, look at the text
column of this table.
CREATE TABLE "command_output" (
cmd_id INTEGER NOT NULL REFERENCES command_history(id) ON DELETE CASCADE,
seq INTEGER NOT NULL,
time DATETIME NOT NULL,
line INTEGER NOT NULL,
col INTEGER NOT NULL,
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