Skip to content
GitHub

Search & collections

The Search menu holds collections and recursive search by file name or contents. Both show their results as a sortable list with each file’s source path, and both work with the viewer and quick preview.

  • Ctrl-F: search the current folder and everything below it. Every word must match: main rs finds main.rs, and a | b finds either word. A lowercase word ignores case; a word with an uppercase letter matches case exactly. You can also use globs such as *.log, quoted phrases, paths with a slash such as src/lib, and -word to exclude matches, plus the filters ext:rs,toml, type:file, type:dir, type:link, size:>10M, size:1M..50M, mod:<7d (changed in the last week), mod:>1y and in:src (a folder anywhere in the path). Recent searches are listed below the form, with those made in the same folder first; click one, or press Ctrl-P and Ctrl-N in the query field, to reuse it. The dialog opens with the query and the choices you last left in it, set to the folder you are in. Names match in any alphabet whatever the case of a glob, and accented letters match however the file system stores them. Matches close to the search folder appear first, while the rest of the tree is still being read.
  • Alt-K: collect the marked files, or the current file, into a collection in the other panel. A collection holds references, so the file’s contents are not copied.
  • Alt-V: choose a saved collection from a scrollable list that shows how many entries each has and an estimate of its size. Press F7 or N to create one. Collections are kept when Borg restarts.
  • Esc: hide the results and keep the cursor, scroll position, marks, filter, and grouping.
  • Alt-Shift-R: show hidden results again. A scan keeps running while its results are hidden.
  • Alt-D: open Folder sizes to find folders by total size or file count. Hidden files are included by default. Alt-D opens the Ctrl-F dialog set to Folder totals; change Look for to switch between the two. Ctrl-C stops a scan.
  • Alt-S: calculate the sizes of the selected folder. Alt-Shift-D: open a size tree of the current folder.
  • Alt-W: maximize or restore the active result pane. Results open in a normal pane by default. The [+] (maximize), [=] (restore), and [-] (fold) controls in the title bar can be clicked. Folding hides the view; Alt-Shift-R brings it back with its layout and selection.
  • Ctrl-S: filter the results by name or source path. An empty filter shows everything.

Type text in Containing in the Ctrl-F dialog to list the files below the folder that contain it. The name pattern still applies, so *.rs with fn main in Containing finds the Rust files that have it. The switches beside the field work as in the find bar: Alt-C matches case exactly (otherwise a lowercase query matches any case), Alt-W matches whole words, and Alt-R reads the text as a regular expression. You can click the switches too. Ctrl-P and Ctrl-N in the field bring back recent queries from the find bar and earlier searches. A search for text lists files only, so it takes no folder totals or minimum file count, and Folder sizes has no Containing field.

Each result shows its first matching line, with the line number, in the Match column, and the status line adds the line number to the file’s path. F3 opens the file in the viewer at that match with the find bar open on the query, so Enter goes on to the next one, and Ctrl-Q shows it there in the quick view with the query marked. Markdown and JSON files open as source in both, since the search read the file as it is, and s switches to the formatted view. F4 opens the file in Borg’s editor at that match, with the match selected and the find bar open on the query, and Alt-E does the same in the other panel, so the results stay in view. Borg reads the files in the background, and the context line counts the files read. Binary files (a NUL byte in the first 8 KiB) and files over 64 MiB stay unread and are counted as binary or too large. Ctrl-C stops the search, and it stops at 20,000 files like any search.

Ctrl-R in the results, or Replace in files… in the File menu, replaces the text in the marked files, or in every file the results show when none is marked. Type what goes in its place and press Enter; leave the field empty to remove the text. A second question names the text and the files and starts on No. Press Y to change them. Borg keeps no copy of the old text. The search’s switches apply, so a whole-word search replaces whole words, and with a regular expression $1 puts back the first group. Borg writes each file the way its editor saves, so permissions and links stay. It skips files that are not text, are larger than 32 MiB, or changed while the job ran. The job shows in Alt-J, and the results refresh when it ends.

Set Look for to Rule matches in the Ctrl-F dialog to scan the files below the folder with YARA rules: those Borg ships and your own. The name pattern, Minimum size and Leave out build output, caches and ignored files still apply. The rules decide what to look for, so the dialog drops Containing and Minimum files.

Each result shows in the Match column the worst rule the file matched, how many more it matched, and the first bytes that rule found, as quoted text or as hex. F3 opens the file in the viewer at those bytes with the find bar on them, and F4 and the quick view land there too. The context line counts the files scanned and the rules that ran. Files over 64 MiB stay unread and count as too large, and the scan stops at 20,000 files like any search. Ctrl-C stops it.

Borg’s own rules look for:

  • reverse_shell: an interactive shell over /dev/tcp, nc or socat running a shell, or a shell spawned on a pseudo-terminal.
  • download_and_run: a script downloaded and piped straight into a shell.
  • decode_and_run: base64 decoded and run as a shell command or as Python code.
  • crypto_miner: a mining pool address, or the settings of a common miner.
  • upx_packed: an executable packed with UPX, which unpacks itself in memory.
  • execve_shellcode: the shell path exploit code builds before it starts a shell.
  • ssh_key_planted: a public key appended to an authorized_keys file.
  • reboot_job_fetch: a cron job that runs at every boot and downloads, decodes or runs something from a temporary folder.
  • password_prompt: an AppleScript dialog that asks for a password with the answer hidden, as macOS stealers do.
  • launch_agent_from_temp: a macOS launch agent or daemon that starts a program from a temporary or shared folder.
  • preload_write: a write to /etc/ld.so.preload, which loads a library into every program on Linux.
  • history_wiping: shell history turned off, or system logs emptied.
  • agent_unattended: an AI coding agent started with its approvals turned off, as the Nx supply-chain attack did to search machines for secrets.
  • hidden_prompt: a run of invisible Unicode tag characters, which can hide instructions for AI models in prompts, rule files and web pages.
  • pickle_runs_code: a pickle, the format Python and PyTorch save models in, that runs a command when it is loaded.

Put your own rules in the rules folder beside config.toml: ~/.config/borg-commander/rules, or the same folder under $XDG_CONFIG_HOME or $BORG_CONFIG_DIR. Borg reads every .yar and .yara file there and in the folders below, each in a namespace of its own, so two files can use the same rule names. Each file compiles by itself. A file with an error is left out whole, the status line names it with the compiler’s message, the context line counts the files left out, and the other files still run. Since every file loads on its own, a file that uses include is left out too, and the files it includes run by themselves.

Rules can import the hash, math, string, time, elf, macho, pe, dotnet and dex modules; a file that imports magic, cuckoo or console is left out. The variables filename, filepath and extension hold the scanned file’s name, path and extension, as rule sets written for THOR and LOKI expect, and filetype and owner are empty. A rule’s severity meta sets how much a match matters: alert, critical or high make an alert, warning, medium or suspicious a warning, and notice, low or info a notice. Without it, a score of 80 or more makes an alert, 60 or more a warning, and less a notice. A rule with neither counts as a warning. Its description and false_positives show with each match.

Borg ships no public rule sets, because their licenses differ. Download the ones you trust into the rules folder, and check each license before you use it at work:

Rules match patterns of bytes and know nothing of intent. Installers, security tools and their test data match too, and a file that no rule matches can still be malicious. Treat matches as leads. Scanning memory with rules says what a scan cannot see.

Set Look for to Packed executables in the Ctrl-F dialog to list the programs below the folder whose code is as dense as compressed or encrypted bytes. Packers and protectors leave code like that, and so does malware that hides its code until it runs. Borg reads the parts of each ELF, Mach-O and PE file that the loader maps executable, every slice of a universal Mach-O binary included, and measures the entropy of up to 1,024 blocks of 4 KiB spread evenly over them. A program is listed when at least 70% of those blocks reach 7.2 bits per byte. Code compiled the usual way stays well below that. The name pattern, Minimum size and Leave out build output, caches and ignored files still apply, and the dialog drops Containing and Minimum files.

The Match column gives the share of high blocks and the highest entropy found, such as “97% high · max 8”. F3 opens the program in the viewer’s hex rows at the first high block, with the entropy strip described under Viewer and quick view beside them. The context line counts the programs read and the other files, which hold no code Borg knows how to find. Ctrl-C stops the search, and it stops at 20,000 files like any search. A packed program shows its real code only while it runs, and Entropy scan of every process looks at programs that way.

Click a column heading to sort by it, and click again to reverse the order. The Left and Right menus also offer sorting, and the Search menu adds sorting by source folder and grouping by folder or file type. Enter on a group heading folds the group; Insert marks the matching files in it. Marks are kept when you sort or filter, and the footer also counts marked files that the filter hides.

F3 and Ctrl-Q open the original file, and after a search for text they open it at its first match. The quick view follows the cursor through the results and shows each file at its match, with the query marked as the find bar marks it. Alt-E opens the file in Borg’s editor in the other panel, so the results stay in view. Esc or F10 closes that editor and gives the focus back to the results, and the quick view comes back if it showed before. F5 copies to a real folder; if the other panel is a collection, F5 adds references to it instead. F6 needs a real folder as its destination. In a collection, F8 removes references and leaves the files alone; in search results, F8 asks to delete the original files. Shift-F8 deletes the original files from a collection too, after you confirm. When both a folder and files inside it are marked, the job handles the folder once. Reveal original or Alt-O opens the file’s folder in the other panel, with the cursor on the file. Left or Esc hides the results, and Alt-Shift-R brings them back where you left them. Tab switches between panels even when the shell has an unfinished command. The shell always stays in a real folder. F10 always asks before quitting.

Git and archive actions only work in real folder panels for now. To use them on a collected file, open its folder with Reveal original first.

Search reads file names and metadata in a background worker that you can cancel, and stops at 20,000 matches. The context line shows whether the search has finished, any errors and skipped entries, and whether it hit that limit. Hidden folders are searched only when Show hidden files is on. Search stays on the file system where it started and does not follow symlinks to folders. The search window can limit results to files or to folders and set a minimum size.

Choose Folder totals to measure every file below each folder before filtering by name, size, or minimum file count. Borg keeps the 20,000 largest matching folders and sorts them by size; click Files to rank them by file count instead. Use a pattern such as node_modules or *cache*, or * to see every folder below the starting folder.

Totals add up file contents. Deleting a folder may free a different amount of disk space. Nested folders are counted in their parents’ totals as well. Symlinks are never followed, scans stay on the file system where they started, and a folder that contains itself (through a bind mount or a hard-linked folder) is counted only once. When a total is incomplete because of such a boundary, or because a subfolder could not be read or was left out, it is shown with ≥. Folder scans read metadata only, never file contents. Results appear once the measurement is done, and you can cancel the scan at any time.

Folder size tree shows the total for the starting folder and its subfolders in the current panel. Right expands a branch, or enters it if it is already expanded; Left folds a branch or selects its parent. Enter opens the folder itself. Click a branch arrow to fold or expand it, or a column heading to sort folders on the same level by name, size, or file count. Esc hides the tree, and Alt-Shift-R brings back its branches, marks, and cursor. File operations work on the real paths, and if you mark both a folder and a subfolder, a copy or delete job gets only the folder.

While Leave out build output, caches and ignored files is checked, name searches skip generated folders: node_modules, .git, Python caches and virtual environments, folders such as target and dist that sit next to a build file (Cargo.toml, package.json), and any folder tagged with a CACHEDIR.TAG file. They also skip files excluded by .gitignore, .ignore, .rgignore, or .borgignore, and the globs in [search] exclude.

To change what is left out, press F4 in the search dialog or click F4 Edit. You can switch generated folders and ignore files on or off, and add (Ins), edit (Enter), or remove (Del) patterns. Changes are saved to the configuration file. A left-out folder still appears if its own name matches, and the context line counts how many folders were left out. Add excluded:yes to a query to search everything once, or hidden:yes to include hidden files. Size scans always read everything.

On macOS, searches and size scans that start above ~/Library/Containers and ~/Library/Group Containers skip them: reading there makes macOS hold the read until someone answers whether to allow access to another app’s data. A search started inside one of these folders does read it.

Search history stays on this computer and only you can read it. Set history = false under [search] to stop keeping it.

Search → Index this folder for instant search keeps an index of every name below the active folder, so Ctrl-F there, or in any folder below it, answers at once. The context line says when the index was built. Borg rebuilds indexes in the background after it starts and whenever an index is more than 15 minutes old, and the old index keeps answering until the new one is ready. A search that leaves nothing out, or uses different exclusions, reads the folders instead, and so does a search for text, because the index holds only names. Choose the menu item again to stop indexing and delete the index. Indexes are kept in the cache folder next to the size scans, and [index] in the configuration lists the indexed folders.

To measure sizes while keeping ordinary file panels open, press Alt-I or choose Search → Count sizes in background. Borg scans every folder below the current one, including hidden files, and fills in each folder’s total as it finishes. You can keep browsing or use the console while it runs. Folders still being measured show a growing total marked ≥, and totals stay when you leave a folder and come back. The panel footer shows progress; press Alt-I again, or click the footer, to stop the scan and keep the totals measured so far. Starting a copy, move, or delete job stops a size scan in progress. Finished scans share their cache with the size tree and Folder totals.

Finished scans are saved on this computer. Folder totals and the size tree both reuse a saved scan of the same folder with the same hidden-file setting. When you reopen a folder that was measured before, its saved sizes appear at once, marked ~, with the date of the measurement above the tree. Ctrl-R scans again in either size view, and Ctrl-C cancels. The previous tree stays visible while it refreshes, and stays if the new scan is cancelled or fails. Ordinary folder listings also show saved totals where they exist. Changes made outside Borg can make them out of date, and browsing never starts a recursive scan by itself. Copy, move, and delete jobs in Borg discard saved scans that cover the paths they changed.

The local SQLite cache keeps every measured folder for up to 16 starting folders. Trees load a branch’s subfolders when you expand it. A branch shows up to 20,000 folders, and Folder totals keeps the 20,000 largest matches; these display limits do not stop the scan or change the totals. A “Files in this folder” row accounts for the bytes stored directly in an expanded folder. Errors and skipped subfolders mark totals as incomplete. The cache lives in ~/.cache/borg-commander, or under XDG_CACHE_HOME if it is set; BORG_CACHE_DIR overrides the location. The cache only holds measurements that can be recreated, and is separate from collections. A hard-linked file counts once for every path it has. All sizes measure file contents, so the space a file takes on disk can be larger or smaller.

This guide follows the main branch · Borg 0.11.0 · 1f6bce6
The latest release may not have everything described here. Release notes