Obtendo valores de variáveis - script bash

4

Estou tentando escrever um script bash para imprimir valores das três variáveis. Continue recebendo erros. O que estou fazendo errado?

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for i in 1 2 3
do 
echo $(INPUT$i)
done

Quando executo esse script, a saída é:

syntax error: operand expected (error token is "/tmp/dir1
    
por Ubuntuser 26.08.2013 / 12:45

4 respostas

3

O Bash não suporta esse tipo de sintaxe diretamente. Você poderia usar 'eval', no entanto, com versões modernas de 'bash' a maneira mais limpa é através de um array

input=( "/tmp/dir1" "/tmp/dir2" "/tmp/dir3" )

for i in {0,1,2}; do echo "${input[i]}"; done

(note que os arrays do bash são indexados com zero); ou para listar todos os elementos que você pode usar

for i in "${input[@]}"; do echo "$i"; done
    
por steeldriver 26.08.2013 / 13:17
3

Concordo que usar uma matriz como mostrado em outras respostas é uma maneira melhor de resolver a tarefa real do OP.
Mas essas respostas não respondem diretamente à pergunta, como declarado, então eu farei isso:

Veja como você pode fazer isso com eval para acessar as variáveis, acompanhando de perto a maneira como o OP deu seu código:

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for i in {1..3} ; do
    eval "echo $INPUT$i"
done

Saída:

/tmp/dir1
/tmp/dir2
/tmp/dir3
    
por Volker Siegel 14.09.2014 / 20:53
0

A melhor maneira é definir INPUT variable como uma matriz:

#!/bin/bash

INPUT[1]=/tmp/dir1
INPUT[2]=/tmp/dir2
INPUT[3]=/tmp/dir3

for i in "${INPUT[@]}"
do 
echo $i     #or $INPUT[$i]
done

Veja também: link

    
por Radu Rădeanu 26.08.2013 / 13:16
0

bash na verdade suporta algo muito próximo do que você primeiro tentou .

INPUT1=/tmp/dir1
INPUT2=/tmp/dir2
INPUT3=/tmp/dir3

for s in INPUT{1..3}; do
    echo ${!s}
done

Isso funciona porque:

  • INPUT{1..3} expande para INPUT1 INPUT2 INPUT3 . (É equivalente a INPUT{1,2,3} .)

  • Em que $s é a expansão de s , ${!s} é a expansão da expansão de s .

    Por exemplo, na primeira iteração do loop, se $s aparecer, ele será expandido para INPUT1 . Se $INPUT1 aparecer, seria expandido para /tmp/dir1 . Assim, ${!s} é expandido para /tmp/dir1 .

    Esse tipo de expansão de parâmetros é chamado expansão indireta . Nesta situação e em muitos outros, a sintaxe ! integrada obtém isso de maneira mais compacta e elegante do que eval .

    Para obter mais informações, consulte É possível criar nomes de variáveis de outras variáveis no bash? em estouro de pilha .

Algumas ressalvas (que também se aplicam a algumas das outras respostas que foram postadas):

  • Se algum valor de INPUTn puder conter espaço em branco 1 (como espaços 2 , guias ou newlines ) ou (como $varname ), citando deve ser usado.

    Aspas simples para a tarefa são melhores se você quiser evitar toda a expansão lá: INPUT1=/tmp/dir1INPUT1='/tmp/dir with spaces'

    (Apenas um caractere de aspas ' é tratado especialmente, pois ele funcionará como a marca de fechamento de citações.)

    Mas use aspas duplas para permitir que a variável seja expandida:
    echo ${!s}echo "${!s}"

    (Isso funciona mesmo se o valor após a expansão contiver um $ . O conteúdo expandido não será expandido novamente.
    Por exemplo, BAZ=QUUX FOO='BAR $BAZ'; echo "$FOO" imprime BAR $BAZ , não BAR QUUX .)

  • Se algum dos INPUTn assumir um valor que echo interpretaria como uma opção em vez de texto para imprimir, substitua echo por printf '%s\n' . 3

    Atualmente, isso é - seguido por mais um e , E ou n . Mas você provavelmente deve considerar qualquer coisa que comece com - como perigosa no caso de futuras versões bash adicionarem novas opções.

Embora, em termos de sintaxe, a expansão indireta apresentada acima seja quase tão simples quanto fazê-lo com uma matriz, você ainda pode querer usar uma matriz porque:

  • Pode refletir melhor o significado subjacente do problema que você está tentando resolver.
  • Você pode usar outros recursos de matrizes para resolver esse problema.

Talvez você pretendesse /tmp/dir1 , /tmp/dir2 e /tmp/dir3 como exemplos opacos que podem ser substituídos por qualquer coisa.

Mas se você realmente quiser criar uma matriz desses valores específicos, recomendo:

input=(/tmp/dir{1..3})

Da mesma forma, se o seu objetivo for percorrer /tmp/dir1 , /tmp/dir2 e /tmp/dir3 e executar alguma ação com cada um, você não precisará armazená-los em nenhum tipo de variável :

for s in /tmp/dir{1..3}; do
    echo $s
done

Se os valores de s contiverem espaços em branco ou caracteres especiais (veja acima), cite-os, mas deixe o intervalo de {...} sem aspas separadamente, citando o texto à esquerda e à direita dele - não ser expandido se for cotado, mesmo entre aspas duplas.

for s in '/tmp/dir '{1..3}' with  spaces'; do
    echo "$s"
done

Isso imprime:

/tmp/dir 1 with  spaces
/tmp/dir 2 with  spaces
/tmp/dir 3 with  spaces

E se seu objetivo for realmente apenas imprimir /tmp/dir1 , /tmp/dir2 e /tmp/dir3 , cada um em sua própria linha, então esse único comando 3 é suficiente:

printf '%s\n' /tmp/dir{1..3}

1 : o shell divide o texto em palavras no espaço em branco ou, se a variável IFS estiver definida, nos separadores de campos especificados. Mas normalmente você não precisa se preocupar com IFS , a menos que você tenha definido você mesmo.

2 : echo hello world realmente funciona: ela imprime hello world , como echo 'hello world' . Isso ocorre porque echo imprime um único espaço entre cada argumento ecoado . No entanto, echo hello world não é equivalente a echo 'hello world' : a primeira ainda imprime hello world enquanto a segunda imprime hello world .

3 : Para mais informações sobre bash ' printf builtin, consulte o saída de help printf ou esta seção do manual de Bash . printf também é um executável que pode ser chamado de outros shells (e nessa capacidade é padronizado ).

    
por Eliah Kagan 18.09.2014 / 17:47

Tags