Включить библиотеку функций в awk

Есть много общих функций (особенно арифметика / математика), которые не встроены в awk что мне нужно писать самому все время.

Например:

  1. Здесь нет c=min(a,b) так что в awk я постоянно пишу c=a<b?a:b
  2. то же самое для максимума т.е. c=max(a,b)
  3. то же самое для абсолютного значения, т.е. c=abs(a) поэтому я должен постоянно писать c=a>0?a:-a
  4. и так далее....

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

Я изучил функциональность "@include" в GNU gawk, но он просто выполняет все, что есть во включенном скрипте - т.е. я не могу вызывать функции.

Я надеялся написать некоторые функции, например, в mylib.awk, а затем "включить" это всякий раз, когда я звоню awk,

Я попробовал -f mylib.awk возможность awk, но скрипт выполняется - функции в нем не могут быть вызваны.

6 ответов

Решение

С GNU awk:

$ ls lib
prims.awk

$ cat lib/prims.awk
function abs(num) { return (num > 0 ? num : -num) }
function max(a,b) { return (a > b ? a : b) }
function min(a,b) { return (a < b ? a : b) }

$ export AWKPATH="$PWD/lib"

$ awk -i prims.awk 'BEGIN{print min(4,7), abs(-3)}'
4 3

$ cat tst.awk
@include "prims.awk"
BEGIN { print min(4,7), abs(-3) }

$ awk -f tst.awk
4 3

Вы можете иметь несколько -f program-file параметры, так что один может быть вашими общими функциями, а другой может быть конкретной задачей решения сценария awk, который будет иметь доступ к этим функциям.

awk -f common-funcs.awk -f specific.awk file-to-process.txt

Я не знаю, если это то, что вы искали, но это лучшее, что я придумал. Вот пример:

$ cat common_func.awk
# Remove spaces from front and back of string
function trim(s) {
  gsub(/^[ \t]+/, "", s);
  gsub(/[ \t]+$/, "", s);
  return s;
}

$ cat specific.awk
{ print $1, $2 }
{ print trim($1), trim($2) }

$ cat file-to-process.txt 
abc    |    def   |

2$ awk -F\| -f common_func.awk -f specific.awk file-to-process.txt 
abc         def   
abc def

С обычным awk (не GNU) вы не можете смешивать -f program-file вариант со встроенной программой. То есть следующее не будет работать:

awk -f common_func.awk '{ print trim($1) }' file-to-process.txt # WRONG 

Однако, как указано в комментариях, с gawk вы можете использовать -f вариант вместе с -e:

awk -f file.awk -e '{stuff}' file.txt

В случае, если вы не можете использовать -i (если твой awk < 4.1 версия), которую предложил ЭдМортон, попробуйте ниже работы с GNU Awk 3.1.7

- исходная программа-текст

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

$ awk --version
GNU Awk 3.1.7
Copyright (C) 1989, 1991-2009 Free Software Foundation.

$ cat primes.awk 
function abs(num) { return (num > 0 ? num : -num) }
function max(a,b) { return (a > b ? a : b) }
function min(a,b) { return (a < b ? a : b) }

$ awk -f primes.awk --source 'BEGIN{print min(4,7), abs(-3)}'
4 3

В обычном awk (не gnu) вы все еще можете немного подделать, используя оболочку, используя cat файла (ов) в "код" (обычно впереди, но может быть везде, так как он уважает порядок работы awk)

> cat /tmp/delme.awk
   function PrintIt( a) { printf( "#%s\n", a )}

> echo "aze\nqsd" | awk "$( cat /tmp/delme.awk)"'{ sub( /./, ""); PrintIt( $0 )}'
#ze
#sd

С GNU awk вы можете использовать параметр командной строки -i или внутри сценария директиву @include, но если вам нужно решение POSIX, тогда awk -f functions.awk -f script.awk file.txt - это то, как вам нужно идти.

Это был 2015 год. Сегодня существует cppawk , сочетающий в себе препроцессор C и Awk. Это дает вам#includeмеханизм, который:

  • Работает в сочетании с несколькими реализациями Awk.
  • Позволяет получить предварительно обработанный вывод, чтобы получить одну программу Awk, которая работает в системах без препроцессора C.
  • Не требуетAWKPATHпеременная, чтобы узнать, где находятся включаемые файлы. Еслиpath/to/foo.awkсодержит#include "bar.awk", он будет искатьpath/to/bar.awkдля действительно простого объединения файлов библиотеки.

cppawk теперь упоминается в руководстве GNU Awk.

Конкретные функции, упомянутые в вопросе, можно записать в виде макросов:

      cppawk '
#define max(a, b) ((a) > (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? -(a) : (a))

... your code here
'

Но только если ты чувствуешь себя храбрым. Они имеют недостатки скрытой множественной оценки. Например,max(a[i++], n)приводит к неопределенному поведению (в Awk оно есть!) иmax(fun1(), fun2())вызовет функцию дважды.

Мне не известна реализация встроенных функций на Awk, поэтому это может ускорить код.

Однако ни одна известная мне реализация Awk не выполняет CSE (исключение общего подвыражения), поэтому, если макросы вызывают двойной вызов дорогостоящих функций, это может замедлить работу кода.

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