Aliases & Scripts
The Compound Effect of Small Savings
You type git status maybe 30 times a day. That's about 3 seconds each time, counting the keystrokes and the mental overhead of typing a full command. Alias it to gs and you save maybe 1.5 seconds per invocation. That's 45 seconds per day.
Sounds trivial. It's not.
45 seconds per day is 3.75 minutes per week, 3 hours per year — for a single alias. Now consider that you probably have 20-30 commands you type repeatedly throughout the day. The compound savings from a good alias set easily reach 30-60 hours per year.
But the real benefit isn't the time. It's the reduced friction. Every keystroke between you and the result you want is a tiny barrier. Remove enough tiny barriers and your terminal starts feeling like an extension of your thoughts rather than an obstacle between you and your work.
Aliases
An alias is a shortcut for a command. Define them in your shell's RC file (~/.zshrc or ~/.bashrc).
Git aliases (the highest-ROI set)
# Core workflow
alias gs="git status"
alias ga="git add"
alias gc="git commit"
alias gp="git push"
alias gl="git pull"
alias gd="git diff"
alias gds="git diff --staged"
alias gco="git checkout"
alias gsw="git switch"
alias gb="git branch"
alias glog="git log --oneline --graph --decorate -20"
# Common operations
alias gca="git commit --amend"
alias gcan="git commit --amend --no-edit"
alias grb="git rebase"
alias grbi="git rebase -i"
alias gcp="git cherry-pick"
alias gst="git stash"
alias gstp="git stash pop"
Navigation aliases
alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
# Project shortcuts (customize these)
alias proj="cd ~/projects"
alias work="cd ~/work"
alias dots="cd ~/dotfiles"
Listing aliases
alias ll="ls -la"
alias la="ls -A"
alias lt="ls -lt" # Sort by modification time
# If you use eza (modern ls replacement)
alias ls="eza"
alias ll="eza -la"
alias lt="eza -la --sort modified"
alias tree="eza --tree"
Safety aliases
# Prompt before overwriting files
alias cp="cp -i"
alias mv="mv -i"
# Show what's being removed
alias rm="rm -v"
Utility aliases
# Quick editing
alias zshrc="$EDITOR ~/.zshrc"
alias reload="source ~/.zshrc"
# Network
alias myip="curl -s ifconfig.me"
alias ports="lsof -i -P -n | grep LISTEN"
# Disk usage
alias duh="du -h -d 1 | sort -hr"
# Process searching
alias psg="ps aux | grep -v grep | grep"
Alias tips
Keep alias names short but memorable. Single-letter aliases are tempting but become confusing fast — two-letter aliases hit the sweet spot.
Don't alias commands that change behavior in surprising ways. Aliasing rm to rm -rf will eventually destroy something important.
Review your shell history to find alias candidates:
history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20
This shows your 20 most frequently used commands. Anything in the top 10 deserves an alias.
Shell Functions
When an alias isn't enough — when you need arguments in the middle of a command, or you need conditional logic — use a shell function.
Functions that should be in everyone's RC file
# Create a directory and cd into it
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Find a file by name
ff() {
find . -type f -name "*$1*" 2>/dev/null
}
# Find a directory by name
fd() {
find . -type d -name "*$1*" 2>/dev/null
}
# Quick grep with context
gre() {
grep -rn --color=auto "$1" "${2:-.}"
}
# Open the current git repo in the browser
ghopen() {
local url
url=$(git remote get-url origin 2>/dev/null)
if [ -z "$url" ]; then
echo "Not a git repository or no remote set"
return 1
fi
url=$(echo "$url" | sed 's/git@github.com:/https:\/\/github.com\//' | sed 's/\.git$//')
open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null
}
Git-specific functions
# Switch to a branch with fuzzy finding (requires fzf)
gswf() {
local branch
branch=$(git branch --all | sed 's/remotes\/origin\///' | sort -u | fzf --height 40%)
if [ -n "$branch" ]; then
git switch "$branch" 2>/dev/null || git switch -c "$branch"
fi
}
# Show a compact, useful git log
gll() {
git log --oneline --graph --decorate "${1:--20}"
}
# Delete merged branches
gclean() {
git branch --merged main | grep -v "main\|master\|\*" | xargs -r git branch -d
echo "Cleaned up merged branches."
}
Project-specific functions
# Start your dev environment
devup() {
docker compose up -d
echo "Waiting for services..."
sleep 3
echo "Services ready."
}
# Run tests with common options
t() {
if [ -f "package.json" ]; then
npm test -- "$@"
elif [ -f "go.mod" ]; then
go test ./... "$@"
elif [ -f "Cargo.toml" ]; then
cargo test "$@"
elif [ -f "pytest.ini" ] || [ -f "setup.py" ]; then
pytest "$@"
else
echo "Unknown project type"
fi
}
# Quick serve current directory
serve() {
local port="${1:-8000}"
echo "Serving on http://localhost:$port"
python3 -m http.server "$port"
}
Small Scripts
When a function grows beyond 10-15 lines, move it to a standalone script. Keep personal scripts in a directory like ~/.local/bin or ~/bin and make sure it's in your PATH.
Script template
Every script should start with these basics:
#!/usr/bin/env bash
set -euo pipefail
# Description: What this script does
# Usage: script-name [options] <argument>
# set -e: Exit on error
# set -u: Error on undefined variables
# set -o pipefail: Pipe fails if any command in the pipe fails
set -euo pipefail is non-negotiable. Without it, your script will silently continue past errors, giving you wrong results or, worse, corrupting data.
Example: daily log helper
#!/usr/bin/env bash
set -euo pipefail
LOG_DIR="$HOME/worklogs"
TODAY=$(date +%Y-%m-%d)
LOG_FILE="$LOG_DIR/$TODAY.md"
mkdir -p "$LOG_DIR"
if [ ! -f "$LOG_FILE" ]; then
cat > "$LOG_FILE" << EOF
# Work Log - $TODAY
## Plan
-
## Done
-
## Notes
-
EOF
fi
${EDITOR:-vim} "$LOG_FILE"
Example: port finder
#!/usr/bin/env bash
set -euo pipefail
PORT="${1:?Usage: whichport <port>}"
echo "Processes using port $PORT:"
lsof -i ":$PORT" -P -n 2>/dev/null || echo "Nothing found on port $PORT"
Building Your Personal Toolkit
The key principle: build tools that solve your specific problems. Generic productivity tools exist by the thousands. What makes your toolkit powerful is that it's tailored to your workflow, your projects, and your pain points.
Start with friction
Every time you catch yourself doing something repetitive or annoying, write it down. At the end of the week, look at the list and automate the top items.
Keep it simple
The best personal scripts are under 30 lines. If it's getting complex, you're probably solving the wrong problem or should reach for a real programming language instead of bash.
Version control your dotfiles
Your aliases, functions, and scripts are valuable. They represent years of accumulated workflow optimization. Put them in a git repository:
~/dotfiles/
.zshrc
.gitconfig
bin/
new-project
worklog
whichport
install.sh # Symlinks everything into place
When you get a new machine, clone the repo, run install.sh, and you're productive in minutes instead of days.
Common Pitfalls
Over-aliasing. If you can't remember what your aliases do without looking them up, you have too many. Start with 10-15 high-frequency commands and grow slowly.
Not using set -euo pipefail in scripts. This will burn you eventually. A script that silently ignores errors is a script that will delete the wrong directory at 2am.
Making scripts too clever. A script that handles every edge case, accepts 15 flags, and works on every operating system is not a personal productivity script — it's a software project. Keep personal tools simple and fix them when they break.
Forgetting to make scripts executable. After creating a new script, run chmod +x script-name. If you keep forgetting, add it as a step in your new-script workflow.
Not adding the script directory to PATH. Scripts in ~/bin are useless if ~/bin isn't in your PATH. Add export PATH="$HOME/bin:$PATH" to your RC file once and forget about it.
Key Takeaways
Aliases for your most-used commands save time and reduce friction. Check your shell history to find the best candidates.
Shell functions handle anything that needs arguments or logic. Keep a small library of them in your RC file.
Standalone scripts belong in a dedicated directory on your PATH. Always use set -euo pipefail.
Version control your dotfiles. Your personal toolkit is a valuable asset that should follow you across machines.
The best personal tools are small, specific, and built to solve problems you actually have. Don't build tooling for imaginary problems.