Могу ли я передать массив в 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
Другие вопросы по тегам