These seven command-line tools make the terminal faster to use. Each one handles a single job and works on its own, so install the ones you want on macOS, Linux or Windows.
| Tool | You type | What it does |
|---|---|---|
| zoxide | z | Jumps to a folder from part of its name |
| fzf | fzf | Filters any list as you type |
| ripgrep | rg | Searches inside files |
| tldr | tldr | Shows short, practical help |
| atuin | Ctrl-R | Searches your command history |
| lazygit | lazygit | Runs Git from a terminal UI |
| jq | jq | Pulls fields out of JSON |
Install them
Each system has one package manager that has all seven tools. After installing, zoxide, fzf and atuin also need a line or two in your shell's config file, the file your shell reads when it starts. The other four work as soon as they are installed.
macOS
Install them with Homebrew (check with brew --version; if it's missing, install it from the Homebrew website first):
brew install zoxide fzf ripgrep tlrc atuin lazygit jqmacOS uses zsh, so add these lines to the end of ~/.zshrc:
source <(fzf --zsh)
eval "$(atuin init zsh)"
eval "$(zoxide init zsh)"Linux
Homebrew works on Linux too, and it has newer versions than most distributions' own package managers:
brew install zoxide fzf ripgrep tlrc atuin lazygit jqMost Linux systems use bash, so add these lines to the end of ~/.bashrc. If your shell is zsh (check with echo $SHELL), use the macOS lines instead.
eval "$(fzf --bash)"
eval "$(atuin init bash)"
eval "$(zoxide init bash)"You can use apt, dnf or pacman instead, but check the version you get: fzf's --bash and --zsh options need fzf 0.48 or later.
Windows
Install them with winget, which comes with Windows 10 and 11, in PowerShell:
winget install -e --id ajeetdsouza.zoxide
winget install -e --id junegunn.fzf
winget install -e --id BurntSushi.ripgrep.MSVC
winget install -e --id tldr-pages.tlrc
winget install -e --id Atuinsh.Atuin
winget install -e --id JesseDuffield.lazygit
winget install -e --id jqlang.jqfzf's key bindings in PowerShell come from a module, and your profile (PowerShell's config file) can only run once scripts are allowed. Run these once, then open the profile:
Install-Module PSFzf -Scope CurrentUser
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
if (!(Test-Path $PROFILE)) {
New-Item -Path $PROFILE -ItemType File -Force
}
notepad $PROFILEAdd these lines to the end of it:
Import-Module PSFzf
Set-PsFzfOption -PSReadlineChordProvider 'Ctrl+t'
atuin init powershell | Out-String | Invoke-Expression
Invoke-Expression (& { (zoxide init powershell | Out-String) })If you work in WSL, follow the Linux instructions inside it instead.
On every system
Keep the lines in the order shown. zoxide asks to be last, and fzf and atuin both want Ctrl-R, so atuin goes after fzf to get it. Then open a new terminal window: a shell only reads its config file when it starts, and on Windows a new window is also what finds the newly installed commands.
zoxide: jump to folders
cd needs the path to a folder. zoxide remembers every folder you visit and scores it by how often and how recently you went there. z plus part of a name takes you to the best match, wherever you are:
z tuna # the best match for 'tuna'
z shop tuna # 'shop', then 'tuna', in that order
z - # back to the last folder
zi tuna # pick from every match (uses fzf)zoxide only knows folders you have visited, so a new folder needs one cd before z can find it. cd keeps working as before alongside it.
fzf: pick from any list
fzf is a fuzzy finder. It reads a list of lines, shows them, and filters the list as you type. 'Fuzzy' means the letters you type have to appear in order but not side by side, so tna matches tuna.test.ts. On its own, fzf lists the files below the current folder, and Enter prints the one you pick:
Because it reads any list, fzf works with other commands. Pipe in Git branches, running processes or the lines of a log, and it prints the one you choose for the next command to use.
With the shell lines added, Ctrl-T pastes a file you pick into the command you are typing. In zsh and bash, Alt-C also changes into a folder you pick.
ripgrep: search inside files
fzf finds files by name. ripgrep, run as rg, finds them by what is inside. It searches the current folder and everything below it, and prints each match with its file and line number:
It is fast on big projects because it searches files in parallel and skips three kinds of file by default: anything your .gitignore lists, hidden files and binary files. That keeps folders like node_modules and .git out of your results, and also explains most 'missing' matches. rg -uu turns the skipping off.
rg "TODO" # every match
rg -i "todo" # ignore case
rg -t py "TODO" # only Python files
rg -F "a.b(" # plain text, not a regextldr: short, practical help
A man page lists every flag a command has, which is a lot to read when you only want the common case. tldr shows a handful of examples of a command's most common uses, each with a one-line description:
The pages come from the community tldr-pages project and cover Linux, macOS and Windows commands, such as tldr tar, tldr git commit or tldr winget. Windows has no man command, so tldr fills that gap there. The official client is installed as tlrc, you run it as tldr, and it keeps a copy of the pages on your machine: refresh it with tldr --update.
atuin: search your history
Your shell's history is a plain list of commands. atuin keeps it in a database instead and records, for each command, the folder it ran in, whether it worked (its exit code), how long it took and which machine ran it. Run atuin import auto once to bring in the history you already have.
Ctrl-R, and the up arrow, open a full-screen search. Pressing Ctrl-R again inside it switches between every command, this session, this machine and this folder. Inspecting a command shows everything atuin kept about it:
Syncing between machines is optional and end-to-end encrypted, so one search can cover your laptop and your desktop, even on different systems. Without it, your history stays on your machine. To keep the up arrow for plain history, add --disable-up-arrow to atuin's line in your config file.
lazygit: Git in a terminal UI
lazygit shows a repository in panels: files, branches, commits and stashes, with the diff of whatever is selected. Run lazygit inside any Git repository, and each key you press runs a Git command:
Spacestages or unstages the selected file.ccommits what is staged, after asking for a message.Ppushes andppulls.?lists every key for the panel you are in, andqquits.
Here Space stages a changed file and c commits it with a message:
lazygit only runs ordinary Git commands, so it is as safe as Git. It also shows each command as it runs, which teaches you the Git behind each key.
jq: read JSON
APIs answer in JSON, often on one long line. jq takes a filter and prints the part of the JSON it selects, indented and coloured. Here an API's orders come back as one wall of text, and one filter keeps only the tuna:
Filters read like a path through the data:
.is the whole input, and.nameis one field..[]is every item in an array.|passes each result to the next filter, as in the shell.-rprints strings without their quotes, for output that feeds another command.
jq reads a file (jq '.name' data.json) or whatever is piped into it. In PowerShell 7.3 and later, filters work as written. The older Windows PowerShell 5.1 strips double quotes inside them, so write \"tuna\" there, and use curl.exe rather than curl.
Common mistakes
- A config change does nothing: the shell reads the file only when it starts. Open a new terminal window.
- 'Command not found' on Windows straight after installing: open a new PowerShell window.
- PowerShell says running scripts is disabled: run the
Set-ExecutionPolicyline from the Windows install. Ctrl-Ropens the wrong search: move atuin's line below fzf's.zcan't find a folder: zoxide hasn't seen it yet, socdinto it once.
These tools are for typing at the terminal yourself. Scripts and CI jobs should keep using cd, grep, find and plain git, because the next machine may not have them installed.
Key takeaways
- Homebrew installs all seven on macOS and Linux, and winget does on Windows.
- zoxide, fzf and atuin also need lines in your shell's config file, with atuin after fzf.
- zoxide and fzf get you to a folder or file in a few keystrokes, and ripgrep searches inside files.
- tldr gives the common examples, and atuin makes your history searchable by folder and result.
- lazygit runs Git from single keys, and jq pulls fields out of JSON.