A feature-rich, POSIX-compliant shell profile that works on (almost) all shells. Designed for *NIX systems from desktops to embedded SBCs (tested on Ubuntu 25.04, Onion Omega2+ with BusyBox and MacOS Ventura).
No external dependencies required. Everything works out of the box.
- Syntax Highlighting - Real-time command highlighting as you type
- 7 Themes - Dracula, Nord, Gruvbox, Catppuccin, Tokyo Night, Monokai, Solarized
- Custom Neofetch - System info with theme-matched ASCII art
- Fuzzy CD - Jump to directories with partial names (
cdf partial) - Autojump - Learns your habits,
j partialjumps to frequently visited dirs - Smart CDPATH - Tab-complete from all CDPATH directories
- Directory Stack -
dshows numbered recent directories,cd -Njumps to them
- Shared History - Commands sync across all terminal sessions instantly
- Auto-suggestions - Fish-style prefix matching from history (shows in dim text)
- History Search - Press
Ctrl+Rand type to filter - History Stats -
histshows your most used commands
- Git Prompt - Shows branch, dirty state, stash count in your prompt
- Git Aliases - Shortcuts for common commands (
gst,gco,gl, etc.) - Works offline - No git required, gracefully degrades
- Custom Completion System - Built-in bash completion (no package needed)
- Smart Completions - For git, ssh, scp, kill, cd, make, and package managers
- Lazy Loading - Completions load on demand
- Global Aliases -
Gfor grep,Lfor less,Hfor head,Tfor tail - Spelling Correction -
cdspellauto-fixes cd typos - Vi Mode - Press
jjto exit insert mode - Plugin System - Drop scripts in
~/.profile.d/for easy organization
# Clone the repo
git clone https://github.com/efwxx/trinity.git ~/.dotfiles
# Link the profile
ln -sf ~/.dotfiles/profile ~/.profile
# Source itsource~/.profile# Backup your existing profile
cp ~/.profile ~/.profile.bak
# Copy this repo's profile to your home
cp profile ~/.profile
# Start a new shell or source itsource~/.profileecho'[[ -f ~/.profile ]] && . ~/.profile'>>~/.bashrctheme # Show current theme
theme nord # Switch to Nord
theme gruvbox # Switch to Gruvbox
and so on...dracula- Purple/pink (default)nord- Arctic blue/whitegruvbox- Retro brown/greenmocha- Dark mocha catppuccin variantmacchiato- Medium macchiato catppuccin variantfrappe- Frappe catppuccin variantlatte- Light latte catppuccin varianttokyo- Tokyo Nightmonokai- Classic Monokaisolarized- Solarized light/dark
Some features can be toggled:
# Disable real-time syntax highlightingunset RTSH_ENABLE
# Disable git prompt integrationunset GIT_PROMPT_ENABLEThis profile has a modular plugin system. Plugins are shell scripts that get loaded automatically on shell startup.
Plugins are loaded from these directories in order:
~/.profile.d/~/.dotfiles/.profile.d/
The plugin loader (60-plugin-loader.sh) does the following:
- Scans for
.profile.d/directories - Loads all
*.shfiles in each directory - Files are loaded in alphabetical order (hence the
10-,20-, etc. prefixes)
Create a new file in ~/.profile.d/ or ~/.dotfiles/.profile.d/:
# ~/.profile.d/90-my-plugin.sh# Give it a descriptive name# Variables and functions defined here are available in your shell# You can use all theme colorsecho"My plugin loaded! Theme is: $SHELL_THEME"# Define functionsmy_custom_function() {
echo"Hello from my plugin!"
}
# Set aliasesalias myalias='echo "Custom alias"'# Export variablesexport MY_CUSTOM_VAR="value"The numbers at the start of plugin names control load order:
| Prefix | Purpose |
|---|---|
10- | Core settings (PATH, history config) |
20- | Navigation features |
30- | History features |
40- | Git integration |
50- | Completions |
60- | Plugin loader itself |
90- | User custom plugins |
| Plugin | Lines | Description |
|---|---|---|
10-base.sh | 26 | History settings, PATH, EDITOR |
20-navigation.sh | 118 | Fuzzy cd, autojump, directory stack |
30-history.sh | 105 | Shared history, autosuggestions |
40-git.sh | 112 | Git aliases, git prompt |
50-completions.sh | 62 | Completion system |
60-plugin-loader.sh | 52 | Plugin loader + helper functions |
When plugins are loaded, these functions become available:
# List loaded plugins
plugin_list
# Reload all plugins
plugin_reloadTo temporarily disable a plugin, rename it:
mv ~/.profile.d/40-git.sh ~/.profile.d/40-git.sh.disabledOr move custom plugins to a separate directory:
mkdir ~/.my-plugins/
mv ~/.profile.d/my-custom.sh ~/.my-plugins/
# Then manually load: . ~/.my-plugins/my-custom.shFor plugins that work on both bash and ash:
# Good: Check for bash before using bash-specific featuresif [ -n"$BASH_VERSION" ];then# Bash-only code hereset -o vi
fi# Good: Use POSIX-compatible syntax
[ -z"$var" ] &&echo"empty"
[ -n"$var" ] &&echo"not empty"# Avoid:# - [[ ]] (bash-only)# - (( )) (bash arithmetic)# - function keyword (deprecated, but portable)# - Process substitution <() (bash-only)Want to share a plugin? Drop it in ~/.profile.d/ with a descriptive name and it will be loaded on next shell start.
Completions are stored in .profile_completions/ and provide tab-completion for various commands.
50-completions.shsets up the completion system- Completion functions in
.profile_completions/*.shdefine completion rules - When you press Tab, bash uses these rules
| Completion | What it completes |
|---|---|
git.sh | Branches, remotes, subcommands |
ssh.sh | Hosts from ~/.ssh/config |
scp.sh | Remote file paths |
kill.sh | Process names and signals |
cd.sh | Directories from CDPATH |
make.sh | Targets from Makefile |
pkg.sh | Packages for apt/yum/pacman/etc |
# ~/.profile_completions/mycmd.sh_complete_mycmd() {
local cur="${COMP_WORDS[COMP_CWORD]}"# Complete with these words
COMPREPLY=($(compgen -W "start stop restart status" -- "$cur"))
}
# Register the completioncomplete -F _complete_mycmd mycmdInside a completion function:
${COMP_WORDS[@]}- Array of words on the command line${COMP_CWORD}- Index of current word being completed${COMP_LINE}- Full command lineCOMPREPLY- Array of completions to offer
~/.dotfiles/
├── profile # Main profile
├── README.md # This file
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md # Bug report template
│ └── feature_request.md # Feature request template
├── .profile.d/ # Built-in plugins
│ ├── 10-base.sh
│ ├── 20-navigation.sh
│ ├── 30-history.sh
│ ├── 40-git.sh
│ ├── 50-completions.sh
│ └── 60-plugin-loader.sh
└── .profile_completions/ # Completion modules
├── git.sh
├── ssh.sh
├── scp.sh
├── kill.sh
├── cd.sh
├── make.sh
└── pkg.sh
These files are created automatically:
| File | Purpose |
|---|---|
~/.sh_history | Shared command history |
~/.cdhistory | Directory visit tracking for autojump |
- bash or ash
- grep, sed, awk
- find, cut, tr
git
fzf
zoxide
Everything else is optional and will be auto-detected.
cdf foo # Fuzzy find and cd into directory containing "foo"
j bar # Jump to most visited directory matching "bar"
d # Show directory stackcd -2 # Go to 2nd directory in stack
.. # cd .. (already exists)
... # cd ../.. (already exists)ps aux G nginx # Pipe to grep
cat file L # Pipe to less
ls H # Pipe to head# Type a command prefix, press Ctrl+R repeatedly to cycle matches# Or use the autosuggestion (shown dimmed, press right arrow to accept)
hist # Show history statistics
hist 20 # Show top 20 commandsgst # git status -sb
gco main # git checkout main
gcb newbranch # git checkout -b newbranch
gl # git log with graph
gp # git push
ga # git add
gc "message"# git commit -m "message"Tested and working on:
- Ubuntu / Debian
- Arch Linux
- Void Linux
- macOS
- OpenWRT (ash)
- Alpine Linux
- Android (Termux)
- MacOS Ventura (13.7.8)
Found a bug? Want a feature? Open an issue or PR.
- Fork it
- Create your feature branch
- Make your changes
- Test on a minimal system (like OpenWRT)
- Submit a PR
MIT - Do whatever you want with it.
Built from scratch with love. Shell scripting is underrated.