My Top Drawer Helps Me Change Directories

Every so often I get curious about my shell command usage on Arch Linux so that I can start thinking of ways to improve my command-line efficiency. I had already recorded a few thousand lines in ~/.zsh_history on this particular computer so I knew I could extract some useful data from which to learn.

Getting the Data

I am not well-versed in zsh beyond minor customizations, so I wasn’t aware if zsh had any built-in statistics that would give me a summary and I didn’t feel like writing a parser to analyze the file so I looked on the internet. I eventually found that atuin could generate a summary that would work for my research.

After installing it, I ran atuin stats which presented my top 10 commands:

[▮▮▮▮▮▮▮▮▮▮] 1418 cd
[▮▮▮▮▮▮▮   ] 1041 ls
[▮▮▮▮      ]  673 exit
[▮▮        ]  331 iex
[▮         ]  263 cargo run
[▮         ]  235 git status
[▮         ]  211 emacs
[▮         ]  205 killall
[▮         ]  181 mix
[▮         ]  163 pacman
Total commands:   7818
Unique commands:  1610

I suspected the first 3 commands would be near the top, but the rest surprised me a little until I thought about the recent write-compile-repeat cycle I had been on some software projects lately.

These results manifested multiple questions within me:

  • Why am I moving around directories so much?
  • What files am I looking for?
  • Do I have some bad terminal habits I need to address?
  • How long have I’ve been collecting this data?
  • How does this compare to my shell history on my work computer?
  • And many more…

Getting More Granular

I decided I needed to focus on cd, but in order for me to do that, I need to find out all the directories I was visiting and how often I was visiting them.

I remembered reading that atuin extracts the history data from my shell and stores it in a SQLite database somewhere. After some hunting in my local dotfiles, I found a history.db file in ~/.local/share/atuin.

So I ran sqlite3 history.db, got my prompt and started investigating more:

SQLite version 3.45.0 2024-01-15 17:01:13
Enter ".help" for usage hints.
sqlite> .tables
_sqlx_migrations  history
sqlite> .schema history
CREATE TABLE history (
	id text primary key,
	timestamp integer not null,
	duration integer not null,
	exit integer not null,
	command text not null,
	cwd text not null,
	session text not null,
	hostname text not null, deleted_at integer,

	unique(timestamp, cwd, command)
);
CREATE INDEX idx_history_timestamp on history(timestamp);
CREATE INDEX idx_history_command on history(command);
CREATE INDEX idx_history_command_timestamp on history(
	command,
	timestamp
);
sqlite>

This was excellent. Now, I just needed to see what the data looks like:

SELECT *
FROM history
LIMIT 1;

-- Results

018d32cffd8e7c1599e40599343ba55f|1694721762001000000|0|-1|cat .zsh|unknown|018d32cffd8e785dbeab027db0d677a1|killship:angelo|

I cared only about timestamp and command, so I SELECTed them only:

SELECT timestamp, command
FROM history
ORDER BY timestamp ASC
LIMIT 1;

-- Results

1694721762001000000|cat .zsh

I dont’t understand unix timestamp epochs intuitively, so after some googling, I found the Date and Time Functions page for SQLite which pointed me to the datetime function:

SELECT datetime(timestamp/1000000000, 'unixepoch'), command
FROM history
ORDER BY timestamp ASC
LIMIT 1;

-- Results

2023-09-14 20:02:42|cat .zsh

This was so much better. Now I just needed some filtering…

SELECT datetime(timestamp/1000000000, 'unixepoch'), command
FROM history
WHERE command LIKE 'cd%'
ORDER BY timestamp ASC
LIMIT 1

-- Results

2023-09-14 20:27:17|cd code/aur

But this didn’t quite give me what I wanted. I really want to see my most frequent cd arguments and I don’t really care about the timestamps, so I dropped that part of the query and the LIMIT, then I added a COUNT and GROUP BY clause to tally up the most frequent arguments:

SELECT command, COUNT(command)
FROM history
WHERE command LIKE 'cd%'
GROUP BY command
ORDER BY count(command) DESC;

-- Results

cd ..|238
cd code|109
cd projects|93
cd|73
cd totemic|60
cd tada-beam|38
cd tada|35
cd code/projects|30
cd alakra|28
cd Downloads|27
cd code/aur|25
cd dotfiles|19
cd written|18
cd learn|15
cd github|14
...

And because I wanted to be fancy, I asked ChatGPT to generate the output a bar chart using ASCII with the following prompt:

Write a SQL query that generates a ASCII-based bar chart within sqlite from a table with 2 fields. The two fields are as follows: the first field is a name and is of type string and the second field is a number is of type integer. Please give an example of the expected output.

This gave me some explanations and the following query:

WITH RECURSIVE
  cnt(x) AS (
    SELECT 1
    UNION ALL
    SELECT x+1 FROM cnt
    LIMIT (SELECT MAX(number) FROM your_table_name)
  ),
  bar_chart AS (
    SELECT
      name,
      number,
      (SELECT GROUP_CONCAT('▮', '') FROM cnt WHERE x <= number) AS bar
    FROM your_table_name
  )

SELECT name, bar FROM bar_chart;

I then modified this with my own query:

WITH RECURSIVE
  cnt(x) AS (
    SELECT 1
    UNION ALL
    SELECT x+1 FROM cnt
    LIMIT (SELECT COUNT(command) FROM history WHERE command LIKE 'cd%')
  ),
  bar_chart AS (
    SELECT
      command,
      COUNT(command),
      (SELECT GROUP_CONCAT('▮', '') FROM cnt WHERE x <= COUNT(command)) AS bar
    FROM history
    WHERE command LIKE 'cd%'
    GROUP BY command
    ORDER BY COUNT(command) DESC
  )

SELECT command, bar FROM bar_chart;

And got these results (reformatted for clarity):


| command                  | bar                                                                                                                                                                                                                                            |
|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| cd ..                    | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ |
| cd code                  | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                  |
| cd projects              | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                  |
| cd                       | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                      |
| cd totemic               | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                   |
| cd tada-beam             | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                         |
| cd tada                  | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                            |
| cd code/projects         | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                 |
| cd alakra                | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                   |
| cd Downloads             | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                    |
| cd code/aur              | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                      |
| cd dotfiles              | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                            |
| cd written               | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                             |
| cd learn                 | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                |
| cd github                | ▮▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                 |
| cd angelolakra           | ▮▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                  |
| cd discord_arch_electron | ▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                   |
| cd go                    | ▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                   |
| cd notes                 | ▮▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                   |
| cd notes/pain            | ▮▮▮▮▮▮▮▮▮▮▮                                                                                                                                                                                                                                    |
| ...                      | ...                                                                                                                                                                                                                                            |

Most of these paths live under ~/code/projects on my system and that directory tree at 2-levels of depth (via tree -d -L 2) looks like:

├── alakra
│   ├── ditl
│   ├── dotfiles
│   ├── haikus
│   ├── journal
│   ├── scraps
│   └── todo
├── angelolakra
│   ├── devops
│   ├── diatheke
│   ├── time_tracking
│   ├── written
│   └── www
├── data
│   ├── analysis
│   ├── astronomical-objects
│   ├── closed
│   ├── generated
│   ├── jobs
│   ├── lists
│   └── mastermind
├── eve
│   ├── assets
│   ├── data
│   ├── digiship
│   ├── junk
│   ├── notebooks
│   └── reports
├── fpga
│   ├── ecet-4730
│   └── test
├── games
│   └── ticket-to-ride-core
├── jobs
│   ├── interview-project-api-battleship_Angelo-Lakra
│   └── sturdy-eureka
├── junk
│   ├── aquaduct
│   ├── extraction
│   ├── gettit
│   ├── royal
│   └── scraps
├── learn
│   ├── advent-of-code
│   ├── build-a-text-editor
│   ├── cl
│   ├── coursera
│   ├── exercism
│   ├── mazes
│   ├── my-app
│   ├── my-redis
│   ├── nasati
│   ├── programming-pearls
│   ├── project-euler
│   ├── quote-editor
│   ├── runit
│   └── scheme
├── masterminds
│   └── masterminds
├── roguepowered
│   ├── astroheart
│   ├── ditl
│   ├── imports-to-games
│   ├── interstellar-stuff
│   ├── the-coat
│   ├── the-hour-of-tower
│   ├── the-list
│   └── workspace
└── totemic
    ├── app
    ├── derts
    ├── devops
    ├── notes
    ├── reboot
    ├── rogue
    ├── rogue-strategies
    ├── rust-test
    ├── safari
    ├── site
    ├── standard
    ├── tada
    ├── tada-elixir
    ├── tada-grammars
    ├── tada-old
    ├── tools
    ├── tribal
    ├── winnow
    └── www

Realizations and Actions I’m Taking

So from the tree output and the SQL query I realized that:

  • I have spent a lot of time moving up from current directories.
  • I have spent a lot of time in my projects folder
  • I have spent a lot of time on specific projects.

After thinking about this a bit, I thought about my sock drawer. I organize everything in there by my frequency of access. My top drawer contains white undershirts, socks and underwear. I use these all the time and they are very accessible. What if I treated my projects folder like this too?

So I decided to:

  • Move my projects folder to ~/
  • Move my currently active projects to ~/

I think this small change will be a little faster for me to access things, but maybe I’m kidding myself because it’s only a few more characters. I felt like I realized this anecdotally, but this was a fun exercise to prove it to myself. I did get some good benefits out of this experience:

  • I learned about and how to Use atuin
  • I learned how to prompt ChatGPT to build non-trivial SQL
  • I practiced writing.