Gawk: Локальные переменные в SYMTAB имеют другой тип

Похоже, что параметры функций в массиве SYMTAB вводятся иначе, чем если бы вы проверяли их напрямую. то есть typeof(p) не всегда равно typeof(SYMTAB["p"])

Я пытаюсь написать общую функцию для инициализации одномерного массива с переменным количеством элементов. Эта проблема специфична для gawk, так как он использует массив SYMTAB, которого нет в стандартном awk.

Например:

array_new(array1, 1, 2, "c", 4, "e")
array_new(array2, 99, 98, 97)

function array_new(arr, p1, p2, p3, p4, p5, p6) {
   # initialization code
}

Gawk не допускает необязательных параметров, поэтому я установил разумный верхний предел — 6 для приведенного выше примера, но на практике я использовал 20 — а затем внутри функции я хочу создавать только элементы, для которых было задано значение. данный. Первый подход «грубой силы», который я пробовал и который работает, выглядит следующим образом:

function array_new(arr, p1, p2, p3, p4, p5, p6) {
    delete arr
    if (typeof(p1)  != "untyped") arr[1] = p1
    if (typeof(p2)  != "untyped") arr[2] = p2
    if (typeof(p3)  != "untyped") arr[3] = p3
    if (typeof(p4)  != "untyped") arr[4] = p4
    if (typeof(p5)  != "untyped") arr[5] = p5
    if (typeof(p6)  != "untyped") arr[6] = p6
    return
}

Но чем больше параметров я хочу разрешить, тем громоздче это становится, поэтому я хотел перебрать параметры и выйти, как только встретится неинициализированный.

Итак, я попробовал следующее, но это не сработало:

function array_new_2(arr, p1, p2, p3, p4, p5, p6, n) {
    for (n=1; n<=6; n++) {
        if (typeof(SYMTAB["p"n]) != "untyped") arr[n] = SYMTAB["p"n]
        else break
    }
    return
}

Пытаясь понять, почему я провел некоторые тесты, и оказалось, что typeof(p...) является "строкой", "числом" или "нетипизированным" в зависимости от того, что передается в функцию, или нет, а typeof(SYMTAB[ "p"n]) всегда "не назначено".

Это мой полный код, с некоторыми добавленными операторами отладки "print", чтобы увидеть, что происходит:

END {
    array_new_1(aaa, 3, 2, 1)
    array_walk(aaa, "aaa")
    print ""

    array_new_2(bbb, "a", "b", "c")
    array_walk(bbb, "bbb")
    print ""
}

function array_walk(arr, name,     i) {
    for (i in arr) {
        if (isarray(arr[i]))
            array_walk(arr[i], (name "[" i "]"))
        else
            printf("%s[%s] = '%s'\n", name, i, arr[i]) 
    }
}

function array_new_1(arr, p1, p2, p3, p4, p5, p6) {
    print "p1           : " typeof(p1), p1
    print "p6           : " typeof(p6), p6
    print "SYMTAB[\"p1\"] : " typeof(SYMTAB["p1"]), SYMTAB["p1"]
    print "SYMTAB[\"p6\"] : " typeof(SYMTAB["p6"]), SYMTAB["p6"]   # this creates an "unassigned" value
    if (typeof(p1)  != "untyped") arr[1] = p1
    if (typeof(p2)  != "untyped") arr[2] = p2
    if (typeof(p3)  != "untyped") arr[3] = p3
    if (typeof(p4)  != "untyped") arr[4] = p4
    if (typeof(p5)  != "untyped") arr[5] = p5
    if (typeof(p6)  != "untyped") arr[6] = p6
    return
}

function array_new_2(arr, p1, p2, p3, p4, p5, p6, n) {
    print "p1           : " typeof(p1), p1
    print "p6           : " typeof(p6), p6
    print "SYMTAB[\"p1\"] : " typeof(SYMTAB["p1"]), SYMTAB["p1"]
    print "SYMTAB[\"p6\"] : " typeof(SYMTAB["p6"]), SYMTAB["p1"]
    for (n=1; n<=6; n++) {
        if (typeof(SYMTAB["p"n]) == "unassigned") arr[n] = SYMTAB["p"n]
        else break
    }
    return
}

Это производит следующий вывод:

p1           : number 3
p6           : untyped 
SYMTAB["p1"] : unassigned 
SYMTAB["p6"] : unassigned 
aaa[1] = '3'
aaa[2] = '2'
aaa[3] = '1'
aaa[6] = ''

p1           : string a
p6           : untyped 
SYMTAB["p1"] : unassigned 
SYMTAB["p6"] : unassigned 
bbb[1] = ''
bbb[2] = ''
bbb[3] = ''
bbb[4] = ''
bbb[5] = ''
bbb[6] = ''

Итак, подведем итог: может ли кто-нибудь объяснить, почему версии параметров SYMTAB типизированы иначе, чем сами переменные, а также, есть ли лучший способ написать мою функцию array_new?

Пожалуйста, сократите свой код до минимального (но все же полного) примера, которого достаточно, чтобы продемонстрировать проблему, с которой вы обращаетесь за помощью, чтобы нам было легче вам помочь. Вы должны быть в состоянии написать функцию длиной, возможно, в 2 строки, и вызвать ее из BEGIN, чтобы общая длина сценария составила, может быть, 5 строк, чтобы иметь возможность продемонстрировать Function parameters seem to be typed differently in the SYMTAB array than if you check them directly.

Ed Morton 16.02.2023 17:15

Спасибо за совет, но я считаю, что объяснение проблемы и предоставление кода, который у меня есть, проясняет ситуацию и также показывает, что я провел некоторое исследование.

cjnwl 16.02.2023 17:21

Этот вопрос спрашивает, как передать переменные числа аргументов в функцию или почему параметры функции в массиве SYMTAB выглядят иначе, чем если бы вы проверяли их напрямую? Думал последнее, а может и нет. Если первое, то это дубликат stackoverflow.com/q/65032256/1745001.

Ed Morton 16.02.2023 17:37

Спасибо за ваши комментарии Эд. Мой главный вопрос был о SYMTAB, и, вероятно, поэтому я не нашел (или даже не искал) другой вопрос, на который вы ссылаетесь. markp-fuso ответил ниже по обоим пунктам. Я использую awk/gawk более 20 лет для работы, но я только сейчас перехожу от простых однострочников или коротких скриптов к использованию gawk для создания прототипа личного проекта с более чем 3000 строк, что заставило меня копать гораздо глубже в возможности gawk и недостатки ...

cjnwl 17.02.2023 10:16
Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел &quot;Заголовок&quot; в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
2
4
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне кажется (мне), что вопрос SYMTAB[]/typing - это отвлечение от основной проблемы выяснения того, как (эффективно) предоставить переменное количество входных параметров функции awk. [ПРИМЕЧАНИЕ: это похоже на проблему с желанием передать переменное количество значений в командной строке с помощью нескольких предложений -v var=val.]

Одним из распространенных обходных путей является объединение (переменного) списка значений в одну строку с разделителями, а затем код split() этой строки с разделителями в массив значений переменной длины.

Применяя это к случаю ОП:

array_new(array1, "1,2,c,4,e")             # concatenate the list of values into a comma-delimited string

function array_new{arr, plist) { 
   n=split(plist,p,",") ...                # split the comma-delimited string into an array named p[], with "n" elements in the array
   for (i=1;i<=n;i++) {                    # loop through the indices of the p[] array (1 to n)
       # do something with p[i]
   }
}

Если единственной целью функции OP является заполнение массива, мы можем использовать входной параметр (arr) в качестве цели вызова split(), например:

function array_new(arr, plist) {
    split(plist,arr,",")
}

Запуск некоторых тестов:

array_new(array1, "1,2,c,4,e")
print "########### array1"
for (i=1;i<=length(array1);i++)
    print "array1[" i "] = " array1[i]

array_new(array2, "99,98,97")
print "########### array2"
for (i=1;i<=length(array2);i++)
    print "array2[" i "] = " array2[i]

Это генерирует:

########### array1
array1[1] = 1
array1[2] = 2
array1[3] = c
array1[4] = 4
array1[5] = e
########### array2
array2[1] = 99
array2[2] = 98
array2[3] = 97

ПРИМЕЧАНИЕ. В этом примере кода я использовал запятую в качестве разделителя; если данные могут включать запятые, то OP (очевидно) нужно будет переключиться на другой разделитель (который не отображается в данных)


С другой стороны, если функция OP нужна только для заполнения массива, на самом деле нет необходимости в определяемой пользователем функции, которая служила бы оболочкой для предоставленной awk функции.

Другими словами, все это:

array_new(array1, "1,2,c,4,e")
array_new(array2, "99,98,97")


function array_new(arr, plist) {
    split(plist,arr,",")
}

Можно заменить на это:

split("1,2,c,4,e", array1, ",")
split("99,98,97",  array2, ",")
Ответ принят как подходящий

Глядя исключительно на проблему SYMTAB[] ...

Похоже, что SYMTAB[] не знает о «локальных» параметрах, определенных в списке параметров функции, если они также не указаны в теле функции, но даже тогда кажется, что SYMTAB[<param>] не содержит значение параметра.

Рассмотрим следующее:

awk '
function array_new_2(arr, p1, p2, p3, p4, p5, p6, n) {

    print "p1",p1,SYMTAB["p1"],typeof(SYMTAB["p1"])
    print "p6",p6,SYMTAB["p6"],typeof(SYMTAB["p1"])
    print "XX",XX,SYMTAB["XX"],typeof(SYMTAB["XX"])

    print "############# pX in SYMTAB ?"

    for (i=1;i<=6;i++)
        print "p"i ("p"i in SYMTAB ? "" : " not") " in SYMTAB[]; SYMTAB[p"i"] = " SYMTAB["p"i]

    print "############# for loop:"

    for (i in SYMTAB)
        if (isarray(SYMTAB[i]) )
           print i,"[ array ]"
        else
           print i,SYMTAB[i]

    print "#############"

    arr[1]=p1
}

BEGIN {
    OFS = ","
    array_new_2(arrX,1,2,3)    # provide values for p1/p2/p3
}
'

Это генерирует:

p1,1,,unassigned                   # SYMTAB["p1"] is empty/undefined
p6,,,unassigned                    # no value supplied for p6, SYMTAB["p6"] is empty/undefined
XX,,,unassigned                    # undefined variable "XX"

############# pX in SYMTAB ?
p1 in SYMTAB[]; SYMTAB[p1]=        # in SYMTAB[] because referenced in body of function, but value not in SYMTAB[] !!
p2 not in SYMTAB[]; SYMTAB[p2]=    # value provided but not in SYMTAB[] !!
p3 not in SYMTAB[]; SYMTAB[p3]=    # value provided but not in SYMTAB[] !!
p4 not in SYMTAB[]; SYMTAB[p4]=
p5 not in SYMTAB[]; SYMTAB[p5]=
p6 in SYMTAB[]; SYMTAB[p6]=        # no value provided but in SYMTAB[] because referenced in body of function

############# for loop:
ARGV,[ array ]
i,i
ROUNDMODE,N
ORS,

OFS,,
LINT,0
FNR,0
ERRNO,
NR,0
IGNORECASE,0
p1,                                # referenced in body of function; SYMTAB[] is empty/undefined
TEXTDOMAIN,messages
NF,0
ARGIND,0
arrX,[ array ]                     # without "arr[1]=p1" the variable "arrX" is treated as a scalar and SYMTAB["arrX"] is empty/undefined
XX,
ARGC,1
PROCINFO,[ array ]
FIELDWIDTHS,
CONVFMT,%.6g
SUBSEP,
PREC,53
ENVIRON,[ array ]
RS,

FPAT,[^[:space:]]+
p6,                                # referenced in body of function; SYMTAB[] is empty/undefined
RT,
RLENGTH,0
OFMT,%.6g
FS, 
RSTART,0
FILENAME,
BINMODE,0
#############

ПРИМЕЧАНИЯ:

  • p1 (=1) и p6 (пусто/не определено) отображаются в выводе цикла for, потому что на них есть ссылки в теле функции.
  • p2 (= 2) и p3 (= 3) имеют значения, предоставленные вызовом функции, но они никогда не упоминаются в теле функции, так что они не отображаются в выводе цикла for
  • p4(пустой/неопределенный) и p5(пустой/неопределенный) никогда не упоминаются в теле функции тааак, они также не отображаются в выводе цикла for

Из этого небольшого теста видно:

  • SYMTAB[] нельзя использовать для определения того, были ли входные параметры функции предоставлены значениями
  • SYMTAB[] нельзя использовать для доступа к фактическим значениям, переданным в вызове функции

Как говорится в руководстве, «массив, индексы которого являются именами всех определенных глобальных переменных и массивов в программе», и аргументы функций не являются ни тем, ни другим. Я удивлен, что вы не получаете семантической ошибки при поиске SYMTAB с помощью p1. Какую версию gawk вы используете? Это может быть ошибка.

Ed Morton 17.02.2023 01:25

Спасибо @markp-fuso, я не думал использовать здесь split таким образом, хотя я уже регулярно использую его именно для этого. А также спасибо за дополнительные тесты на SYMTAB и за комментарий Эда, который указывает на руководство по глобальным переменным. Больше всего меня беспокоила проблема с SYMTAB, так как эта функция помогала поддерживать согласованность моей библиотеки функций массива, и я хотел понять, почему поведение SYMTAB кажется непоследовательным. Я использую gawk 5.1.

cjnwl 17.02.2023 10:10

FWIW, когда я запускаю этот скрипт в gawk 5.2.1, я получаю awk: cmd. line:4: fatal: reference to uninitialized element `SYMTAB["p1"] is not allowed', поэтому, если вы можете в 5.1, это звучит как ошибка. Одна из причин, которая не может быть разрешена, заключается в том, что если бы также была глобальная переменная с именем p1 и вам было бы разрешено искать SYMTAB как по локальным, так и по глобальным переменным, то не было бы способа найти глобальную переменную. p1 в SYMTAB внутри функции, поскольку глобальное значение будет маскироваться локальным, и нет возможности определить, какое p1 вы хотите найти.

Ed Morton 17.02.2023 12:59

Это хорошее замечание относительно области действия и того, на какую переменную будет ссылаться SYMTAB["p1"]. Спасибо обоим за помощь. Кроме того, не могли бы вы указать мне сайт, где я могу загрузить последнюю версию gawk для Windows. Я пытался найти один, и все, что я мог найти, это либо устаревшие версии, либо дистрибутивы с нескомпилированным исходным кодом GNU.

cjnwl 17.02.2023 15:04

@EdMorton fwiw, я получаю аналогичные сообщения об ошибках при запуске кода OP под cygwin/gawk 5.2.1, но никаких ошибок не генерируется (и на самом деле я получаю тот же результат, что и код OP) при запуске под ubuntu/gawk 5.1.0; на данный момент я списываю это на что-то не так с компиляцией cygwin/gawk

markp-fuso 17.02.2023 16:13

Я действительно думаю, что это просто старая обычная ошибка в gawk 5.1.0 (или, может быть, лучше охарактеризовать ее как улучшение в gawk 5.2?), поскольку попытка доступа к несуществующей записи в SYMTAB[] должна сообщать об ошибке.

Ed Morton 17.02.2023 16:16

@cjnwl не уверен, что вы подразумеваете под windows version of gawk ... cygwin, похоже, имеет последнюю версию gawk (5.2.1-2 при последней проверке); если Linux работает под Windows (WSL?), я ожидаю, что соответствующий дистрибутив (например, Ubuntu) будет иметь актуальную версию; если вы используете какой-то другой софт (мкс?), пожимайте плечами....

markp-fuso 17.02.2023 18:33

Я ищу исполняемый установочный файл Windows (gawk.exe + связанные библиотеки, папки и т. д.), а не linux или cygwin. Я не могу вспомнить, откуда я загрузил 5.1, и я не могу найти сайт для загрузки чего-либо более нового, чем 4.1.6...

cjnwl 20.02.2023 17:13

На самом деле Cygwin кажется тем, что я ищу, но я все еще не могу найти, где скачать что-либо, кроме файла .zst, тогда как я знаю, что в прошлом для предыдущих выпусков (v4.x, v5.0, 5.1 ) Мне удалось найти установочный файл Windows

cjnwl 20.02.2023 17:29

Re: cygwin ... не могу ответить на комментарий *zst; cygwin больше похож на установщик пакетов; основной сайт ; вы скачиваете exe; запустите *exe, следуйте инструкциям, выберите из различных пакетов, которые вы хотите установить (например, оболочки, двоичные файлы и т. д.); периодически перезапускайте *exe для проверки наличия новых/обновленных пакетов и/или для установки пакета, который вы решили использовать.

markp-fuso 20.02.2023 17:36

Я хотел сказать, что *exe - это установщик пакета... запускайте его каждый раз, когда хотите установить/обновить пакет в среде cygwin.

markp-fuso 20.02.2023 17:52

@ для всех : это вовсе не ошибка. В журнале изменений gawk есть 4 записи с подробным описанием последних изменений Арнольда в SYMTAB : (это строки #s) ::::::::: 305 Disallow SYMTAB["x"]["y"].:::::::::: 485 PROCINFO["identifiers"] is like SYMTAB and FUNCTAB. This makes ::::::: :: 579 FUNCTAB and SYMTAB to create new elements. Thanks to :::::::::: 1030 Disallow SYMTAB and FUNCTAB as destination arguments to builtin

RARE Kpop Manifesto 22.02.2023 07:10

Другие вопросы по теме