Большинство bash-скриптов медленные не потому что bash плохой, а потому что внутри: лишние grep | awk | sed, десятки subshell, сетевые вызовы без таймаутов и циклы по 100k строк
И пока не измерил - не оптимизируешь.
1️⃣ Базовый уровень - time. Самое простое:
time ./script.sh
Вывод:
real 0m3.421s
user 0m0.212s
sys 0m0.084s
Что важно:real- общее время (включая ожидание сети, IO)user- CPU в user spacesys- системные вызовы
Если real > user + sys - это значит, что скрипт ждет (сеть, диск, sleep).
Если user большой - это значит много вычислений.
2️⃣ Профилирование построчно через DEBUG trap. Настоящая магия начинается здесь.
#!/usr/bin/env bash
PS4='+ $(date "+%s.%N") '
exec 3>&2
BASH_XTRACEFD=3
set -x
Но это просто трассировка. Чтобы измерять время между строками:
#!/usr/bin/env bash
last_time=$(date +%s%N)
trap '
now=$(date +%s%N)
diff=$(( (now - last_time) / 1000000 ))
echo "${diff} ms → $BASH_COMMAND"
last_time=$now
' DEBUG
Теперь перед каждой командой будет вывод:
2 ms → var=$(cat file)
153 ms → curl https://api
1 ms → echo done
И сразу видно: где реальная задержка, какой вызов тормозит и сколько стоит subshell
⚠️ Важно
trap DEBUG вызывается перед каждой командой, включая: внутренние, подстановки и циклы.На больших скриптах лог будет огромный.
▪️ Мини-профилировщик функции. Если нужно измерить только конкретный блок:
measure() {
local start=$(date +%s%N)
"$@"
local end=$(date +%s%N)
echo "Функция заняла $(( (end - start)/1000000 )) ms"
}
Использование:
measure heavy_function
BashTex 📱 #bash #utils