Gawk: passer des tableaux à des fonctions

9

Coincé avec GNU awk 3.1.6 et pense que j'ai contourné ses bogues de tableau, mais j'ai toujours ce qui ressemble à un problème de portée dans un programme awk de 600 lignes. Besoin de vérifier la compréhension de la portée du tableau dans awk pour trouver mon bogue.

Étant donné ce code awk illustratif ...

function foo(ga) {
  ga[1] = "global result"
}

garray[1] = "global"
foo(garray)

print garray[1]

imprimera ...

global result

Étant donné que les tableaux sont toujours passés aux fonctions par référence, tous les tableaux sont toujours globaux. Il n'y a aucun moyen de créer un tableau local. Est-ce correct? N'ont pas pu trouver de documents qui le disent explicitement.

Depuis que je débogue et que la 3.1.6 elle-même a connu des bogues dans ce domaine, j'essaie de déterminer où les bogues d'Awk s'arrêtent et où commence le mien.

Supplémentaire: Pourquoi alors ga [] fonctionne-t-il à l'intérieur de la fonction?

Tout d'abord, passer le tableau à la fonction avec foo(ga)n'est en fait pas nécessaire. Accédez-y simplement comme garray[]dans la fonction. Cependant, il n'y a pas de pénalité de performance mesurable et cela aide au débogage et au rapport d'erreurs.

En utilisant foo(ga), ga[]est un synonyme du tableau global garray[]. Au lieu d'être une copie locale de garray[], il s'agit simplement d'un pointeur vers garray[], un peu comme un lien symbolique est un pointeur vers un fichier et donc le même fichier (ou tableau) est accessible sous plusieurs noms.

Supplémentaire: clarification de la réponse de Glenn Jackman

Alors que les tableaux créés à l' extérieur d' une fonction sont globaux pour la fonction et peuvent lui être transmis ou simplement référencés à l'intérieur, les tableaux créés à l' intérieur d' une fonction restent en effet locaux à la fonction et ne sont pas visibles à l'extérieur. Modifier l'exemple de M. Jackman illustre cela ...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: 

Notez que nous transmettons uniquement le x[]tableau (en fait, juste un pointeur vers celui-ci) à bar(). Le y[]tableau n'existe même pas jusqu'à ce que nous entrions dans la fonction.

Cependant, si nous déclarons y[]en l'incluant dans la bar()liste des arguments sans lui assigner quoi que ce soit en dehors de la fonction, il devient visible après l'appel bar(x,y)...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello

Enfin, si nous créons le y[]tableau en dehors de la fonction et le transmettons avec bar(x,y), l' split()affectation à l'intérieur de la fonction remplace les éléments de ce tableau ...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      y[1]="howdy"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: howdy
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello
DocSalvager
la source

Réponses:

5

Les paramètres de fonction sont locaux à la fonction.

awk '
    function foo(x,y) {y=x*x; print "y in function: "y} 
    BEGIN {foo(2); print "y out of function: " y}
'
y in function: 4
y out of function: 

Si vous passez moins de valeurs à une fonction qu'il n'y a de paramètres, les paramètres supplémentaires sont simplement vides. Vous pouvez parfois voir des fonctions définies comme

function foo(a, b, c            d, e, f) {...

où les paramètres après l'espace sont des variables locales et ne sont pas destinés à prendre une valeur lors de l'appel.

Aucune raison pour laquelle cela ne peut pas fonctionner pour les baies locales:

awk '
    function bar(x) {
        split("hello world", x)
        print "in: " x[1]
    }
    BEGIN {
        x[1]="world"
        bar()
        print "out: " x[1]}
'
in: hello
out: world
glenn jackman
la source
3

La documentation de Gawk indique clairement que les tableaux sont transmis par référence, et il n'y a aucun moyen documenté de contourner cela. Le comportement est le même avec gawk4.0.1.

POSIX spécifie ce comportement , donc je ne m'attends pas à ce que vous trouviez une awkimplémentation qui se comporte autrement.

Si vous avez besoin de cette fonctionnalité, vous pouvez l'utiliser perl. perlest livré avec un outil ( a2p) pour traduire les awkscripts en perl.

Stéphane Chazelas
la source