nomes de variáveis ​​dinâmicas (variáveis) do bash

12

Quero criar dinamicamente uma sequência de seqüências de caracteres manipulando uma matriz de elementos e criar algum procedimento aritmético.

for name in FIRST SECOND THIRD FOURTH FIFTH; do
    $name = $(( $6 + 1 ))
    $name = "${$name}q;d"
    echo "${$name}"; printf "\n"
done

O resultado desejado seria o seguinte para $6iguais 0.

1q;d
2q;d
3q;d
4q;d
5q;d

Mas eu recebo esse erro

reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution

Eu acho que é algo simples. Costumava funcionar quando eu fazia algo como

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"
giannis christofakis
fonte
1
Você pode explicar um pouco melhor. Realmente não entendo o que você está tentando fazer.
Neurônio
O que `$ name = $ (($ 6 + 1))` deve fazer?
PSKocik 11/08/2015
@PSkocik que eu esperava fazerFIRST=$(( $6 + 1 ))
giannis christofakis

Respostas:

16

Primeiro de tudo, não pode haver espaço ao redor = na declaração de variável em bash.

Para conseguir o que deseja, você pode usar eval .

Por exemplo, um exemplo de script como o seu:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    eval "$name"="'$(( $i + 1 ))q;d'"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

Impressões:

1q;d
2q;d
3q;d
4q;d
5q;d

Use com evalcautela, algumas pessoas chamam isso de mal por algum motivo válido.

declare funcionaria também:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    declare "$name"="$(( $i + 1 ))q;d"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

também imprime:

1q;d
2q;d
3q;d
4q;d
5q;d
heemail
fonte
Para que serve o !ponto de exclamação printf '%s\n' "${!name}"?
Giannis christofakis
1
É chamado de expansão indireta da expansão de bashparâmetros
Leia
1
Bash também tem uma alternativa mais agradável para declare/ eval: printf -v varname '%fmt' args. Algumas funções internas de conclusão do bash usam isso para chamada por referência. (passe o nome de uma variável para armazenar).
Peter Cordes
Nota: Usar declareapenas define a variável no escopo local, enquanto a evalabordagem a define globalmente.
usuário
11

Se você desejar fazer referência a uma variável bash enquanto mantém o nome armazenado em outra variável, faça o seguinte:

$ var1=hello
$ var2=var1
$ echo ${!var2}
hello

Você armazena o nome da variável que deseja acessar, digamos, var2 nesse caso. Em seguida, você acessa com ${!<varable name>}onde <variable name>está uma variável que contém o nome da variável que você deseja acessar.

Eric Renouf
fonte
Há uma maneira portátil com, eval var=\$$holdermas evalé perigoso!
gavenkoa
1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

É isso que você está tentando?

neurônio
fonte
1

O que recebo do seu código e da sua saída desejada (corrija-me se estiver errado):
Não há uso dos nomes de variável "PRIMEIRO" / "SEGUNDO" / ..., você só precisa de um loop com um índice .. .

Isso fará o trabalho:

for i in {1..5} ; do echo $i"q;d" ; done

csny
fonte
Sim, você está certo, exceto, além disso, quero fazer uma função aritmética com uma variável.
Giannis christofakis
Você pode dar um exemplo dessa função aritmética? Você precisa do nome da variável (como "TERCEIRO") para ela ou apenas do valor do índice?
csny
SUM=$(($6 + $i)); echo $SUM"q;d", Vejo o que estava fazendo de errado.
Giannis christofakis