Bash fornisce supporto per l'utilizzo dei puntatori?


12

Domanda semplice. La shell bash ha qualche supporto per l'uso dei puntatori quando si scrive uno script di shell?

Ho familiarità con la notazione di espansione, ${var[@]}quando si scorre sull'array $var, ma non è chiaro che questo stia utilizzando i puntatori per iterare sugli indici dell'array. Bash fornisce accesso ad indirizzi di memoria come altre lingue?

Se bash non supporta l'uso dei puntatori, quali altre shell fanno?

Risposte:


28

Un puntatore (verso una posizione di memoria ) non è in realtà un concetto utile in qualcosa di livello superiore a C, sia esso qualcosa come Python o la shell. I riferimenti agli oggetti sono ovviamente utili in linguaggi di alto livello, forse persino necessari per costruire strutture di dati complesse. Ma nella maggior parte dei casi pensare in termini di indirizzi di memoria è un livello troppo basso per essere molto utile.

In Bash (e altre shell), è possibile ottenere i valori degli elementi dell'array con la ${array[index]}notazione, assegnarli con array[index]=...e ottenere il numero di elementi dell'array con ${#array[@]}. L'espressione tra parentesi è un'espressione aritmetica. Come esempio inventato, potremmo aggiungere un prefisso costante a tutti i membri dell'array:

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

(Se ci preoccupassimo solo dei valori e non degli indici, for x in "${array[@]}" ; do...andrebbe bene.)

Con array associativi o sparsi , un ciclo numerico non ha molto senso, ma invece dovremmo recuperare le chiavi / gli indici dell'array ${!array[@]}. Per esempio

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

Inoltre, Bash ha due modi per indirizzare indirettamente verso un'altra variabile:

  • espansione indiretta , utilizzando la ${!var}sintassi , che utilizza il valore della variabile il cui nome è in var, e
  • namerefs , che devono essere creati con il declarebuiltin (o il kshsinonimo compatibile typeset). declare -n ref=varfa refun riferimento alla variabile var.

Namerefs supporta anche l'indicizzazione, nel senso che se lo avremo arr=(a b c); declare -n ref=arr;poi ${ref[1]}si espanderà a b. Utilizzare ${!p[1]}invece prenderebbe pcome un array e fare riferimento alla variabile denominata dal suo secondo elemento.

In Bash, namerefs è letteralmente quello, i riferimenti per nome e l'uso di un nameref all'interno di una funzione utilizzerà il valore locale della variabile denominata. Questo stamperà local value of var.

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

BashFAQ ha anche un articolo più lungo sull'indirizzamento indiretto .


2
il riferimento indiretto è piuttosto utile nelle lingue di livello superiore. ad es. riferimenti in perl. Non sono uguali ai puntatori C ma svolgono la stessa funzione di base. Anche bash può accedere alle variabili indirettamente ... ma IMO se inizi a scrivere codice che fa un uso significativo della funzionalità, è meglio iniziare da zero con perl o qualcosa del genere. Vedi anche mywiki.wooledge.org/BashFAQ/006
cas

2
@cas, oh, assolutamente. Ma è probabilmente meglio pensarli come puntati a oggetti , piuttosto che a indirizzi di memoria. (Anche in C, c'è un tipo coinvolto.) Volevo notare sia l'espansione indiretta che le nameref, ma non ho avuto il tempo di farlo immediatamente.
ilkkachu,

Vale probabilmente la pena sottolineare che l'esempio for-loop è scritto in modo più naturale a for foo in "${array[@]}" ; do ... donemeno che non sia necessario l'indice per altri scopi.
Will Crawford,

@WillCrawford, punto. modificato l'esempio e notato.
ilkkachu,

9

No, bashnon ha "puntatori", ma ha riferimenti:

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

Dalla bashpagina man:

A una variabile può essere assegnato l'attributo nameref usando l'opzione -n ​​ai comandi declareo localbuiltin per creare un nameref o un riferimento a un'altra variabile. Ciò consente di manipolare le variabili indirettamente. Ogni volta che la variabile nameref viene referenziata, assegnata, non impostata o ha i suoi attributi modificati (oltre all'utilizzo o alla modifica dell'attributo nameref stesso), l'operazione viene effettivamente eseguita sulla variabile specificata dal valore della variabile nameref. Un nameref è comunemente usato all'interno delle funzioni della shell per fare riferimento a una variabile il cui nome viene passato come argomento alla funzione. Ad esempio, se un nome di variabile viene passato a una funzione shell come primo argomento, in esecuzione

declare -n ref=$1

all'interno della funzione crea una ref di nameref il cui valore è il nome della variabile passato come primo argomento. I riferimenti e le assegnazioni a ref e le modifiche ai relativi attributi vengono trattati come riferimenti, assegnazioni e modifiche agli attributi della variabile il cui nome è stato passato come $ 1. Se la variabile di controllo in un ciclo for ha l'attributo nameref, l'elenco di parole può essere un elenco di variabili shell e verrà stabilito un riferimento al nome per ogni parola nell'elenco, a sua volta, quando il ciclo viene eseguito. Non è possibile assegnare l'attributo nameref alle variabili di matrice. Tuttavia, le variabili nameref possono fare riferimento a variabili di array e variabili di array sottoscritte. Namerefs può essere disinserito usando l'opzione -n ​​nell'integrato unset. Altrimenti, seunset viene eseguito con il nome di una variabile nameref come argomento, la variabile a cui fa riferimento la variabile nameref non verrà impostata.


4

No, le shell non usano "puntatori" (come inteso in C).

Le matrici potrebbero usare gli indici: echo "${array[2]}"ma @nel tuo esempio non è proprio un "puntatore". È un modo per esprimere "l'elenco dei valori dell'array". Qualcosa che il parser di shell capisce. Simile al modo a:

$ echo "$@"

si espande in tutto l'elenco "Parametri posizionali".


2

Mentre gli array indicizzati integer bash possono essere definiti e accessibili in modo iterativo in questo modo;

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

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

Le matrici indicizzate associative o basate su stringhe in bash richiedono la seguente definizione iterativa;

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

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

Per rispondere alla domanda riguardante i puntatori e l'utilizzo di uno da bash; la funzionalità interna del binario bash compilato fa effettivamente uso di puntatori alla memoria allocata nello stack ed espone funzionalità simili con l'uso di eval. Vedi [riferimenti indiretti] http://tldp.org/LDP/abs/html/ivr.html )

Ci sono draghi; l'uso di evaldovrebbe essere usato con cautela a causa delle implicazioni di sicurezza

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.