Могу ли я передать массив в awk, используя -v?
Я хотел бы иметь возможность передать переменную массива awk
, Я не имею в виду массив оболочки, но родной awk
один. Я знаю, что могу передать скалярные переменные следующим образом:
awk -vfoo="1" 'NR==foo' file
Могу ли я использовать тот же механизм для определения awk
массив? Что-то вроде:
$ awk -v"foo[0]=1" 'NR==foo' file
awk: fatal: `foo[0]' is not a legal variable name
Я попробовал несколько вариантов выше, но ни один из них не работает на GNU awk 4.1.1 на моем Debian. Итак, есть ли версия awk
(gawk
,mawk
или что-нибудь еще), который может принять массив из -v
выключатель?
Я знаю, что могу обойти это и легко думать о способах сделать это, мне просто интересно, если таковые имеются awk
Реализация поддерживает этот вид функциональности изначально.
5 ответов
Похоже, это невозможно по определению.
От man awk
у нас есть это:
-v var = val
--assign var = val
Присвойте значение val переменной var до начала выполнения программы. Такие значения переменных доступны для правила BEGIN программы AWK.
Затем мы читаем в разделе Использование переменных в программе:
Имя переменной должно быть последовательностью букв, цифр или символов подчеркивания, и оно не может начинаться с цифры.
Переменным в awk могут быть присвоены либо числовые, либо строковые значения.
Так как -v
Определенная реализация делает невозможным предоставление массива в качестве переменной, так как любой вид использования символов =
или же [
не допускается как часть -v
переменная передача. И оба требуются, так как массивы в awk
только ассоциативны.
Вы можете использовать функцию split() внутри mawk или gawk, чтобы разделить ввод значения "-v" (вот страница man gawk):
split(s, a [, r [, seps] ])
Разбейте строку s на массив a и разделитель массива пересекается с регулярным выражением r и возвращает количество полей.*
Пример здесь, в котором я передаю значение "ARRAYVAR", разделенный запятыми список значений, который является моим массивом, с "-v" программе awk, а затем разделяю его на массив внутренних переменных "arrayval", используя split() функции, а затем выведите 3-е значение массива:
echo 0 | gawk -v ARRAYVAR="a,b,c,d,e,f" '{ split(ARRAYVAR,arrayval,","); print(arrayval[3]) }'
c
Кажется, работает:)
Если вы не настаиваете на использовании
-v
вы могли бы использовать
-i
(include), чтобы прочитать файл awk, содержащий настройки переменных. Как это:
if F=$(mktemp inputXXXXXX); then
cat >$F << 'END'
BEGIN {
foo[0]=1
}
END
cat $F
awk -i $F 'BEGIN { print foo[0] }' </dev/null
rm $F
fi
Пример трассировки (с использованием gawk-4.2.1):
bash -x /tmp/test.sh
++ mktemp inputXXXXXX
+ F=inputrpMsan
+ cat
+ cat inputrpMsan
BEGIN {
foo[0]=1
}
+ awk -i inputrpMsan 'BEGIN { print foo[0] }'
1
+ rm inputrpMsan
К сожалению, это невозможно. Однако вы можете преобразовать массив bash в массив awk, используя несколько умных методов.
Недавно я хотел сделать это, передав массив bash в awk, чтобы использовать его для фильтрации, поэтому вот что я сделал:
$ arr=( hello world this is bash array )
$ echo -e 'this\nmight\nnot\nshow\nup' | awk 'BEGIN {
for (i = 1; i < ARGC; i++) {
my_filter[ARGV[i]]=1
ARGV[i]="" # unset ARGV[i] otherwise awk might try to read it as a file
}
} !my_filter[$0]' "${arr[@]}"
Выход:
might
not
show
up
Для ассоциативных массивов вы можете передать его как строку пар ключ-значение, а затем переформатировать ее в разделе НАЧАЛО.
$ echo | awk -v m="a,b;c,d" '
BEGIN {
split(m,M,";")
for (i in M) {
split(M[i],MM,",")
MA[MM[1]]=MM[2]
}
}
{
for (a in MA) {
printf("MA[%s]=%s\n",a, MA[a])
}
}'
Выход:
MA[a]=b
MA[c]=d