Productividad en Shell
Pipes, redirección, shell scripting, aliases, y consejos de flujo de trabajo que te hacen más rápido en la terminal — adaptado para desarrolladores web.
Receta
Tarjeta de referencia rápida — lista para copiar y pegar.
# Pipes — encadena comandos
cat package.json | jq '.dependencies | keys[]'
git log --oneline | head -20
npm outdated | grep -v "Package"
# Redirección
npm run build > build.log 2>&1 # stdout + stderr a archivo
npm test 2>/dev/null # suprime errores
# Sustitución de comandos
echo "Node $(node -v) on $(uname -s)"
# Historial
history | grep "docker" # busca comandos anteriores
Ctrl+R # búsqueda inversa (interactiva)
!! # repite el último comando
sudo !! # repite el último comando con sudoCuándo usarlo: Cuando necesitas combinar comandos, automatizar tareas repetitivas, o acelerar tu flujo de trabajo en la terminal.
Ejemplo Práctico
Script de Verificación Rápida de Salud del Proyecto
#!/bin/bash
# guardar como: scripts/health-check.sh
# ejecutar con: bash scripts/health-check.sh
echo "=== Project Health Check ==="
echo ""
echo "Node: $(node -v) | npm: $(npm -v)"
echo "Branch: $(git branch --show-current)"
echo "Uncommitted changes: $(git status --porcelain | wc -l | tr -d ' ')"
echo ""
echo "--- Dependencies ---"
echo "Total packages: $(ls node_modules | wc -l | tr -d ' ')"
echo "Outdated:"
npm outdated 2>/dev/null || echo " All up to date"
echo ""
echo "--- Code Stats ---"
echo "TypeScript files: $(find src -name '*.ts' -o -name '*.tsx' 2>/dev/null | wc -l | tr -d ' ')"
echo "Test files: $(find src -name '*.test.*' -o -name '*.spec.*' 2>/dev/null | wc -l | tr -d ' ')"
echo "TODO count: $(grep -r 'TODO\|FIXME' src/ --include='*.ts' --include='*.tsx' 2>/dev/null | wc -l | tr -d ' ')"
echo ""
echo "--- Type Check ---"
npx tsc --noEmit 2>&1 | tail -1Lo que esto demuestra:
$(...)para salida de comando en línea- Combinando
find,grep,wcpara contar cosas 2>/dev/nullpara suprimir ruido- Un script práctico que realmente puedes usar en tus proyectos
Profundidad
Pipes y Composición
Los pipes (|) pasan la salida de un comando como entrada al siguiente.
# Cuenta líneas de código por tipo de archivo
find src -name "*.tsx" | xargs wc -l | sort -n | tail -20
# Encuentra las 10 dependencias más grandes
du -sh node_modules/* | sort -rh | head -10
# Lista todas las fuentes de importación únicas
grep -rh "from ['\"]" src/ | sed "s/.*from ['\"]//;s/['\"].*//" | sort -u
# Encuentra componentes que usan useState pero no useEffect
grep -rl "useState" src/components/ | xargs grep -L "useEffect"
# Cuenta commits por autor
git shortlog -sn --all | head -10
# Encuentra archivos cambiados en el último commit que contengan TODO
git diff --name-only HEAD~1 | xargs grep -l "TODO" 2>/dev/null
# Procesamiento JSON con jq
cat package.json | jq '.scripts'
cat package.json | jq '.dependencies | keys | length'
curl -s https://api.example.com/data | jq '.items[] | {id, name}'Redirección
# Redirige stdout a archivo
npm run build > build.log
# Redirige stderr a archivo
npm run build 2> errors.log
# Redirige ambos al mismo archivo
npm run build > build.log 2>&1
# Sintaxis moderna (bash 4+):
npm run build &> build.log
# Añade en lugar de sobrescribir
echo "new entry" >> log.txt
# Descarta la salida
npm install > /dev/null 2>&1
# Redirige stdin desde archivo
node script.js < input.txt
# Documento aquí (entrada multilínea)
cat << 'EOF' > .env.local
DATABASE_URL=postgresql://localhost:5432/mydb
NEXT_PUBLIC_API_URL=http://localhost:3000/api
EOFShell Aliases y Funciones
Añade a ~/.bashrc o ~/.zshrc:
# Navegación
alias ..="cd .."
alias ...="cd ../.."
alias proj="cd ~/projects"
# Atajos de Git
alias gs="git status -sb"
alias gl="git log --oneline --graph -20"
alias gd="git diff"
alias gc="git commit -m"
alias gp="git push"
alias gpu="git pull"
alias gco="git checkout"
alias gcb="git checkout -b"
# Atajos de npm
alias ni="npm install"
alias nd="npm run dev"
alias nb="npm run build"
alias nt="npm test"
alias nrd="npm run dev"
# Servidores rápidos
alias serve="npx serve ."
alias py-serve="python3 -m http.server 8080"
# Utilidad
alias ll="ls -la"
alias cls="clear"
alias ports="lsof -i -P | grep LISTEN"
alias myip="curl -s ifconfig.me"
# Funciones
mkcd() { mkdir -p "$1" && cd "$1"; }
# Mata el proceso en un puerto
killport() { lsof -ti :"$1" | xargs kill -9 2>/dev/null && echo "Killed port $1" || echo "Nothing on port $1"; }
# Crea un nuevo archivo de componente
newcomp() {
local name="$1"
local dir="src/components"
mkdir -p "$dir"
cat > "$dir/$name.tsx" << EOF
interface ${name}Props {
// props
}
export function ${name}({}: ${name}Props) {
return (
<div>
<h2>${name}</h2>
</div>
);
}
EOF
echo "Created $dir/$name.tsx"
}# Recarga después de editar
source ~/.zshrc # o ~/.bashrcFundamentos de Shell Scripting
#!/bin/bash
# Variables
NAME="my-app"
PORT=${PORT:-3000} # valor por defecto si no está establecido
TIMESTAMP=$(date +%Y%m%d)
# Condicionales
if [ -f "package.json" ]; then
echo "Node project found"
elif [ -f "Cargo.toml" ]; then
echo "Rust project found"
else
echo "Unknown project type"
fi
# Verifica si existe el comando
if command -v pnpm &> /dev/null; then
pnpm install
else
npm install
fi
# Bucles
for file in src/components/*.tsx; do
echo "Component: $(basename "$file" .tsx)"
done
# Bucle sobre líneas
git diff --name-only | while read -r file; do
echo "Changed: $file"
done
# Sale si hay error (siempre úsalo en scripts)
set -euo pipefail
# -e: sale si algún comando falla
# -u: error en variables no definidas
# -o pipefail: detecta errores en pipes
# Trap para limpieza
cleanup() { rm -f /tmp/myapp-*.log; }
trap cleanup EXITScripts Prácticos para Desarrolladores
# Verificación rápida de deploy: type-check, lint, test, build
#!/bin/bash
set -euo pipefail
echo "1/4 Type checking..."
npx tsc --noEmit
echo "2/4 Linting..."
npx next lint
echo "3/4 Testing..."
npx vitest run
echo "4/4 Building..."
npm run build
echo "All checks passed!"# Monitorea un archivo y ejecuta automáticamente un comando
# Instala: brew install entr (macOS) o apt install entr (Linux)
find src -name "*.test.ts" | entr -c npx vitest run
# O monitorea con un bucle simple
while true; do
inotifywait -r -e modify src/ 2>/dev/null || fswatch -1 src/
npx tsc --noEmit
doneAtajos de Teclado (Bash/Zsh)
Ctrl+R Búsqueda inversa del historial
Ctrl+A Mueve el cursor al inicio de la línea
Ctrl+E Mueve el cursor al final de la línea
Ctrl+W Elimina la palabra antes del cursor
Ctrl+K Elimina desde el cursor al final de la línea
Ctrl+U Elimina toda la línea (bash) / al inicio (zsh)
Ctrl+L Limpia la pantalla (igual que `clear`)
Ctrl+C Cancela el comando actual
Ctrl+Z Suspende el proceso actual (reanuda con `fg`)
Alt+B Mueve atrás una palabra
Alt+F Mueve adelante una palabra
!! Repite el último comando
!$ Último argumento del comando anterior
xargs — Construye Comandos desde Entrada
# Elimina todos los archivos .log encontrados
find . -name "*.log" | xargs rm
# Ejecuta prettier en todos los archivos TypeScript cambiados
git diff --name-only --diff-filter=M | grep '\.tsx\?$' | xargs npx prettier --write
# Abre todos los archivos que contienen un patrón en VS Code
rg -l "deprecated" src/ | xargs code
# Ejecución en paralelo
find tests -name "*.test.ts" | xargs -P 4 -I {} npx vitest run {}
# -P 4 = 4 procesos en paralelo
# -I {} = placeholder para la entradaGotchas
Cosas que te pueden atrapar. Cada gotcha incluye qué sale mal, por qué sucede, y la solución.
-
Aliases no se cargan — Los aliases definidos en
~/.bashrcno aparecen en nuevas terminales. Solución: macOS usa~/.zshrcpor defecto (zsh). Pon los aliases allí, o añadesource ~/.bashrca~/.zshrc. -
Script falla silenciosamente — Un comando en el medio falla pero el script continúa. Solución: Añade
set -euo pipefailal inicio de cada script. -
Espacios en nombres de archivo rompen xargs —
xargsdivide por espacios en blanco por defecto. Solución: Usafind -print0 | xargs -0o entre comillas variables:"$file". -
Pipe oculta códigos de salida —
cmd1 | cmd2devuelve el código de salida decmd2, ocultando fallos encmd1. Solución:set -o pipefaildetecta errores en cualquier etapa del pipe. -
Historial no se guarda — Los comandos de una terminal no aparecen en otra. Solución: Añade a
~/.zshrc:setopt SHARE_HISTORYysetopt INC_APPEND_HISTORY.
Alternativas
Otras formas de resolver el mismo problema — y cuándo cada una es la mejor opción.
| Alternativa | Úsalo Cuando | No lo Uses Cuando |
|---|---|---|
zsh + Oh My Zsh | Rico ecosistema de plugins, temas, sugerencias automáticas | Necesitas máxima compatibilidad POSIX |
fish shell | Valores por defecto sensatos, auto-completado increíble listo para usar | Los scripts necesitan ser portátiles a bash |
just (justfile) | Task runner reemplazando Makefile, sintaxis más simple | npm scripts son suficientes |
Makefile | Proyectos multi-lenguaje, automatización CI | Proyectos simples de Node.js (npm scripts bastan) |
| Turbo/Nx | Orquestación de tareas de monorepo con caching | Proyectos de paquete único |
FAQs
¿Qué hace el operador pipe (|)?
- Pasa el stdout de un comando como stdin al siguiente comando
- Ejemplo:
git log --oneline | head -20muestra solo las primeras 20 entradas de log - Puedes encadenar tantos pipes como necesites
¿Cuál es la diferencia entre > y >> para redirección?
>sobrescribe el archivo con la nueva salida>>añade al archivo sin borrar el contenido existente- Usa
>>para archivos de log; usa>cuando quieres un archivo nuevo
¿Cómo redirijo tanto stdout como stderr al mismo archivo?
npm run build > build.log 2>&1
# o (bash 4+):
npm run build &> build.log2>&1redirige stderr (descriptor de archivo 2) a donde vaya stdout (1)
¿Qué hace set -euo pipefail al inicio de un script?
-esale del script inmediatamente si algún comando falla-utrata variables no definidas como errores-o pipefaildetecta fallos en cualquier etapa de un pipe, no solo la última- Siempre incluye esto en scripts shell de producción
¿Cómo creo un alias de shell para un comando usado frecuentemente?
Añade a ~/.zshrc (o ~/.bashrc):
alias gp="git push"Luego recarga: source ~/.zshrc
Gotcha: Los aliases que definí en ~/.bashrc no funcionan en nuevas terminales en macOS. ¿Por qué?
- macOS por defecto usa
zsh, que lee~/.zshrc, no~/.bashrc - Mueve tus aliases a
~/.zshrco añadesource ~/.bashrcdentro de~/.zshrc
¿Cómo busco en mi historial de comandos un comando anterior?
- Presiona
Ctrl+Rpara búsqueda inversa interactiva - O:
history | grep "docker"para buscar de forma no interactiva !!repite el último comando;sudo !!lo vuelve a ejecutar con sudo
¿Cómo funciona xargs y cuándo debo usarlo?
xargstoma líneas de stdin y las pasa como argumentos a otro comando- Ejemplo:
find . -name "*.log" | xargs rmelimina todos los archivos.logencontrados - Usa
-P 4para ejecución en paralelo y-0confind -print0para nombres de archivo con espacios
Gotcha: Mi script continúa silenciosamente después de que un comando en un pipe falla. ¿Cómo lo detecto?
- Por defecto, solo se verifica el código de salida del último comando en un pipe
- Añade
set -o pipefailpara que cualquier fallo en el pipe cause que el script falle
¿Cómo escribo una función de shell que crea un archivo de componente TypeScript?
newcomp() {
local name="$1"
cat > "src/components/$name.tsx" << EOF
interface ${name}Props {}
export function ${name}({}: ${name}Props) {
return <div>${name}</div>;
}
EOF
}- Llama con
newcomp Buttonpara crearsrc/components/Button.tsx
¿Cuál es la diferencia entre $() y backticks para sustitución de comandos?
$(command)y`command`ambos capturan la salida de un comando$()es preferido porque se anida limpiamente:$(echo $(date))- Los backticks no se pueden anidar sin escapes incómodos
¿Cómo ejecuto un script de verificación rápida de deploy para un proyecto TypeScript?
#!/bin/bash
set -euo pipefail
echo "Type check..." && npx tsc --noEmit
echo "Lint..." && npx next lint
echo "Test..." && npx vitest run
echo "Build..." && npm run build
echo "All checks passed!"Relacionado
- Sysadmin Essentials — Gestión de procesos, disco, red y servicios
- Search & Regex — Busca archivos, busca contenido, y usa patrones regex
- Node.js Developer Commands — npm, entorno, y comandos de build