Skip to content

Instantly share code, notes, and snippets.

@ruisilva450
Created February 2, 2026 16:40
Show Gist options
  • Select an option

  • Save ruisilva450/9ecac5e0a8c7609b92fd3c15739a200a to your computer and use it in GitHub Desktop.

Select an option

Save ruisilva450/9ecac5e0a8c7609b92fd3c15739a200a to your computer and use it in GitHub Desktop.
Faster `rm -rf node_modules`
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Find project root (directory containing package.json or node_modules)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR"
while [ "$PROJECT_ROOT" != "/" ]; do
if [ -f "$PROJECT_ROOT/package.json" ] || [ -d "$PROJECT_ROOT/node_modules" ]; then
break
fi
PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
done
cd "$PROJECT_ROOT" || exit 1
if [ ! -d "node_modules" ]; then
echo -e "${YELLOW}⚠️ node_modules directory not found in project root: ${PROJECT_ROOT}${NC}"
exit 0
fi
TOTAL=$(find node_modules -mindepth 1 -maxdepth 1 2>/dev/null | wc -l | tr -d ' ')
if [ "$TOTAL" -eq 0 ]; then
echo -e "${YELLOW}⚠️ node_modules directory is empty!${NC}"
exit 0
fi
# Determine number of parallel processes (use CPU cores or max 8)
if command -v sysctl >/dev/null 2>&1; then
CPU_CORES=$(sysctl -n hw.ncpu 2>/dev/null || echo "4")
else
CPU_CORES=4
fi
PARALLEL=$((CPU_CORES > 8 ? 8 : CPU_CORES))
PARALLEL=$((PARALLEL < 2 ? 2 : PARALLEL))
show_progress() {
local current=$1
local total=$2
local percent=$((current * 100 / total))
local bar_length=50
local filled=$((current * bar_length / total))
local bar=""
for ((i=0; i<filled; i++)); do
bar="${bar}█"
done
for ((i=filled; i<bar_length; i++)); do
bar="${bar}░"
done
printf "\r${CYAN}[${bar}] ${percent}%% (${current}/${total})${NC}"
}
ITEMS_PER_PART=$((TOTAL / PARALLEL))
ITEMS_PER_PART=$((ITEMS_PER_PART < 1 ? 1 : ITEMS_PER_PART))
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
PART_NUM=0
CURRENT_ITEM=0
while IFS= read -r item; do
if [ $((CURRENT_ITEM % ITEMS_PER_PART)) -eq 0 ] && [ $CURRENT_ITEM -gt 0 ]; then
PART_NUM=$((PART_NUM + 1))
fi
echo "$item" >> "$TEMP_DIR/part_$PART_NUM"
CURRENT_ITEM=$((CURRENT_ITEM + 1))
done < <(find node_modules -mindepth 1 -maxdepth 1)
# Spawn parallel deletion processes for each partition
PIDS=()
for part_file in "$TEMP_DIR"/part_*; do
[ -f "$part_file" ] || continue
(
while IFS= read -r item; do
rm -rf "$item" 2>/dev/null
done < "$part_file"
) &
PIDS+=($!)
done
while [ ${#PIDS[@]} -gt 0 ]; do
NEW_PIDS=()
for pid in "${PIDS[@]}"; do
if kill -0 $pid 2>/dev/null; then
NEW_PIDS+=($pid)
fi
done
PIDS=("${NEW_PIDS[@]}")
REMAINING=$(find node_modules -mindepth 1 -maxdepth 1 2>/dev/null | wc -l | tr -d ' ')
DELETED=$((TOTAL - REMAINING))
show_progress $DELETED $TOTAL
[ ${#PIDS[@]} -eq 0 ] && break
# Small sleep to avoid excessive CPU usage
sleep 0.05
done
for pid in "${PIDS[@]}"; do
wait $pid 2>/dev/null
done
if [ -d "node_modules" ]; then
rm -rf node_modules 2>/dev/null
fi
show_progress $TOTAL $TOTAL
printf "\r${NC}\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment