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


9

Застряг у GNU awk 3.1.6 і думаю, що я працював над його помилками масиву, але все ще маю те, що схоже на проблему з масштабом у програмі awk у 600 рядків. Щоб знайти мою помилку, потрібно перевірити розуміння області масиву.

З огляду на цей ілюстративний код awk ...

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

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

print garray[1]

буде надруковано ...

global result

Оскільки масиви завжди передаються функціям за посиланням, то всі масиви завжди є глобальними. Немає можливості створити локальний масив. Це правильно? Не змогли знайти документи, які прямо говорять про це.

Оскільки я налагоджую, і 3.1.6 сама знає про помилки в цій області, я намагаюся визначити, де помиляються помилки awk і починаються мої.

Доповнення: Чому тоді га [] працює всередині функції?

Перш за все, передача масиву у функцію за допомогою 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.