Se você não estivesse trabalhando apenas com matemática, eu sugeriria o único outro método seguro / portátil que eu conheço que não requer testes muito rigorosos:
var1=string1
export "$var1=string2"
echo "$var1"
echo "$string1"
OUTPUT
string1
string2
Mas você está apenas trabalhando com matemática e, portanto, o problema é que você está echo
ing o valor da variável em um subshell quando você deve defini-lo e avaliá-lo no shell atual.
i=0 ; until [ $((i=$i+1)) -ge 3 ]
do echo "\$x_$i = $((x_$i=3+$i))"
done
echo $x_1 $x_2
OUTPUT
$x_1 = 4
$x_2 = 5
4 5
Então o que você está fazendo é apenas matemática. O interessante sobre a aritmética de shell é que você pode usá-lo para avaliar duas vezes com segurança uma variável no shell atual - não há subshells.
POSIX tem o que dizer sobre isso :
A expansão aritmética fornece um mecanismo para avaliar uma expressão aritmética e substituir seu valor. O formato da expansão aritmética será o seguinte:
$((expression))
The expression shall be treated as if it were in double-quotes, except that a double-quote inside the expression is not treated specially. The shell shall expand all tokens in the expression for parameter expansion, command substitution, and quote removal.
Talvez mais interessante, também tem a dizer:
All changes to variables in an arithmetic expression shall be in effect after the arithmetic expansion, as in the parameter expansion "${x=value}"
.
If the shell variable x
contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))"
and "$(($x))"
shall return the same value.
Portanto, se uma variável é definida dentro do contexto de uma substituição aritmética, essa definição persiste no ambiente atual. Como:
echo $((x=1)); echo $x
1
1
Mas se você adicionar a isso as outras partes - especificamente que o shell deve expandir todos os tokens e que "$((x))"
e "$(($x))"
devolverão o mesmo valor . Você pode ver como o loop until
acima funciona.
Então:
$((x_ #just a string
$i #integer value
= #assignment operator
3 + #addition
$i )) #same integer value
Você vê que o shell precisa expandir o $i
em ambos os contextos - o do token shell variável como uma cadeia antes do operador de atribuição e o do valor inteiro no qual ele executa a operação de adição, cuja soma é atribuído a x_$i
.
Os arrays podem ser úteis, mas, sem contar um formulário, eles não são portáteis e todos vêm com o próprio snaffus específico da implementação. E além disso - esta é a resposta para a pergunta que você fez.
É por isso que a seguinte função funciona:
defv() {
[ -n "${1##*[!0-9]*}" ] && # verify $1 is numeric only
v=x_$1 && # redefine caller loop var
: $((x_$1=5+$1)) # : do nothing but expand arg
}
for v in 1 2 3 4 5 # init array
do defv $v # defv() $indirection
echo "$v = $(($v))" # \$x_$indirection = $x_$indirection
done
OUTPUT
x_1 = 6
x_2 = 7
x_3 = 8
x_4 = 9
x_5 = 10
Suas funções:
check_1()
{
check_2 x_$1 $1
}
check_2()
{
: $(($1=3+$2))
}
for((i=1; i<=2;i++))
do
check_1 $i
tmp=x_$i
echo ${!tmp}
done
OUTPUT
4
5