O bash fornece suporte para o uso de ponteiros?

11

pergunta simples. O bash shell tem algum suporte para usar ponteiros ao escrever um script de shell?

Estou familiarizado com a notação de expansão, ${var[@]} ao iterar sobre a matriz $var , mas não está claro se isso está utilizando ponteiros para iterar sobre os índices da matriz. O bash fornece acesso a endereços de memória como outros idiomas?

Se o bash não suporta o uso de ponteiros, o que outros shells fazem?

    
por datUser 28.12.2017 / 15:10

4 respostas

23

Um ponteiro (para uma localização de memória ) não é realmente um conceito útil em algo de nível superior a C, seja algo como Python ou o shell. Referências a objetos são naturalmente úteis em linguagens de alto nível, talvez até necessárias para a construção de estruturas de dados complexas. Mas na maioria dos casos, pensar em termos de endereços de memória é muito baixo para ser muito útil.

No Bash (e outros shells), você pode obter os valores dos elementos do array com a notação ${array[index]} , atribuí-los com array[index]=... e obter o número de elementos no array com ${#array[@]} . A expressão dentro dos colchetes é uma expressão aritmética. Como exemplo inventado, poderíamos adicionar um prefixo constante a todos os membros da matriz:

for ((i=0 ; i < ${#array[@]} ; i++ )) ; do
    array[i]="foo-${array[i]}"
done

(Se nos importássemos apenas com os valores, e não com os índices, apenas for x in "${array[@]}" ; do... estaria bem.)

Com associativo ou matrizes esparsas , um loop numérico não faz muito sentido, mas em vez disso, precisamos buscar as chaves / índices da matriz com ${!array[@]} . Por exemplo,

declare -A assoc=([foo]="123" [bar]="456")
for i in "${!assoc[@]}" ; do 
    echo "${assoc[$i]}"
done 

Além disso, o Bash tem duas maneiras de apontar indiretamente para outra variável:

  • expansão indireta , usando a sintaxe ${!var} , que usa o valor da variável cujo nome está em var e
  • namerefs , que precisam ser criados com o declare builtin (ou o sinônimo ksh -compatível, typeset ). declare -n ref=var torna ref uma referência à variável var .

Namerefs também suporta indexação, em que se tivermos arr=(a b c); declare -n ref=arr; , então ${ref[1]} será expandido para b . Usar ${!p[1]} , em vez disso, usaria p como uma matriz e referir-se à variável nomeada por seu segundo elemento.

No Bash, namerefs são literalmente que, referências por nome , e usando um nameref de dentro de uma função, usarão o valor local da variável nomeada. Isto irá imprimir local value of var .

#!/bin/bash
fun() {
        local var="local value of var"
        echo "$ref";
}
var="global var"
declare -n ref=var
fun

O BashFAQ também tem um artigo mais extenso sobre a indireção .

    
por 28.12.2017 / 15:49
8

Não, bash não tem "ponteiros", mas tem referências:

$ spam="fred"
$ declare -n tripe=spam
$ echo $tripe
fred
$ tripe=juki
$ echo $spam
juki

Na página bash man:

A variable can be assigned the nameref attribute using the -n option to the declare or local builtin commands to create a nameref, or a reference to another variable. This allows variables to be manipulated indirectly. Whenever the nameref variable is referenced, assigned to, unset, or has its attributes modified (other than using or changing the nameref attribute itself), the operation is actually performed on the variable specified by the nameref variable's value. A nameref is commonly used within shell functions to refer to a variable whose name is passed as an argument to the function. For instance, if a variable name is passed to a shell function as its first argument, running

declare -n ref=$1

inside the function creates a nameref variable ref whose value is the variable name passed as the first argument. References and assignments to ref, and changes to its attributes, are treated as references, assignments, and attribute modifications to the variable whose name was passed as $1. If the control variable in a for loop has the nameref attribute, the list of words can be a list of shell variables, and a name reference will be established for each word in the list, in turn, when the loop is executed. Array variables cannot be given the nameref attribute. However, nameref variables can reference array variables and subscripted array variables. Namerefs can be unset using the -n option to the unset builtin. Otherwise, if unset is executed with the name of a nameref variable as an argument, the variable referenced by the nameref variable will be unset.

    
por 28.12.2017 / 18:07
4

Não, shells não usam "ponteiros" (como entendido em C).

Os arrays podem usar índices: echo "${array[2]}" , mas o @ em seu exemplo não é realmente um "ponteiro". É uma maneira de expressar "a lista de valores de matriz". Algo que o analisador de shell entende. Similar à maneira como:

$ echo "$@"

expande para toda a lista "Parâmetros posicionais".

    
por 28.12.2017 / 15:19
2

Enquanto matrizes indexadas inteiras bash podem ser definidas & acessado iterativamente assim;

declare -a obj
obj+=("val1")
obj+=("val2")

for item in ${obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

Matrizes indexadas baseadas em string ou associativas no bash exigem a seguinte definição iterativa;

declare -A obj
obj["key1"]="val1"
obj["key2"]="val2"

for item in ${!obj[@]}; do
  echo "${obj[${item}]} ${item}"
done

Para responder à pergunta sobre ponteiros e usando um do bash; a funcionalidade interna do binário bash compilado de fato faz uso de ponteiros para memória alocada na pilha e expõe funcionalidade semelhante com o uso de eval . Veja [referências indiretas] link )

Haver dragões; o uso de eval deve ser usado com cautela devido a implicações de segurança

    
por 28.12.2017 / 16:29

Tags