Skip to content

Instantly share code, notes, and snippets.

@marijnbent
Last active May 14, 2025 13:29
Show Gist options
  • Save marijnbent/02af375463dae03ceb0bf02a4b3d29a0 to your computer and use it in GitHub Desktop.
Save marijnbent/02af375463dae03ceb0bf02a4b3d29a0 to your computer and use it in GitHub Desktop.
Brew Interactive Install
#!/bin/bash
#
# brew-interactive: Interactive Homebrew Package Management
#
# Install it as a brew package here: https://github.com/marijnbent/homebrew-interactive-install
#
# Description:
# This script provides an enhanced, interactive command-line interface for
# managing Homebrew packages (formulae and casks). It streamlines the common
# workflow of searching for a package, viewing its information, and then
# installing it. Instead of typing multiple `brew` commands, you can:
#
# 1. Search for packages using a fuzzy finder (`fzf`).
# 2. Instantly preview `brew info` for the highlighted package within `fzf`.
# 3. Select a package (press Enter) to directly install it.
# 4. After an install attempt, you are immediately presented with options to:
# - Re-run the same search (refresh results).
# - Start a new search for a different package.
# - Quit the interactive session.
#
# This tool is ideal for users who frequently explore and install new
# Homebrew packages and prefer a more dynamic, keyboard-driven experience.
# It leverages `fzf` for its powerful fuzzy searching and preview capabilities.
#
# Keywords for search:
# brew, homebrew, fzf, interactive, search, install, package manager,
# formula, cask, tui, cli, fuzzy finder, brew search, brew info, brew install
#
# ------------------------------------------------------------------------------
# Installation and Setup:
# ------------------------------------------------------------------------------
#
# 1. Prerequisites:
# - Homebrew: Must be installed on your macOS or Linux system.
# (See: https://brew.sh/)
# - fzf (Fuzzy Finder): This script relies heavily on `fzf`.
# Install it via Homebrew:
# `brew install fzf`
#
# 2. Save the Script:
# Copy the entire content of this script and save it to a file on your
# system. For example, you could name it `brew-interactive.sh` or simply `brewi`.
# A common location for personal scripts is `~/bin` or `~/.local/bin`.
#
# Example:
# `mkdir -p ~/bin` (if it doesn't exist)
# `curl -o ~/bin/brewi https://gist.github.com/YOUR_GIST_URL/raw/brewi.sh`
# (Replace `YOUR_GIST_URL` if you host it on a Gist)
# OR
# `nano ~/bin/brewi` (and paste the script content)
#
# 3. Make it Executable:
# Navigate to the directory where you saved the script and make it executable:
# `chmod +x ~/bin/brewi`
#
# 4. Add to PATH (Recommended):
# If you saved the script to a directory like `~/bin` or `~/.local/bin`,
# ensure this directory is in your system's `PATH` environment variable.
# This allows you to run the script by simply typing its name from any
# directory.
#
# To check if `~/bin` is in your PATH:
# `echo $PATH`
#
# If it's not, add one of the following lines to your shell's configuration
# file (e.g., `~/.bashrc`, `~/.zshrc`):
#
# For bash:
# `export PATH="$HOME/bin:$PATH"`
# For zsh:
# `export PATH="$HOME/bin:$PATH"` (or `path=($HOME/bin $path)`)
#
# After editing the file, source it or open a new terminal window:
# `source ~/.bashrc` or `source ~/.zshrc`
#
# 5. Create an Alias (Optional):
# If you prefer a different command name or if the script is not in your
# PATH, you can create an alias in your shell's configuration file.
#
# Example alias in `~/.bashrc` or `~/.zshrc`:
# `alias brewi='/path/to/your/script/brew-interactive.sh'`
# (Replace `/path/to/your/script/` with the actual path)
#
# Remember to source your shell config file after adding an alias.
#
# ------------------------------------------------------------------------------
# Usage:
# ------------------------------------------------------------------------------
#
# Once installed and (optionally) in your PATH or aliased:
#
# - To start and be prompted for a search term:
# `brewi`
#
# - To start with an initial search term:
# `brewi <search_term>`
# Example: `brewi httpie`
#
# Inside the script:
# - Use arrow keys (↑↓) to navigate the search results in `fzf`.
# - The right pane will show `brew info` for the highlighted package.
# - Press `Enter` on a package in the list to *directly install it*.
# - Press `Esc` in the `fzf` list to go back to the main options menu
# (search again, new search, quit).
#
# ------------------------------------------------------------------------------
set -euo pipefail
if ! command -v fzf &> /dev/null; then
echo "Error: fzf could not be found." >&2
echo "Please install it first: brew install fzf" >&2
exit 1
fi
if ! command -v brew &> /dev/null; then
echo "Error: brew command could not be found." >&2
echo "Please ensure Homebrew is installed and in your PATH." >&2
exit 1
fi
main_interactive_loop() {
local current_search_term="$1"
local packages=""
local selected_package=""
while true; do
if [ -z "$current_search_term" ]; then
local new_search_input
echo
read -r -p "Enter Brew search term (or press Enter to quit): " new_search_input
if [ -z "$new_search_input" ]; then
echo "No search term provided. Quitting."
return 0
fi
current_search_term="$new_search_input"
fi
echo
echo "Searching for '$current_search_term'..."
packages=$( (brew search --formulae "$current_search_term" 2>/dev/null; brew search --casks "$current_search_term" 2>/dev/null) |
grep -v '^==>' |
grep . |
sort -u )
if [ -z "$packages" ]; then
echo "No packages found matching '$current_search_term'."
# No packages found. Proceed directly to the main options menu.
else
# Packages found. Enter the fzf loop for selection.
# This loop runs once per selection (install) or if Esc is pressed in fzf.
# After one selection/install, it breaks to the main menu.
while true; do
selected_package=$(echo "$packages" | fzf \
--prompt="Select ('$current_search_term' results | Enter: INSTALL | Esc: main menu): " \
--height="70%" \
--layout=reverse \
--border \
--preview-window='right:60%:wrap' \
--header "Search: '$current_search_term'. ↑↓ to navigate. Enter to INSTALL. Preview: 'brew info'." \
--preview="echo 'Loading info for {}...' && brew info {} 2>/dev/null || echo 'No detailed info or cask not tapped.'" \
--exit-0)
if [ -z "$selected_package" ]; then
break
fi
echo
echo "-----------------------------------------------------"
echo "Attempting to install: $selected_package (from search '$current_search_term')"
echo "-----------------------------------------------------"
if brew install "$selected_package"; then
echo -e "\n'$selected_package' installed successfully!"
else
echo -e "\nFailed to install '$selected_package'. It might already be installed or another issue occurred." >&2
fi
echo
break
done
fi
echo
echo "What would you like to do next?"
echo "1. Search again for '$current_search_term' (refresh results)"
echo "2. Search for a new app"
echo "3. Quit"
local choice
while true; do
read -r -p "Enter your choice (1-3): " choice
case "$choice" in
1)
echo "Preparing to search again for '$current_search_term'..."
break
;;
2)
current_search_term=""
echo "Preparing to search for a new app..."
break
;;
3)
echo "Quitting."
return 0
;;
*) echo "Invalid choice. Please enter 1, 2, or 3." >&2 ;;
esac
done
done
}
initial_search_term="${1-}"
main_interactive_loop "$initial_search_term"
exit 0
@marijnbent
Copy link
Author

You can install it as a brew package here: https://github.com/marijnbent/homebrew-interactive-install

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment