13 Configuración y Personalización
Este capítulo final cubre la configuración avanzada del entorno de trabajo, personalización profunda de herramientas y creación de un sistema altamente productivo y eficiente.
13.1 Configuración del Shell
13.1.1 Configuración de zsh avanzada
Archivo ~/.zshrc optimizado:
# ~/.zshrc - Configuración avanzada
# History
HISTSIZE=50000
SAVEHIST=50000
HISTFILE=~/.zsh_history
setopt HIST_VERIFY
setopt SHARE_HISTORY
setopt APPEND_HISTORY
setopt INC_APPEND_HISTORY
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
# Options
setopt AUTO_CD
setopt CORRECT
setopt CORRECT_ALL
# Completions
autoload -Uz compinit
compinit
# Case insensitive completion
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'
# Initialize tools
eval "$(starship init zsh)"
eval "$(direnv hook zsh)"
eval "$(zoxide init zsh)"
eval $(thefuck --alias fix)
# Path additions
export PATH="/opt/homebrew/bin:$PATH"
export PATH="$HOME/.local/bin:$PATH"
# Environment variables
export EDITOR="code --wait"
export VISUAL="$EDITOR"
export PAGER="bat"
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
# FZF configuration
export FZF_DEFAULT_COMMAND='rg --files --hidden --follow --glob "!.git/*"'
export FZF_DEFAULT_OPTS='
--height 40%
--layout=reverse
--border
--preview "bat --color=always --style=header,grid --line-range :300 {}"
'
# Aliases
alias ls='eza'
alias ll='eza -la --git'
alias lt='eza --tree'
alias cat='bat'
alias grep='rg'
alias find='fd'
alias du='dust'
alias df='duf'
alias ps='procs'
alias top='htop'
# Git aliases
alias g='git'
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git pull'
alias gco='git checkout'
alias gb='git branch'
alias gm='git merge'
alias gd='git diff'
alias glog='git log --oneline --graph'
# Functions
# Quick CD and list
cl() {
cd "$1" && ll
}
# Make directory and CD into it
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Find and edit files
fe() {
local files
files=$(fzf --multi --preview 'bat --color=always {}') && ${EDITOR:-vim} "${files[@]}"
}
# Kill process by name
fkill() {
local pid
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
if [ "x$pid" != "x" ]; then
echo $pid | xargs kill -${1:-9}
fi
}
# Git commit with conventional commits
gci() {
local type="$1"
local scope="$2"
local message="$3"
if [ -z "$type" ] || [ -z "$message" ]; then
echo "Uso: gci <type> [scope] <message>"
echo "Types: feat, fix, docs, style, refactor, test, chore"
return 1
fi
if [ -n "$scope" ]; then
git commit -m "${type}(${scope}): ${message}"
else
git commit -m "${type}: ${message}"
fi
}
# Project initialization
init_project() {
local project_type="$1"
local project_name="$2"
if [ -z "$project_type" ] || [ -z "$project_name" ]; then
echo "Uso: init_project <type> <name>"
echo "Types: python, node, go, rust"
return 1
fi
mkdir "$project_name" && cd "$project_name"
case "$project_type" in
python)
python3 -m venv .venv
echo "source .venv/bin/activate" > .envrc
echo ".venv/" > .gitignore
echo "*.pyc" >> .gitignore
echo "__pycache__/" >> .gitignore
direnv allow
;;
node)
npm init -y
echo "node_modules/" > .gitignore
echo ".env" >> .gitignore
echo "dist/" >> .gitignore
;;
go)
go mod init "$project_name"
echo "# $project_name" > README.md
;;
rust)
cargo init
;;
esac
git init
touch README.md
git add .
git commit -m "chore: initial commit"
}
# Load local configuration if exists
[ -f ~/.zshrc.local ] && source ~/.zshrc.local13.1.2 Configuración de Starship
Archivo ~/.config/starship.toml:
# Starship configuration
format = """
$username\
$hostname\
$directory\
$git_branch\
$git_state\
$git_status\
$git_metrics\
$fill\
$nodejs\
$python\
$rust\
$golang\
$package\
$docker_context\
$time\
$line_break\
$character"""
[fill]
symbol = " "
[directory]
style = "blue"
truncation_length = 4
truncation_symbol = "…/"
[character]
success_symbol = "[❯](purple)"
error_symbol = "[❯](red)"
vicmd_symbol = "[❮](green)"
[git_branch]
symbol = "🌱 "
truncation_length = 15
truncation_symbol = "…"
[git_status]
ahead = "⇡${count}"
diverged = "⇕⇡${ahead_count}⇣${behind_count}"
behind = "⇣${count}"
conflicted = "🏳"
untracked = "🤷"
stashed = "📦"
modified = "📝"
staged = '[++\($count\)](green)'
renamed = "👅"
deleted = "🗑"
[nodejs]
symbol = "⬢ "
detect_files = ["package.json", ".nvmrc"]
detect_folders = ["node_modules"]
[python]
symbol = "🐍 "
detect_extensions = ["py"]
detect_files = ["requirements.txt", ".python-version", "pyproject.toml"]
[rust]
symbol = "🦀 "
detect_extensions = ["rs"]
detect_files = ["Cargo.toml"]
[golang]
symbol = "🐹 "
detect_extensions = ["go"]
detect_files = ["go.mod", "go.sum", "glide.yaml"]
[docker_context]
symbol = "🐳 "
detect_files = ["docker-compose.yml", "docker-compose.yaml", "Dockerfile"]
[time]
disabled = false
format = '🕙[\[ $time \]]($style) '
time_format = "%T"
utc_time_offset = "local"
[package]
symbol = "📦 "13.2 Configuración de herramientas específicas
13.2.1 Git configuración avanzada
#!/bin/bash
# setup-git.sh - Configuración avanzada de Git
setup_git_config() {
echo "🔧 Configurando Git..."
# Configuración básica
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global push.default simple
git config --global core.autocrlf input
git config --global core.editor "code --wait"
# Aliases útiles
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
git config --global alias.graph 'log --graph --pretty=format:"%h -%d %s (%cr) <%an>" --abbrev-commit'
git config --global alias.conflicts 'diff --name-only --diff-filter=U'
# Configuración de merge
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# Configuración de colores
git config --global color.ui auto
git config --global color.branch.current "yellow reverse"
git config --global color.branch.local yellow
git config --global color.branch.remote green
git config --global color.diff.meta "yellow bold"
git config --global color.diff.frag "magenta bold"
git config --global color.diff.old "red bold"
git config --global color.diff.new "green bold"
git config --global color.status.added yellow
git config --global color.status.changed green
git config --global color.status.untracked cyan
}
setup_git_hooks() {
echo "🪝 Configurando Git hooks..."
# Hook de pre-commit
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Pre-commit hook
# Verificar que no hay debuggers
if grep -r "debugger\|console\.log\|pdb\.set_trace" --include="*.js" --include="*.py" .; then
echo "❌ Debuggers encontrados. Remueve antes de commitear."
exit 1
fi
# Ejecutar linting si existe
if [ -f "package.json" ]; then
npm run lint 2>/dev/null || true
fi
# Ejecutar tests si existen
if [ -f "package.json" ]; then
npm test 2>/dev/null || true
fi
EOF
chmod +x .git/hooks/pre-commit
}
setup_git_config
[ -d ".git" ] && setup_git_hooks13.2.2 Configuración de herramientas de desarrollo
#!/bin/bash
# setup-dev-tools.sh
setup_bat() {
echo "🦇 Configurando bat..."
mkdir -p ~/.config/bat
cat > ~/.config/bat/config << 'EOF'
--theme="gruvbox-dark"
--style="numbers,changes,header"
--paging=auto
--wrap=never
EOF
}
setup_ripgrep() {
echo "🔍 Configurando ripgrep..."
cat > ~/.ripgreprc << 'EOF'
--max-columns=150
--max-columns-preview
--smart-case
--hidden
--glob=!.git/*
--glob=!node_modules/*
--glob=!dist/*
--glob=!build/*
--colors=line:none
--colors=line:style:bold
EOF
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
}
setup_fzf() {
echo "🔭 Configurando fzf..."
export FZF_DEFAULT_COMMAND='rg --files --hidden --follow --glob "!.git/*"'
export FZF_DEFAULT_OPTS='
--height 40%
--layout=reverse
--border
--preview "bat --color=always --style=header,grid --line-range :300 {}"
--bind "ctrl-/:change-preview-window(down|hidden|)"
--bind "ctrl-y:execute-silent(echo {} | pbcopy)+abort"
--color=bg+:#414559,bg:#303446,spinner:#f2d5cf,hl:#e78284
--color=fg:#c6d0f5,header:#e78284,info:#ca9ee6,pointer:#f2d5cf
--color=marker:#f2d5cf,fg+:#c6d0f5,prompt:#ca9ee6,hl+:#e78284
'
}
setup_all() {
setup_bat
setup_ripgrep
setup_fzf
echo "✅ Configuración de herramientas completada"
}
setup_all13.3 Scripts de productividad
13.3.1 Sistema de templates de proyecto
#!/bin/bash
# project-templates.sh
TEMPLATES_DIR="$HOME/.project-templates"
create_templates() {
mkdir -p "$TEMPLATES_DIR"
# Template Python
mkdir -p "$TEMPLATES_DIR/python"
cat > "$TEMPLATES_DIR/python/.envrc" << 'EOF'
export PYTHONPATH="$PWD/src:$PYTHONPATH"
export VIRTUAL_ENV="$PWD/.venv"
export PATH="$VIRTUAL_ENV/bin:$PATH"
if [ -d "$VIRTUAL_ENV" ]; then
source "$VIRTUAL_ENV/bin/activate"
fi
EOF
cat > "$TEMPLATES_DIR/python/pyproject.toml" << 'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "PROJECT_NAME"
version = "0.1.0"
description = ""
authors = [{name = "Your Name", email = "your@email.com"}]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.8"
dependencies = []
[project.optional-dependencies]
dev = [
"pytest",
"black",
"isort",
"flake8",
"mypy"
]
[tool.black]
line-length = 88
target-version = ['py38']
[tool.isort]
profile = "black"
line_length = 88
EOF
# Template Node.js
mkdir -p "$TEMPLATES_DIR/nodejs"
cat > "$TEMPLATES_DIR/nodejs/.envrc" << 'EOF'
export NODE_ENV=development
export PATH="$PWD/node_modules/.bin:$PATH"
EOF
cat > "$TEMPLATES_DIR/nodejs/package.json" << 'EOF'
{
"name": "PROJECT_NAME",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write ."
},
"keywords": [],
"author": "Your Name",
"license": "MIT",
"devDependencies": {
"eslint": "^8.0.0",
"prettier": "^2.0.0",
"nodemon": "^2.0.0",
"jest": "^28.0.0"
}
}
EOF
echo "📁 Templates creados en $TEMPLATES_DIR"
}
new_project() {
local template="$1"
local name="$2"
if [ -z "$template" ] || [ -z "$name" ]; then
echo "Uso: new_project <template> <name>"
echo "Templates disponibles:"
ls "$TEMPLATES_DIR" 2>/dev/null || echo "No hay templates (ejecuta: create_templates)"
return 1
fi
if [ ! -d "$TEMPLATES_DIR/$template" ]; then
echo "❌ Template '$template' no encontrado"
return 1
fi
if [ -d "$name" ]; then
echo "❌ Directorio '$name' ya existe"
return 1
fi
echo "🚀 Creando proyecto '$name' desde template '$template'..."
# Copiar template
cp -r "$TEMPLATES_DIR/$template" "$name"
cd "$name"
# Reemplazar PROJECT_NAME en archivos
if command -v sed >/dev/null; then
find . -type f -name "*.json" -o -name "*.toml" -o -name "*.md" | \
xargs sed -i.bak "s/PROJECT_NAME/$name/g"
find . -name "*.bak" -delete
fi
# Inicializar git
git init
git add .
git commit -m "chore: initial commit from template"
# Configurar según tipo de proyecto
case "$template" in
python)
python3 -m venv .venv
direnv allow
;;
nodejs)
npm install
direnv allow
;;
esac
echo "✅ Proyecto '$name' creado exitosamente"
echo "📁 Ubicación: $(pwd)"
}
case "${1:-help}" in
create-templates)
create_templates
;;
new)
new_project "$2" "$3"
;;
list)
echo "Templates disponibles:"
ls "$TEMPLATES_DIR" 2>/dev/null || echo "No hay templates"
;;
*)
echo "Project Templates Manager"
echo "Uso: $0 <comando> [argumentos]"
echo ""
echo "Comandos:"
echo " create-templates - Crear templates básicos"
echo " new <template> <name> - Crear proyecto desde template"
echo " list - Listar templates disponibles"
;;
esac13.3.2 Backup automatizado
#!/bin/bash
# auto-backup.sh - Sistema de backup automatizado
BACKUP_CONFIG="$HOME/.config/auto-backup/config.json"
BACKUP_LOG="$HOME/.local/log/backup.log"
init_backup() {
mkdir -p "$(dirname "$BACKUP_CONFIG")"
mkdir -p "$(dirname "$BACKUP_LOG")"
cat > "$BACKUP_CONFIG" << 'EOF'
{
"directories": [
"~/Documents",
"~/Projects",
"~/.config"
],
"exclude": [
"*.tmp",
"*.log",
"node_modules",
".git",
"dist",
"build"
],
"destinations": {
"local": "~/Backups",
"remote": "user@server.com:/backups"
},
"retention": {
"daily": 7,
"weekly": 4,
"monthly": 12
}
}
EOF
echo "Configuración de backup creada en: $BACKUP_CONFIG"
}
perform_backup() {
local destination_type="${1:-local}"
local timestamp=$(date +%Y%m%d_%H%M%S)
log_message() {
echo "[$(date)] $1" | tee -a "$BACKUP_LOG"
}
log_message "Iniciando backup ($destination_type)..."
# Leer configuración
local directories=$(jq -r '.directories[]' "$BACKUP_CONFIG")
local excludes=$(jq -r '.exclude[]' "$BACKUP_CONFIG" | sed 's/^/--exclude=/')
local destination=$(jq -r ".destinations.$destination_type" "$BACKUP_CONFIG")
# Expandir tilde en destination
destination=$(eval echo "$destination")
# Crear directorio de backup
local backup_dir="$destination/backup_$timestamp"
mkdir -p "$backup_dir"
# Realizar backup de cada directorio
echo "$directories" | while read -r dir; do
if [ -n "$dir" ]; then
expanded_dir=$(eval echo "$dir")
if [ -d "$expanded_dir" ]; then
log_message "Backing up: $expanded_dir"
rsync -av --delete \
$excludes \
"$expanded_dir/" \
"$backup_dir/$(basename "$expanded_dir")/"
if [ $? -eq 0 ]; then
log_message "✅ Success: $expanded_dir"
else
log_message "❌ Error: $expanded_dir"
fi
fi
fi
done
# Comprimir backup
log_message "Comprimiendo backup..."
cd "$(dirname "$backup_dir")"
tar -czf "backup_$timestamp.tar.gz" "backup_$timestamp"
rm -rf "backup_$timestamp"
# Limpieza de backups antiguos
cleanup_old_backups "$destination"
log_message "Backup completado: backup_$timestamp.tar.gz"
}
cleanup_old_backups() {
local backup_dir="$1"
local daily_retention=$(jq -r '.retention.daily' "$BACKUP_CONFIG")
# Eliminar backups antiguos (mantener solo los últimos N)
cd "$backup_dir"
ls -t backup_*.tar.gz | tail -n +$((daily_retention + 1)) | xargs rm -f
}
case "${1:-help}" in
init)
init_backup
;;
backup)
[ ! -f "$BACKUP_CONFIG" ] && init_backup
perform_backup "${2:-local}"
;;
logs)
tail -f "$BACKUP_LOG"
;;
*)
echo "Auto Backup System"
echo "Uso: $0 <comando> [tipo]"
echo ""
echo "Comandos:"
echo " init - Crear configuración inicial"
echo " backup [local] - Realizar backup local"
echo " backup remote - Realizar backup remoto"
echo " logs - Ver logs de backup"
;;
esac13.4 Instalación completa del entorno
#!/bin/bash
# setup-complete-environment.sh - Instalación completa
setup_homebrew_tools() {
echo "🍺 Verificando herramientas de Homebrew..."
tools=(
"bat" "eza" "ripgrep" "fzf" "zoxide" "starship"
"direnv" "tealdeer" "thefuck" "git" "gh" "node"
"ffmpeg" "imagemagick" "pandoc" "glow" "htop"
"fastfetch" "cowsay" "jq" "curl" "wget" "aria2"
)
for tool in "${tools[@]}"; do
if ! command -v "$tool" >/dev/null; then
echo "Instalando $tool..."
brew install "$tool"
fi
done
}
setup_dotfiles() {
echo "📁 Configurando dotfiles..."
# Backup de configuraciones existentes
[ -f ~/.zshrc ] && cp ~/.zshrc ~/.zshrc.backup
[ -f ~/.gitconfig ] && cp ~/.gitconfig ~/.gitconfig.backup
# Aplicar configuraciones
./setup-git.sh
./setup-dev-tools.sh
# Copiar archivos de configuración
cp .zshrc ~/.zshrc
cp starship.toml ~/.config/starship.toml
}
setup_directories() {
echo "📂 Creando estructura de directorios..."
mkdir -p ~/Projects/{personal,work,forks}
mkdir -p ~/Scripts
mkdir -p ~/.local/{bin,log}
mkdir -p ~/.config/{auto-backup,smart-monitor}
}
setup_scripts() {
echo "📜 Instalando scripts útiles..."
# Copiar scripts a ~/.local/bin
cp *.sh ~/.local/bin/
chmod +x ~/.local/bin/*.sh
# Crear enlaces simbólicos para facilidad de uso
ln -sf ~/.local/bin/project-templates.sh ~/.local/bin/new-project
ln -sf ~/.local/bin/auto-backup.sh ~/.local/bin/backup
ln -sf ~/.local/bin/git-workflow.sh ~/.local/bin/git-flow
}
finalize_setup() {
echo "🎯 Finalizando configuración..."
# Actualizar tealdeer
tldr --update
# Configurar direnv para que funcione inmediatamente
eval "$(direnv hook zsh)"
# Mensaje final
cat << 'EOF'
🎉 ¡Configuración completada!
Pasos siguientes:
1. Reinicia tu terminal o ejecuta: source ~/.zshrc
2. Configura Git con tu información: git config --global user.name "Tu Nombre"
3. Ejecuta: gh auth login para configurar GitHub CLI
4. Crea tu primer proyecto: new-project python mi-proyecto
Comandos útiles instalados:
- new-project <tipo> <nombre> - Crear proyecto desde template
- backup [local|remote] - Realizar backup
- git-flow <comando> - Workflow avanzado de Git
¡Disfruta tu nuevo entorno de desarrollo! 🚀
EOF
}
main() {
echo "🔧 Configurando entorno completo de desarrollo..."
setup_homebrew_tools
setup_dotfiles
setup_directories
setup_scripts
finalize_setup
}
main "$@"- Mantén un repositorio Git con tus dotfiles para sincronizar entre máquinas
- Documenta tus configuraciones personalizadas en un README
- Haz backups regulares de tus configuraciones importantes
- Experimenta con nuevas herramientas pero mantén tu setup estable para trabajo
- Actualiza regularmente tus herramientas:
brew update && brew upgrade - Revisa y limpia configuraciones que ya no uses
- Mantén scripts actualizados y funcionales
- Considera usar herramientas como
mackuppara backup de configuraciones
13.5 Conclusión
Este libro ha cubierto un ecosistema completo de herramientas CLI modernas que transformarán tu productividad en terminal. Desde navegación básica hasta workflows complejos de desarrollo, tienes ahora una base sólida para construir un entorno de trabajo eficiente y personalizado.
13.5.1 Lo que has aprendido:
✅ Navegación eficiente con eza, tree, ranger y zoxide
✅ Gestión avanzada de archivos con rsync y herramientas de renombrado
✅ Búsqueda ultrarrápida con ripgrep, fzf y jq
✅ Desarrollo moderno con git, gh y node
✅ Procesamiento multimedia con ffmpeg, yt-dlp e imagemagick
✅ Networking con curl, httpie y herramientas de descarga
✅ Monitoreo con htop y fastfetch
✅ Documentación con bat, pandoc y glow
✅ Utilidades como tealdeer, thefuck y starship
✅ Workflows complejos combinando múltiples herramientas
✅ Configuración completa de un entorno productivo
13.5.2 Próximos pasos:
- Practica regularmente - La muscle memory es clave
- Personaliza según tus necesidades específicas
- Automatiza tareas repetitivas con scripts
- Comparte tu conocimiento con otros desarrolladores
- Mantente actualizado con nuevas herramientas y versiones
¡El dominio de estas herramientas CLI te convertirá en un desarrollador más eficiente y productivo! 🚀