Похоже, что параметры функций в массиве 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?
Спасибо за совет, но я считаю, что объяснение проблемы и предоставление кода, который у меня есть, проясняет ситуацию и также показывает, что я провел некоторое исследование.
Этот вопрос спрашивает, как передать переменные числа аргументов в функцию или почему параметры функции в массиве SYMTAB выглядят иначе, чем если бы вы проверяли их напрямую? Думал последнее, а может и нет. Если первое, то это дубликат stackoverflow.com/q/65032256/1745001.
Спасибо за ваши комментарии Эд. Мой главный вопрос был о SYMTAB, и, вероятно, поэтому я не нашел (или даже не искал) другой вопрос, на который вы ссылаетесь. markp-fuso ответил ниже по обоим пунктам. Я использую awk/gawk более 20 лет для работы, но я только сейчас перехожу от простых однострочников или коротких скриптов к использованию gawk для создания прототипа личного проекта с более чем 3000 строк, что заставило меня копать гораздо глубже в возможности gawk и недостатки ...
Мне кажется (мне), что вопрос 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 вы используете? Это может быть ошибка.
Спасибо @markp-fuso, я не думал использовать здесь split таким образом, хотя я уже регулярно использую его именно для этого. А также спасибо за дополнительные тесты на SYMTAB и за комментарий Эда, который указывает на руководство по глобальным переменным. Больше всего меня беспокоила проблема с SYMTAB, так как эта функция помогала поддерживать согласованность моей библиотеки функций массива, и я хотел понять, почему поведение SYMTAB кажется непоследовательным. Я использую gawk 5.1.
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 вы хотите найти.
Это хорошее замечание относительно области действия и того, на какую переменную будет ссылаться SYMTAB["p1"]. Спасибо обоим за помощь. Кроме того, не могли бы вы указать мне сайт, где я могу загрузить последнюю версию gawk для Windows. Я пытался найти один, и все, что я мог найти, это либо устаревшие версии, либо дистрибутивы с нескомпилированным исходным кодом GNU.
@EdMorton fwiw, я получаю аналогичные сообщения об ошибках при запуске кода OP под cygwin/gawk 5.2.1, но никаких ошибок не генерируется (и на самом деле я получаю тот же результат, что и код OP) при запуске под ubuntu/gawk 5.1.0; на данный момент я списываю это на что-то не так с компиляцией cygwin/gawk
Я действительно думаю, что это просто старая обычная ошибка в gawk 5.1.0 (или, может быть, лучше охарактеризовать ее как улучшение в gawk 5.2?), поскольку попытка доступа к несуществующей записи в SYMTAB[] должна сообщать об ошибке.
@cjnwl не уверен, что вы подразумеваете под windows version of gawk ... cygwin, похоже, имеет последнюю версию gawk (5.2.1-2 при последней проверке); если Linux работает под Windows (WSL?), я ожидаю, что соответствующий дистрибутив (например, Ubuntu) будет иметь актуальную версию; если вы используете какой-то другой софт (мкс?), пожимайте плечами....
Я ищу исполняемый установочный файл Windows (gawk.exe + связанные библиотеки, папки и т. д.), а не linux или cygwin. Я не могу вспомнить, откуда я загрузил 5.1, и я не могу найти сайт для загрузки чего-либо более нового, чем 4.1.6...
На самом деле Cygwin кажется тем, что я ищу, но я все еще не могу найти, где скачать что-либо, кроме файла .zst, тогда как я знаю, что в прошлом для предыдущих выпусков (v4.x, v5.0, 5.1 ) Мне удалось найти установочный файл Windows
Re: cygwin ... не могу ответить на комментарий *zst; cygwin больше похож на установщик пакетов; основной сайт ; вы скачиваете exe; запустите *exe, следуйте инструкциям, выберите из различных пакетов, которые вы хотите установить (например, оболочки, двоичные файлы и т. д.); периодически перезапускайте *exe для проверки наличия новых/обновленных пакетов и/или для установки пакета, который вы решили использовать.
Я хотел сказать, что *exe - это установщик пакета... запускайте его каждый раз, когда хотите установить/обновить пакет в среде cygwin.
@ для всех : это вовсе не ошибка. В журнале изменений 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
Пожалуйста, сократите свой код до минимального (но все же полного) примера, которого достаточно, чтобы продемонстрировать проблему, с которой вы обращаетесь за помощью, чтобы нам было легче вам помочь. Вы должны быть в состоянии написать функцию длиной, возможно, в 2 строки, и вызвать ее из BEGIN, чтобы общая длина сценария составила, может быть, 5 строк, чтобы иметь возможность продемонстрировать Function parameters seem to be typed differently in the SYMTAB array than if you check them directly.