Bash fournit-il un support pour l'utilisation des pointeurs?

12

Question simple. Le shell bash prend-il en charge l'utilisation de pointeurs lors de l'écriture d'un script shell?

Je suis familier avec la notation d'expansion, ${var[@]}lors de l'itération sur le tableau $var, mais il n'est pas clair que cela utilise des pointeurs pour itérer sur les indices du tableau. Bash donne-t-il accès à des adresses mémoire comme les autres langues?

Si bash ne prend pas en charge l'utilisation de pointeurs, que font les autres shells?

111 ---
la source

Réponses:

28

Un pointeur (vers un emplacement de mémoire ) n'est pas vraiment un concept utile dans quelque chose de plus élevé que C, que ce soit quelque chose comme Python ou le shell. Les références aux objets sont bien sûr utiles dans les langages de haut niveau, peut-être même nécessaires pour construire des structures de données complexes. Mais dans la plupart des cas, penser en termes d'adresses mémoire est un niveau trop bas pour être très utile.

Dans Bash (et autres shells), vous pouvez obtenir les valeurs des éléments du tableau avec la ${array[index]}notation, les affecter avec array[index]=...et obtenir le nombre d'éléments du tableau avec ${#array[@]}. L'expression entre crochets est une expression arithmétique. Par exemple, nous pourrions ajouter un préfixe constant à tous les membres du tableau:

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

(Si nous nous soucions uniquement des valeurs, et non des index, ce for x in "${array[@]}" ; do...serait bien.)

Avec des tableaux associatifs ou clairsemés , une boucle numérique n'a pas beaucoup de sens, mais à la place nous aurions besoin de récupérer les clés / index du tableau avec ${!array[@]}. Par exemple

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

En plus de cela, Bash a deux façons de pointer indirectement vers une autre variable:

  • expansion indirecte , en utilisant la ${!var}syntaxe , qui utilise la valeur de la variable dont le nom est var, et
  • namerefs , qui doivent être créés avec la commande declareintégrée (ou le kshsynonyme compatible typeset). declare -n ref=varfait refréférence à la variable var.

Namerefs indexation également un soutien, en ce que si nous avons arr=(a b c); declare -n ref=arr;alors ${ref[1]}sera étendu à b. À la ${!p[1]}place, l'utilisation prendrait la pforme d'un tableau et ferait référence à la variable nommée par son deuxième élément.

Dans Bash, les namerefs sont littéralement que, les références par nom et l'utilisation d'un nameref à l'intérieur d'une fonction utiliseront la valeur locale de la variable nommée. Cela s'imprimera local value of var.

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

BashFAQ a également un article plus long sur l'indirection .

ilkkachu
la source
2
l'indirection est très utile dans les langues de niveau supérieur. par exemple des références en perl. Ils ne sont pas les mêmes que les pointeurs C mais ils remplissent la même fonction de base. Même bash peut accéder indirectement aux variables ... mais IMO si vous commencez à écrire du code qui fait un usage significatif de la fonctionnalité, vous feriez mieux de recommencer à zéro avec perl ou quelque chose. Voir aussi mywiki.wooledge.org/BashFAQ/006
cas
2
@cas, oh, absolument. Mais il vaut probablement mieux les considérer comme pointant vers des objets plutôt que vers des adresses de mémoire. (Même en C, il y a un type impliqué.) Je voulais noter à la fois l'expansion indirecte et les noms, mais je n'ai pas eu le temps de le faire immédiatement.
ilkkachu
Il vaut probablement la peine de souligner que l'exemple for-loop est plus naturellement écrit, for foo in "${array[@]}" ; do ... donesauf si vous avez besoin de l'index à d'autres fins.
Will Crawford
@ WillCrawford, point. édité l'exemple et noté.
ilkkachu
9

Non, bashn'a pas de "pointeurs", mais il a des références:

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

Depuis la bashpage de manuel:

Une variable peut se voir attribuer l'attribut nameref à l'aide de l'option -n des commandes declareou localintégrées pour créer un nameref ou une référence à une autre variable. Cela permet aux variables d'être manipulées indirectement. Chaque fois que la variable nameref est référencée, affectée à, non définie ou que ses attributs sont modifiés (autres que l'utilisation ou la modification de l'attribut nameref lui-même), l'opération est réellement effectuée sur la variable spécifiée par la valeur de la variable nameref. Un nameref est couramment utilisé dans les fonctions shell pour faire référence à une variable dont le nom est passé en argument à la fonction. Par exemple, si un nom de variable est transmis à une fonction shell comme premier argument, l'exécution

declare -n ref=$1

à l'intérieur de la fonction crée une référence nameref variable dont la valeur est le nom de variable passé comme premier argument. Les références et les affectations à ref, ainsi que les modifications apportées à ses attributs, sont traitées comme des références, des affectations et des modifications d'attribut à la variable dont le nom a été transmis comme $ 1. Si la variable de contrôle dans une boucle for possède l'attribut nameref, la liste de mots peut être une liste de variables shell, et une référence de nom sera établie pour chaque mot de la liste, à son tour, lorsque la boucle est exécutée. Les variables de tableau ne peuvent pas recevoir l'attribut nameref. Cependant, les variables nameref peuvent référencer des variables de tableau et des variables de tableau en indice. Les noms de références peuvent être non définis à l'aide de l'option -n du unsetmodule intégré. Sinon, siunset est exécuté avec le nom d'une variable nameref comme argument, la variable référencée par la variable nameref ne sera pas définie.

hackerb9
la source
4

Non, les shells n'utilisent pas de "pointeurs" (comme compris en C).

Les tableaux peuvent utiliser des indices: echo "${array[2]}"mais @dans votre exemple, ce n'est pas vraiment un "pointeur". C'est un moyen d'exprimer "la liste des valeurs du tableau". Quelque chose que l'analyseur de shell comprend. Similaire à la façon dont a:

$ echo "$@"

s'étend à toute la liste des "Paramètres positionnels".

NotAnUnixNazi
la source
2

Alors que les tableaux indexés en entier bash peuvent être définis et accessibles de manière itérative comme ceci;

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

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

Les tableaux indexés associatifs ou basés sur des chaînes dans bash nécessitent la définition itérative suivante;

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

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

Pour répondre à la question concernant les pointeurs et en utiliser un de bash; la fonctionnalité interne du binaire bash compilé utilise en effet des pointeurs vers la mémoire allouée sur la pile et expose des fonctionnalités similaires avec l'utilisation de eval. Voir [références indirectes] http://tldp.org/LDP/abs/html/ivr.html )

Il y a des dragons; l'utilisation de evaldoit être utilisée avec prudence en raison des implications en matière de sécurité

jas-
la source