A modular, automated setup system for Ubuntu/WSL development environments
LinuxUtils is a comprehensive shell configuration and development environment setup system that automates the installation and configuration of essential development tools, shell environments, and custom utilities through a hierarchical initialization system. It provides a unified configuration for both Bash and Zsh, integrates modern CLI tools with FZF-powered fuzzy finding, and offers smart editor detection with optional Neovim support.
- Features at a Glance
- Quick Start
- What Gets Installed
- Architecture
- Custom Features & Utilities
- Usage Guide
- Customization
- Configuration Details
- Troubleshooting
- Contributing
✅ Automated Setup - One-command installation of complete development environment ✅ Idempotent Scripts - Run setup multiple times without duplicates or conflicts ✅ Dual Shell Support - Unified configuration for both Bash and Zsh ✅ Modern CLI Tools - FZF, ripgrep, bat, lazygit, lazydocker, and more ✅ Smart Editor Detection - Automatically prefers Neovim over Vim ✅ FZF Everywhere - Fuzzy finding for files, history, SSH hosts, and packages ✅ Custom Functions - Extensible command system with auto-generated aliases ✅ Oh My Zsh Integration - Full Zsh plugin ecosystem with custom prompt ✅ Development Ready - Node.js (via NVM), JVM tools (via SDKMAN), Docker ✅ SSH Made Easy - Smart SSH agent management and FZF host selection
# Clone the repository
git clone <repo-url> ~/linuxutils
cd ~/linuxutils
# Make setup script executable (if needed)
chmod +x setup.sh# Standard setup (installs everything except Neovim)
./setup.sh
# Setup with Neovim + LazyVim configuration
./setup.sh --nvim
# View help and all options
./setup.sh --helpThe setup process will:
- Install and update all system packages
- Install Oh My Zsh and plugins (if zsh available)
- Install NVM and Node.js 22
- Install SDKMAN for JVM tools
- Install Homebrew and all configured packages
- Configure shell environments (Bash/Zsh)
- Set up Vim with plugins
- Optionally install Neovim + LazyVim
# Restart your terminal or source the configuration
source ~/.bashrc # for Bash
source ~/.zshrc # for Zsh
# Test FZF integration
fzf --version
# Test custom commands
fapt --help # FZF APT package browser
f sometext # Fuzzy grep search
ssh # SSH with FZF host selection (no arguments)
# Check editor preference
echo $EDITOR # Should show nvim or vimCore utilities and development tools:
| Package | Description |
|---|---|
git |
Version control system |
tree |
Directory tree visualization |
build-essential |
Compilation tools (gcc, make, etc.) |
zsh |
Z Shell - Modern shell alternative |
neofetch |
System information display |
cowsay |
ASCII art text generator |
ansiweather |
Terminal weather display |
zip / unzip |
Archive utilities |
tar / gzip |
Compression tools |
htop |
Interactive process viewer |
btop |
Modern resource monitor |
ripgrep |
Fast text search tool (rg) |
bat |
Modern cat replacement with syntax highlighting |
gdu |
Fast disk usage analyzer |
traceroute |
Network diagnostic tool |
Modern CLI tools installed via Homebrew:
| Package | Description |
|---|---|
fzf |
Command-line fuzzy finder |
oh-my-posh |
Cross-shell prompt theme engine |
lazygit |
Terminal UI for git commands |
lazydocker |
Terminal UI for docker commands |
g-ls |
Modern ls replacement with icons |
asciinema |
Terminal session recorder |
agg |
Asciinema GIF generator |
Containerized applications:
- Docker - Container platform for development
Node.js (via NVM)
- Node.js version 22 (LTS)
- Automatically configured with default alias
SDKMAN
- Java SDK manager
- Pre-configured for JVM tool installation
- Run
sdk install javaafter setup to install Java
Oh My Zsh Plugins (if Zsh available)
git- Git aliases and functionscolorize- Syntax highlighting for filescolored-man-pages- Colorful manual pagescompleat- Enhanced completionsemoji- Emoji support in terminalssh- SSH helper functionsyou-should-use- Reminds you to use existing aliaseszsh-autosuggestions- Fish-like autosuggestionszsh-syntax-highlighting- Syntax highlighting for commandsfast-syntax-highlighting- Faster syntax highlighting alternative
When using the --nvim flag:
- Neovim - Hyperextensible Vim-based text editor
- LazyVim - Pre-configured Neovim distribution with plugins
- Automatically backs up existing Neovim configuration
- Installs on first
nvimstartup
LinuxUtils uses a hierarchical setup orchestrated by setup.sh:
setup.sh
├── 1. dependencies/init.sh (System packages & tools)
├── 2. configs/init.sh (Shell & application configs)
└── 3. functions/init.sh (Custom functions & aliases)
┌─────────────────────────────────────────────────────┐
│ setup.sh │
│ Orchestrates all initialization in correct order │
└─────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ dependencies/ │ │ configs/ │ │ functions/ │
│ init.sh │ │ init.sh │ │ init.sh │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ APT/Brew/ │ │ Shell Configs│ │ Make scripts │
│ Snap Packages│ │ → bashrc.sh │ │ executable │
│ │ │ → zshrc.sh │ │ │
│ NVM/Node.js │ │ │ │ Generate │
│ │ │ Application │ │ aliases for │
│ SDKMAN/JVM │ │ setups: │ │ all custom │
│ │ │ → setup_*.sh │ │ functions │
│ Homebrew │ │ │ │ │
│ │ │ Preserve │ │ Create │
│ Oh My Zsh │ │ SDKMAN at │ │ functions_ │
│ + plugins │ │ end of .rc │ │ aliases.sh │
│ │ │ │ │ │
│ [Optional] │ │ │ │ │
│ Neovim + │ │ │ │ │
│ LazyVim │ │ │ │ │
└───────────────┘ └───────────────┘ └───────────────┘
Bash Configuration Flow:
~/.bashrc
│
└─→ source ~/linuxutils/configs/shell/bashrc.sh
│
├─→ Eval Homebrew shellenv
├─→ Initialize oh-my-posh
├─→ Configure bash-specific settings
│
└─→ Source all common/*.sh files
├─→ editor.sh (detect nvim/vim)
├─→ fzf.sh (fuzzy finder config)
├─→ aliases.sh (common aliases)
├─→ ssh_fzf.sh (SSH integration)
├─→ fuzzygrep.sh (search function)
├─→ fapt.sh (APT browser)
├─→ functions_aliases.sh (auto-generated)
├─→ neofetch.sh (startup display)
├─→ ssh-agent-loader.sh (SSH key management)
│
└─→ Source all bash_*.sh files (bash-specific)
Zsh Configuration Flow:
~/.zshrc
│
└─→ source ~/linuxutils/configs/shell/zshrc.sh
│
├─→ Initialize Oh My Zsh (if installed)
├─→ Eval Homebrew shellenv
├─→ Initialize oh-my-posh (overrides OMZ prompt)
├─→ Configure zsh-specific settings
│
├─→ Source all common/*.sh files
│ (same as Bash, see above)
│
├─→ Source all zsh_*.sh files (zsh-specific)
│
├─→ Unalias 'g' (prevent conflict with g-ls)
│
├─→ Initialize NVM
│
└─→ Initialize SDKMAN (must be at end!)
Key Points:
- Both shells share
configs/shell/common/*.shfiles - Shell-specific files use prefixes:
bash_*.shorzsh_*.sh - SDKMAN initialization must always be at the end
- Oh My Zsh integrates seamlessly with custom configurations
FZF (fuzzy finder) is deeply integrated throughout the system with custom keybindings:
Keyboard Shortcuts:
| Key | Function | Description |
|---|---|---|
Ctrl+T |
File search | Search and insert file path at cursor |
Ctrl+R |
History search | Search command history with preview |
Alt+C |
Directory jump | Search and cd into directory |
Ctrl+F |
File editor | Search files and open in vim/nvim |
Ctrl+/ |
Toggle preview | Show/hide preview window |
Features:
- Beautiful borders and labels (German localization)
- Live preview with syntax highlighting (bat/batcat)
- Smart file search using
fdorfdfindwhen available - Automatic nvim/vim detection for file opening
- Tree preview for directory navigation
- Custom color scheme
Smart SSH connection with fuzzy finding:
# Run ssh without arguments to get FZF host selector
ssh
# Or use the keyboard shortcut
# Alt+S - Opens FZF SSH host selectorFeatures:
- Reads hosts from
~/.ssh/config - Excludes wildcard patterns
- Adds selected command to shell history
- Preserves TTY for interactive sessions
- Works in both Bash and Zsh
Interactive two-step search tool (aliased as f):
# Search for text across all files
f "searchterm"
# Interactive prompt if no term provided
fHow it works:
- Step 1: Find all files containing the search term
- Step 2: Select specific match within chosen file
- Opens editor at exact line and column position
Features:
- Uses
ripgrepfor blazing fast search - Preview shows context with syntax highlighting
- Opens vim/nvim at exact match location
- Smart column positioning in editor
Interactive APT package browser with beautiful UI:
# Launch the package browser
fapt
# Also available as
apt-searchFeatures:
- Browse all available APT packages with FZF
- Rich preview showing:
- Package name and version
- Installation status (color-coded)
- Description and details
- Maintainer and homepage
- Install/reinstall packages directly
- Confirmation prompt for already-installed packages
- Beautiful box-drawing characters and colors
The system automatically detects and configures your preferred editor:
Detection Order:
nvim(Neovim) - Preferred if installedvim(Vim) - Fallback if Neovim unavailablevi- Last resort
Environment Variables Set:
$EDITOR- Used by git, cron, etc.$VISUAL- Used by some applications$PREFERRED_EDITOR- Custom variable for scripts
Integration:
valias points to preferred editor- FZF file opening uses detected editor
- Fuzzygrep opens files in detected editor
- All custom utilities respect preference
Intelligent SSH key management on shell startup:
Features:
- Starts ssh-agent if not running
- Reuses existing agent if available
- Automatically detects encrypted vs unencrypted keys
- Loads unencrypted keys silently
- For encrypted keys:
- Prompts once for common password
- Tries common password on all encrypted keys
- Individual prompts for keys with different passwords
- Validates each key before moving to next
- No duplicate key loading
Behavior:
- Runs automatically on shell initialization
- Silent for unencrypted keys
- Interactive only when necessary
- Secure password handling (no echoing)
Enhanced system information display on shell startup:
Features:
- ASCII art with cowsay (flaming-sheep)
- Live weather for Solothurn, CH
- Color-coded by shell:
- Zsh: Pink/Gold
- Bash: Cyan
- Others: White
- Only runs if all dependencies available
- Falls back to standard neofetch
Setup & Maintenance:
# Show help and options
./setup.sh -h
./setup.sh --help
# Full setup
./setup.sh
# Setup with Neovim
./setup.sh --nvim
# Update all system packages
sau
# Re-run specific initialization
lu-dependencies # Re-run dependency installation
lu-dependencies --nvim # With Neovim installation
lu-configs # Re-configure shells
lu-functions # Regenerate function aliasesFile & Directory Navigation:
# Change to parent directory
..
# List files with icons
ls # g-ls with icons
ll # Long format with icons, sorted by name
# Search and open file
Ctrl+F # Interactive file searchSearch & Find:
# Fuzzy grep search
f "searchterm" # Search and open at exact match
fuzzygrep "searchterm" # Same as above
# FZF search (interactive)
Ctrl+T # File search, insert path
Ctrl+R # Command history
Alt+C # Directory search and cdSSH:
# SSH with host selection
ssh # Opens FZF host picker
Alt+S # Keyboard shortcut for host picker
# Traditional SSH still works
ssh user@hostPackage Management:
# Interactive APT browser
fapt
apt-search # Same as above
# System update
sau # Update APT, Snap, HomebrewGit:
gs # git status
ga # git add
lg # lazygit (terminal UI)Editor:
v file.txt # Open in preferred editor (nvim/vim)Shell:
# Switch default shell
change-my-shell # Toggle between bash and zshNetwork:
# Unset all proxy variables
unset-proxysFZF Integration:
Ctrl+T- Search files and insert pathCtrl+R- Search command historyAlt+C- Search and change directoryCtrl+F- Search and open file in editorCtrl+/- Toggle preview in FZFAlt+S- SSH host selector (FZF)
Bash Specific:
- Tab completion is case-insensitive
- First tab shows all ambiguous completions
Zsh Specific:
Ctrl+R- Incremental backward search
Essential:
cls # Clear screen
v # nvim or vim (auto-detected)
sau # System update (APT + Snap + Brew)Navigation:
.. # cd ..
ls # g --icon --sort=name
ll # g --icon --long --sort=name --sh
la # ls -AGit:
gs # git status
ga # git add
lg # lazygitSearch:
f # fuzzygrep (search and edit)Setup:
lu-dependencies # Re-run dependencies/init.sh
lu-configs # Re-run configs/init.sh
lu-functions # Re-run functions/init.shNetwork:
unset-proxys # Unset all proxy environment variablesPackage Management:
apt-search # fapt (APT package browser)After making changes to configurations:
Shell Configuration Changes:
# Apply changes without restarting terminal
source ~/.bashrc # For Bash
source ~/.zshrc # For Zsh
# Or use the alias after re-running config init
lu-configs
source ~/.bashrc # or ~/.zshrcAdded New Function:
# Regenerate aliases and reload
lu-functions
source ~/.bashrc # or ~/.zshrcAdded New Package:
# Edit apt.sh, brew.sh, or snap.sh, then:
lu-dependenciesFull Re-initialization:
cd ~/linuxutils
./setup.sh # Run full setup again (idempotent)APT Packages:
- Edit
dependencies/apt.sh - Add package name to
APT_PACKAGESarray:
APT_PACKAGES=(
"git"
"vim"
"your-new-package" # Add here
)- Run:
lu-dependencies
Homebrew Packages:
- Edit
dependencies/brew.sh - Add to
BREW_PACKAGESorBREW_CASKSarray:
BREW_PACKAGES=(
"fzf"
"your-new-package" # Add here
)- Run:
lu-dependencies
Snap Packages:
- Edit
dependencies/snap.sh - Add to
SNAP_PACKAGESarray:
SNAP_PACKAGES=(
"docker"
"your-new-package" # Add here
)- Run:
lu-dependencies
Create files in configs/shell/common/:
For Both Shells:
# Create a new configuration file
touch configs/shell/common/my-feature.sh
# Add your configuration
echo 'export MY_VAR="value"' >> configs/shell/common/my-feature.sh
echo 'alias myalias="command"' >> configs/shell/common/my-feature.sh
# No additional setup needed - automatically loaded on next shell startBash Only:
# Create bash-specific configuration
touch configs/shell/common/bash_my-feature.shZsh Only:
# Create zsh-specific configuration
touch configs/shell/common/zsh_my-feature.shApply Changes:
source ~/.bashrc # or ~/.zshrcCustom scripts in functions/ become globally available commands:
Example:
# Create a new function
cat > functions/backup-db.sh << 'EOF'
#!/bin/bash
echo "Backing up database..."
# Your backup logic here
EOF
# Regenerate aliases
lu-functions
# Reload shell
source ~/.bashrc # or ~/.zshrc
# Now available as command (without .sh)
backup-dbHow it works:
functions/init.shmakes all*.shfiles executable- Auto-generates alias for each script (minus
.shextension) - Aliases stored in
configs/shell/common/functions_aliases.sh - Scripts can be run from anywhere in the system
Application-specific configurations go in configs/applications/:
Example:
# Create application setup script
cat > configs/applications/setup_myapp.sh << 'EOF'
#!/bin/bash
print_status "Setting up MyApp..."
# Your setup logic here
# - Create config files
# - Symlink configurations
# - Install plugins
# - etc.
print_status "MyApp setup complete!"
EOF
# Run configs initialization
lu-configsAuto-discovery:
- All
setup_*.shfiles are automatically found and executed - Use
print_status,print_warning,print_errorfor consistent output - Check
configs/applications/setup_vim.shfor a complete example
Add completely new initialization categories:
Example:
# Create new category directory
mkdir -p ~/linuxutils/cloud-tools
# Create initialization script
cat > ~/linuxutils/cloud-tools/init.sh << 'EOF'
#!/bin/bash
print_status "Setting up cloud tools..."
# Install AWS CLI
# Install Azure CLI
# Install GCloud SDK
# Configure credentials
# etc.
print_status "Cloud tools setup complete!"
EOF
# Make executable
chmod +x ~/linuxutils/cloud-tools/init.sh
# Run full setup (auto-discovers new category)
cd ~/linuxutils
./setup.shNote: To control execution order, edit SETUP_ORDER array in setup.sh:
SETUP_ORDER=("dependencies" "configs" "cloud-tools")When Oh My Zsh is installed, the system:
- Initializes Oh My Zsh first (with empty theme)
- Sources Homebrew environment for package availability
- Initializes oh-my-posh (overrides Oh My Zsh prompt)
- Sources all common configs (see Shell Configuration Chain)
- Unaliases
gto prevent conflict withg-ls(git alias from OMZ)
Active Plugins:
git- Git aliases and functionscolorize- Syntax highlighting for filescolored-man-pages- Colorful manual pagescompleat- Enhanced completionsemoji- Emoji supportssh- SSH helper functionsyou-should-use- Alias usage reminderszsh-autosuggestions- Fish-like suggestionszsh-syntax-highlighting- Command syntax highlightingfast-syntax-highlighting- Alternative faster highlighting
Critical Rule: SDKMAN initialization must be at the end of shell configs.
Why? SDKMAN modifies PATH and other variables that can interfere with other tools if loaded too early.
How it's handled:
configs/init.shautomatically detects existing SDKMAN lines- Removes them temporarily during configuration
- Adds custom config sourcing
- Re-adds SDKMAN lines at the very end
Manual Verification:
# Check that SDKMAN is at the end
tail ~/.bashrc # or ~/.zshrc
# Should see these lines at the bottom:
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"The system detects and configures editors in this priority:
- Neovim (
nvim) - Preferred if available - Vim (
vim) - Fallback option - Vi (
vi) - Last resort
Environment Variables:
echo $EDITOR # nvim, vim, or vi
echo $VISUAL # Same as $EDITOR
echo $PREFERRED_EDITOR # Custom variable for scriptsWhere it's used:
valias inconfigs/shell/common/aliases.sh- FZF file opening in
configs/shell/common/fzf.sh - Fuzzygrep in
configs/shell/common/fuzzygrep.sh - Any custom scripts can use
$PREFERRED_EDITOR
Configuration Files:
~/.bashrc # Modified to source bashrc.sh
~/.zshrc # Replaced/modified to source zshrc.sh
~/.vimrc # Symlinked to configs/applications/vim/vimrc
LinuxUtils Locations:
~/linuxutils/ # Main directory
├── setup.sh # Main setup script
├── dependencies/init.sh # Package installation
├── configs/init.sh # Configuration setup
├── configs/shell/bashrc.sh # Bash configuration
├── configs/shell/zshrc.sh # Zsh configuration
├── configs/shell/common/ # Shared shell configs
│ ├── aliases.sh # Common aliases
│ ├── editor.sh # Editor detection
│ ├── fzf.sh # FZF configuration
│ ├── fuzzygrep.sh # Fuzzy grep function
│ ├── ssh_fzf.sh # SSH with FZF
│ ├── fapt.sh # APT package browser
│ ├── ssh-agent-loader.sh # SSH agent management
│ ├── neofetch.sh # System info display
│ ├── functions_aliases.sh # Auto-generated aliases
│ ├── bash_*.sh # Bash-specific configs
│ └── zsh_*.sh # Zsh-specific configs
├── configs/shell/ohmyposh/custom-zash.omp.json # Oh-my-posh theme
├── configs/applications/ # Application setups
│ ├── setup_vim.sh # Vim setup script
│ └── vim/ # Vim configuration
│ ├── vimrc # Vim config file
│ └── plugins.vim # Vim plugins
└── functions/ # Custom functions directory
├── init.sh # Functions initialization
└── *.sh # Custom function scripts
Oh My Zsh:
~/.oh-my-zsh/ # Oh My Zsh installation
~/.oh-my-zsh/custom/plugins/ # Custom OMZ plugins
Development Tools:
~/.nvm/ # Node Version Manager
~/.sdkman/ # SDKMAN installation
/home/linuxbrew/.linuxbrew/ # Homebrew installation
Shell configuration not loading:
# Check if linuxutils is sourced in rc file
grep "linuxutils" ~/.bashrc # or ~/.zshrc
# If missing, re-run configs
lu-configs
source ~/.bashrc # or ~/.zshrcFZF not working:
# Check if FZF is installed
fzf --version
# Reinstall via dependencies
lu-dependencies
# Or install directly
brew install fzfCustom function not available:
# Check if script exists and is executable
ls -la ~/linuxutils/functions/
# Regenerate aliases
lu-functions
source ~/.bashrc # or ~/.zshrcVim plugins not installed:
# Open vim and manually install
vim +PlugInstall +qall
# Or re-run configs
lu-configsSDKMAN not working:
# Check if SDKMAN is at end of rc file
tail ~/.bashrc # or ~/.zshrc
# If not, re-run configs (handles SDKMAN placement)
lu-configs
source ~/.bashrc # or ~/.zshrcOh My Zsh conflicts:
# The system handles OMZ integration automatically
# If issues persist, backup and remove .zshrc
mv ~/.zshrc ~/.zshrc.backup
lu-configsNeovim LazyVim issues:
# Check if Neovim is installed
nvim --version
# Reinstall LazyVim
rm -rf ~/.config/nvim
rm -rf ~/.local/share/nvim
lu-dependencies --nvim
# Or install manually
./setup.sh --nvimPATH issues after setup:
# Ensure Homebrew is in PATH
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
# Check PATH
echo $PATH
# Restart terminal to apply all changesSSH agent not loading keys:
# Check if ssh-agent is running
ps aux | grep ssh-agent
# Check loaded keys
ssh-add -l
# Manually reload
source ~/linuxutils/configs/shell/common/ssh-agent-loader.shPackage installation fails:
# Update package lists first
sudo apt update
# Check for held packages
sudo apt-mark showhold
# Try installing package manually to see error
sudo apt install <package-name>Contributions are welcome! Here's how you can help:
Adding Features:
- Fork the repository
- Create a feature branch
- Add your feature following existing patterns:
- New packages → Edit
dependencies/*.sh - New shell configs → Add to
configs/shell/common/ - New utilities → Add to
functions/ - New app setup → Add to
configs/applications/
- New packages → Edit
- Test thoroughly on clean Ubuntu/WSL instance
- Submit pull request with clear description
Reporting Issues:
- Use GitHub issues
- Include: OS version, shell type, error messages
- Describe steps to reproduce
Best Practices:
- Keep scripts idempotent (safe to run multiple times)
- Use
print_status,print_warning,print_errorfor output - Test in both Bash and Zsh if adding shell configs
- Document new features in README
- Follow existing code style
Note: This project is tailored for Ubuntu/WSL environments. Some features may require adaptation for other Linux distributions.