Gawk: передача массивов в функции


9

Застрял в GNU awk 3.1.6 и думаю, что я обошел его ошибки массива, но все еще имеет то, что похоже на проблему с областью действия в 600-строчной программе awk. Нужно проверить понимание области действия массива в awk, чтобы найти мою ошибку.

Учитывая этот иллюстративный код awk ...

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

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

print garray[1]

напечатает ...

global result

Поскольку массивы всегда передаются функциям по ссылке, то все массивы всегда являются глобальными. Нет способа создать локальный массив. Это правильно? Не удалось найти документы, которые прямо говорят об этом.

Так как я отлаживаюсь, а сама версия 3.1.6 знает ошибки в этой области, я пытаюсь определить, где ошибки awk исчезают, и начинаются мои.

Дополнение: Почему тогда ga [] работает внутри функции?

Прежде всего, передача массива в функцию с помощью foo(ga)фактически не требуется . Просто получите доступ к нему как garray[]внутри функции. Тем не менее, в этом нет никакого измеримого снижения производительности, и это помогает в отладке и сообщении об ошибках.

В использовании foo(ga), ga[]является синонимом для глобального массива garray[]. Вместо того, чтобы быть локальной копией garray[], это просто указатель на garray[], а символическая ссылка - это указатель на файл и, следовательно, один и тот же файл (или массив) может быть доступен под более чем одним именем.

Дополнение: разъяснение ответа Гленна Джекмана

В то время как массивы, созданные вне функции, являются глобальными для функции и могут быть переданы ей или просто упомянуты внутри нее, массивы, созданные внутри функции, действительно остаются локальными для функции и не видны вне ее. Изменение примера мистера Джекмана иллюстрирует это ...

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: 

Обратите внимание, что мы только передаем x[]массив (фактически, просто указатель на него) bar(). y[]Массив даже не существует , пока мы не получим внутри функции.

Однако, если мы объявим y[], включив его в bar()список аргументов, не назначая ему ничего вне функции, оно станет видимым после вызова 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

Наконец, если мы создадим y[]массив вне функции и передадим его bar(x,y), split()присваивание внутри функции заменяет элементы этого массива ...

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

Ответы:


5

Параметры функции являются локальными для функции.

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: 

Если вы передаете в функцию меньше значений, чем параметров, дополнительные параметры будут просто пустыми. Иногда вы можете увидеть функции, определенные как

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

где параметры после пробела являются локальными переменными и не предназначены для принятия значения при вызове.

Нет причин, почему это не может работать для локальных массивов:

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

3

Документация gawk проясняет, что массивы передаются по ссылке, и нет задокументированного способа обойти это. Поведение то же самое с gawk4.0.1.

POSIX определяет это поведение , поэтому я не ожидаю, что вы найдете какую-либо awkреализацию, которая ведет себя иначе.

Если вам нужна эта функциональность, вы можете использовать perl. perlпоставляется с инструментом ( a2p) для перевода awkскриптов в perl.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.