Qual é a maneira mais correta de passar uma matriz para uma função?

8

Considere que eu tenho uma matriz muito grande $large_list, existe uma maneira de escrever uma função que levará a matriz como argumento? Por exemplo:

echo_idx_array () {
    arr="$1"
    idx="$2"

    echo "${arr[$idx]}"
}

Qual é a estratégia usual para fazer algo assim? Eu tentei dar a variável, $large_listmas estava vazia.

Estou disposto a modificar a função para adaptá-la a qualquer alteração na lista de argumentos.

Para constar, estou usando o ksh88 e estou procurando respostas o mais portáteis possível.


EDIT : Até agora, o melhor que eu poderia fazer é percorrer a matriz e enviar cada elemento como argumento para a função. Isso parece incrivelmente feio e propenso a erros, sem mencionar que é provável que atinja algum limite rapidamente. Aqui está o que eu fiz:

foo () {
    echo $*
}

cmd="foo "
while [[ $i -lt $MAX_ARR_SIZE ]]; do
    cmd="$cmd ${large_list[$i]}"
    ((i=i+1))
done

eval $cmd

Não há algo melhor para fazer?

rahmu
fonte
1
Não estou familiarizado com o ksh88, mas se você precisar passar toda a matriz por valor, já tentou func "${array[@]}"? Se você só precisa passar um elemento, basta passá-lo - não há necessidade de torná-lo mais complicado passando uma matriz e um índice.
Jk013
Eu tentei a sintaxe que você sugeriu, mas não funcionou :(
rahmu
1
Eu estava cansado e confuso. Eu tentei "${array[$@]}. Sua sugestão realmente funciona. Mea culpa.
rahmu

Respostas:

10

Para passar os elementos da matriz como argumentos para a função, use a sintaxe ksh para expandir os elementos da matriz como uma lista.

work_on_array "${myarray[@]}"

O [@]sufixo faz disso uma expansão de matriz. As aspas duplas protegem cada elemento de maior expansão (divisão e globbing). O resultado da expansão não é, em geral, uma palavra como costuma ser entre aspas duplas, mas tantas palavras quanto elementos na matriz.

O N -ésimo elemento da matriz é, em seguida . Para acessá-lo, você precisa usar ; consulte Usar uma referência de variável "dentro" de outra variável${N}eval

Gilles 'SO- parar de ser mau'
fonte
Obrigado. Pergunta: se o resultado da expansão não é uma palavra, por que as aspas são necessárias? Eles podem ser omitidos? Você está apenas aplicando seu conselho de "citar sempre, a menos que tenha um bom motivo para não fazer isso"? : p
rahmu
1
@rahmu As aspas são necessárias para evitar divisão e globbing em elementos individuais. Considere myarray=("hello world" wibble)(2 elementos, o primeiro dos quais contém um espaço): work_on_array "${myarray[@]}"passa 2 parâmetros hello worlde wibble; work_on_array ${myarray[@]}2 passa parâmetros hello, worlde wibble. E com myarray=(*), work_on_array ${myarray[@]}passa a lista de arquivos no diretório atual. (Portanto, este é um dos muitos casos em que meus conselhos fazem uma diferença prática.)
Gilles 'SO- stop be evil'
Corrija-me se eu estiver errado, mas eu acredito que há um erro de digitação no que você escreveu: a expansão unquoted passa 3 params, não 2.
rahmu
1
@rahmu Existem dois parâmetros: medo e surpresa ... e eficiência implacável. (Em outras palavras, você está certo, há um erro de digitação: hello, worlde wibblefazer 3 parâmetros.)
Gilles 'SO parada sendo mal'
4

Existe uma maneira no bash 4.3+, que provavelmente vem do ksh:

echo_idx_array () # array index
{
    local -n array=$1     # add nameref attribute
    local idx=$2
    echo "${array[idx]}"
}

$ names=(one two three four)
$ echo_idx_array names 2
three
$ days=([monday]=eggs [tuesday]=bread [sunday]=jam)    # associative array
$ echo_idx_array days sunday
jam

Veja também declare -n.

Edouard Thiel
fonte
Huh, interessante. Sim, isso veio do ksh e funciona no mksh sem modificação.
mirabilos
1

Depende do Korn Shell ... As versões recentes da AT&T ksh93 e mksh suportam isso:

function echo_idx_array {
    nameref arr=$1
    idx=$2

    echo "${arr[idx]}"
}

set -A test -- a b c
echo_idx_array test 1

No meu shell atual, isso gera "b".

mirabilos
fonte