bash - use um valor de variável int para se referir ao parâmetro de posição em uma função

2

Eu gostaria de usar uma variável como:

i=1

como um valor para referir-se a variáveis de posição passadas ao script, por exemplo:

x=101
y=201
z=301

foo(){
    echo "$1"
    echo "$2"
    echo "$3"
}

foo x y z

saída:

101
201
301

Em vez de se referir a cada parâmetro por índice, como eu poderia usar i para incrementar como uma variável de índice?

Para esclarecer:

foo() {
    local i=1
    echo "$i" #echo first paramter
    (( i+=1 ))
    echo "$i" #echo second parameter
    #etc.
}

qual é a sintaxe da parte echo "$i" ?

UPDATE após @Eric answer

~$ t=5
~$ foo() { i=1; echo "${!i}"; }
~$ foo t
t
~$

Atualização nº 2

Em suma, a única maneira de fazer meu método funcionar é com isso:

foo() { #assuming 3 parameters

    i=0
    (( i+=1 ))
    var="${!i}"
    echo "${!var}"

    (( i+=1 ))
    var="${!i}"
    echo "${!var}"

    (( i+=1 ))
    var="${!i}"
    echo "${!var}"        
}
    
por Cybex 29.02.2016 / 20:25

2 respostas

4

Isso é semelhante à pergunta SO aqui , que é semelhante ao comentário @costas. Você pode usar $# para obter o número de argumentos e, em seguida, referências indiretas como ${!i} para acessar uma variável pelo nome. Aqui está um exemplo:

f() {
    for((i=1; i<=$#; i++)); do
        printf "%d %s\n" "$i" "${!i}"
    done
}

f a b c

quais impressões:

1 a
2 b
3 c

Ver agora que você deseja passar os nomes das variáveis como argumentos posicionais, você pode adicionar uma camada extra de referência indireta da seguinte forma:

a=first
b=second
c=third

f() {
    for((i=1; i<=$#; i++)); do
        var="${!i}"
        printf "%d %s\n" "$i" "${!var}"
    done
}

f a b c

que imprime

1 first
2 second
3 third

Isso nos permite tratar cada argumento como o nome de uma variável, que armazenamos em var aqui. Então, acessamos essa variável indiretamente no printf .

Você só recebe uma camada de indireção de cada vez, o aninhamento não funciona. Então, tentar fazê-lo de uma só vez como ${!${!i}} não funciona porque o primeiro { inicia a expansão, com o restante sendo tratado como o valor PARÂMETRO a ser expandido. O primeiro caractere sendo ! tratará o restante como o nome do PARAMETER contendo o nome do parâmetro desejado, mas ${!i} não é um nome de parâmetro válido, portanto, obtemos um bad substitution . Então, fazemos isso em duas etapas para evitar esse problema.

    
por 29.02.2016 / 20:43
2

Usando shift , você pode fazer o seguinte:

num_args="$#"

for (( i = 1; i <= "$num_args"; i++ )); do
    echo "$1"
    shift
done

Aqui, o comando shift desloca cada próximo argumento dos argumentos passados para o script para ser o valor de $1 .

Por exemplo:

$ ./myscript one two three four five six
one
two
three
four
five
six

em que, na primeira execução do loop, $1 = "one" , depois na segunda execução do loop, $1 = "two" , assim por diante, até o último argumento.

Editar: Se você quiser acessar qualquer um dos seus argumentos de script sem ordem, por exemplo. Usando os 2º e 4º argumentos ao mesmo tempo, um método está usando matrizes bash da seguinte forma:

# Initialize the array 'myargs' with all script arguments
myargs=( "$@" )

for (( i = 0; i < "$#"; i++ )); do
    echo "${myargs[$i]}"
done

Aqui, você pode acessar qualquer um dos seus argumentos com qualquer índice especificado i usando o formulário "${myargs[$i]}" .

    
por 29.02.2016 / 20:54