Ну в том виде, в котором у вас скрипт создан, других вариантов и не видно.
Если количество шагов меняется, то grep|wc вполне себе вариант
TOTAL_STEPS=$(grep step_start $0| wc -l )
только не забыть, что сам grep тоже будет +1.
Но если количество шагов у вас не меняется, то просто статику добавить в начало скрипта и все.
Или все зависит от скрипта, от шагов и архитектуры.
Я вот не очень понимаю зачем вы создаете функцию перед и после каждого шага, ее же вызывать надо?
Пример не очень релевантент.
Или как раз сами шаги можно было бы запихнуть в функции, а имена функций в массиве и бежать циклом по массиву. При этом можно сперва и посчитать количество элементов в массиве чуть проще, и шаги организовывать нагляднее, сортировать, убирать, добавлять.
steps="initialize build deploy notify"
function initialize() { echo code1; }
function build() { echo code2; }
function deploy() { echo code3; }
function notify() { echo code4; }
echo "We have total $(wc -w<<<"$steps") steps."
for step in $steps; do
echo "Executing step $step"
$step
done
Или можно работать с массивом
function initialize() { echo code1; }
function build() { echo code2; }
function deploy() { echo code3; }
function notify() { echo code4; }
steps=( initialize build deploy notify )
echo "We have ${#steps} steps in total"
for step in ${steps[@]}; do
echo executing $step
$step
done