Isso acontece porque os colchetes são expandidos antes que o comando seja chamado. Assim você acaba com um comando como:
for i in 1 2 3 ... 10000000 ; do ...
.. e, portanto, usa muita memória ou trava.
A solução ao trabalhar com loops longos é usar a sintaxe do estilo c do bash:
for ((i = 1; i <= 10000000; i++))
do
...
done
Ou, se você quiser permanecer compatível com outros shells, pode canalizar para um loop while:
seq 1 10000000 | while IFS= read -r line
do
...
done