A recursão não é má; contanto que você esteja ciente do que acontece internamente quando você chama uma função e as armadilhas.
Primeiro, verifique se você tem uma condição de parada que será executada quando a função recursiva concluir sua tarefa. Se você não fizer isso, você não terá uma função recursiva, mas um loop indiferente.
Em seguida, variáveis e pontos de reentrada. Cada chamada para uma função envia informações na pilha; o endereço do ponto de reentrada (endereço da próxima instrução quando a função retorna). Então você tem que reservar o espaço para o tipo de valor de retorno tg.
Em seguida, é uma questão de escopo. As variáveis passam como parâmetros e as variáveis locais são declaradas na função. Cada vez que a função é chamada, esse espaço tem que ser alocado na pilha e é mantido lá até ser exibido retornando à função de chamada. Então, eventualmente, você ficará sem memória de pilha (condição de estouro de pilha).
Eu escrevi um programa de "Torres de Hanói" para uma aula de pascal que estava sendo ensinada em um DEC Vax. Eu tentei criar uma condição que iria travar meu programa ou VMS por ser capaz de adicionar tantos pólos e quantos anéis eu quisesse. Cheguei a 1000 toques em 3 poles e o programa ainda funcionava. Demorou cerca de 10 minutos para correr, mas correu.
De qualquer forma, voltemos à sua pergunta. O que parece estar acontecendo aqui é que suas variáveis estão no escopo errado - parece que elas estão sendo invocadas no ambiente global, não no local. Assim, quaisquer alterações feitas na variável pela função são refletidas em todas as instâncias da função. Todas as alterações precisam ser feitas em um escopo local e, em seguida, os valores retornados para a função de chamada. Não tenho certeza se uma linguagem interpitiva como o bash suporta variáveis locais e pode tornar todas as variáveis visíveis para toda a lógica do script.
Espero que isso ajude.