É um problema de "localidade", eu acho.
Na minha localidade, it_IT, o seguinte snippet
if [[ a < A ]]; then
echo "a < A"
elif [[ a > A ]]; then
echo "a > A"
else
echo "a = A"
fi
if [[ b < A ]]; then
echo "b < A"
elif [[ b > A ]]; then
echo "b > A"
else
echo "b = A"
fi
mostra
a < A
b > A
para que A
seja (surpreendentemente) entre a
e b
, portanto, no intervalo.
Tente executar
echo ABC | LC_COLLATE=C awk '$0 ~ /^[a-b]/'
Editar
o seguinte comando mostra a ordem de ordenação na sua localidade:
echo $(LC_COLLATE=C printf '%s\n' {A..z} | sort)
a saída da minha máquina é
' ^ _ [ ] a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
(não é possível entender a partir da página de manual do bash se expressões de sequência são expandidas na ordem de ordenação local ou não; parece que não).