DEV Community

Cover image for Disk full? broot's whale-spotting mode plus Ctrl-G turns your cleanup into one command
Kamon Ayeva
Kamon Ayeva

Posted on

Disk full? broot's whale-spotting mode plus Ctrl-G turns your cleanup into one command

Every engineer knows the disk-full afternoon. The build or the backup job fails, and you end up in the same loop using du -sh and rm:

du -sh */ | sort -h
rm that-one-cache-dir
du -sh */ | sort -h
rm another-thing
Enter fullscreen mode Exit fullscreen mode

That works but, since the listing you get is flat, you see directory totals, not the files inside them. And you delete one directory at a time, with no way to collect a set of files, review the set, and delete it in one go.

This article is about a workflow I use instead, built on broot's staging area:

  1. br -w lists files sorted by size,
  2. Ctrl-G collects the files you want to delete into a review panel,
  3. :rm deletes the whole set.

Let's explore the details, while running the workflow in a real directory.

Step 1: get the sorted view with br -w

As a reminder, broot is launched using br, the shell function; launching plain broot works too, but br is what makes cd work (when you are navigating the tree and want to land in the contextual folder using the :cd verb).

The -w flag is for the whale-spotting mode: it sorts files and directories by size, biggest first. Using this feature, when a disk fills up, you can see the files that are using the space.

br -w
Enter fullscreen mode Exit fullscreen mode

As a result, the tree shows each directory with its total, and you expand any of them by moving down with the arrow keys and hitting Enter on a folder.

The difference from using du | sort -h is that you're inside one interactive tree, moving from the big directories down to the big files inside them, without running a new command per level.

Step 2: build the set of files to delete with Ctrl-G

Next, move the cursor to a file you want to delete and press Ctrl-G. A marker appears next to the filename, and a second panel opens on the right; it's the staging area, showing the files you have collected so far. Press Ctrl-G on each new file you want to delete, and it is added to that area. And you can remove a file from the set, by pressing Ctrl-G on it a second time.

Keep navigating the tree and staging files as you go. The panel refreshes everytime there is a staging or unstaging action, showing the files you collected and their total size. You can see directly how much space can freed by deleting the set, instead of guessing.

Step 3: review the set, then delete it with :rm

One detail that confused me at first: when the staging panel opens, it does not take the focus. The focus stays on the tree panel, so you can keep navigating. This means that a verb you type applies to the tree panel's selection, not the staged set, until you move the focus.

The keystroke to move the focus is Ctrl-Right. Once the staging panel is focused, you can review it like any broot panel: scroll it, filter it, and unstage files you no longer want. The whole deletion set is visible in one place before anything is gone.

In case the Ctrl-Right keystroke do not reach broot, as it happens on my macOS, just use the "typed verb" fallback: :panel_right. And, for going back to the tree panel, there is its counterpart :panel_left_no_open.

When the staged set is right, type the verb needed for deletion (:rm) and read the status line before you go ahead by hitting Enter.

:rm
Enter
Enter fullscreen mode Exit fullscreen mode

One caveat from my run (using both broot 1.58.0 on macOS and broot 1.58.0 on Ubuntu 24.04): with several files staged and the staging panel focused, the status line showed only one of them as selected — but pressing Enter removed the whole staged set. So the status bar report is partial, but the staging panel itself is the true picture of what will be deleted.

Broot's br -w: stage files to delete, review the set, and delete in one go

As you can see, using broot this way, the cleanup loop becomes: list (stage), review, delete.

Before you script the cleanup

Of course you could also use find with a size filter, or a du piped to xargs rm. And for a recurring need, scheduling that command (cron or equivalent) is the right solution.

But the first few times, you want to do it interactively. You don't yet know what is big and why, so the decision about what to delete needs a human check: is that node_modules directory obsolete? is that log file still being written? does that .db file belong to something you forgot you installed? The staging feature shows you the directory file by file, and you understand what is safe to delete. When the pattern becomes obvious (things like old logs past 90 days), then write a script for exactly that. You will know what the script touches, because you staged that set by hand.

In conclusion, do it interactively first, and script it once you know the rules for what to delete. The interactive session is how you identify the rules.

When the keystrokes do nothing

It might happen that Ctrl-G or Ctrl-Right does nothing in your terminal. Some terminals intercept those key combinations before broot receives them. But the workflow does not depend on the keys: each one has a typed verb that does the same thing.

:toggle_stage           # or :stage / :unstage — equivalent to Ctrl-G
:open_staging_area      # or :osa — force the staging panel open
:clear_stage            # or :cls — empty the staging area, start over
:panel_right            # focus the staging panel (if open)
:panel_left_no_open     # focus the tree panel
Enter fullscreen mode Exit fullscreen mode

If a keystroke does not work, type the verb instead.

Other verbs to use on the staged set

While rm is the disk-cleanup verb, the staging set works with anything:

  • :cp {dest}: copy the whole set somewhere first, then delete it; useful for a backup before the cleanup.
  • :mv {dest}: move the set to another volume instead of deleting it.
  • :chmod +x: apply a mode to every staged file, when the task is about permissions instead of space.

There is one verb that works differently: :zip takes the whole staged set as the arguments of a single zip command, so the resulting archive holds everything. While the verbs above run once per staged file, :zip runs once for the whole set.

# Inside broot, after staging several files:
:zip /tmp/backup
Enter fullscreen mode Exit fullscreen mode

That's the archive-first variant of the workflow: br -w, stage the big old logs, run one :zip (in the above example, this creates /tmp/backup.zip), then decide about deletion once the archive exists.


This article expands issue #9 of my newsletter, Shellcraft — one piece of terminal craft per week.

Top comments (0)