выражение awk, которое работает на awk v4.0.2, но не на> = 4.2.1 - PullRequest
1 голос
/ 23 марта 2020

У меня есть эта команда awk:

echo www.host.com |awk -F. '{$1="";OFS="." ; print $0}' | sed 's/^.//'

, которая получает домен от имени хоста:

host.com

, эта команда работает на CentOS 7 (awk v 4.0 .2), но он не работает ни в ubuntu 19.04 (awk 4.2.1), ни в alpine (gawk 5.0.1), вывод:

host com

Как я могу исправить это выражение awk, чтобы оно работало в последних версиях awk?

Ответы [ 4 ]

5 голосов
/ 23 марта 2020

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

echo www.host.com | awk 'match($0,/\..*/){print substr($0,RSTART+1,RLENGTH-1)}'


Исправление кода OP: В случае, если OP хочет использовать собственный пробный код, может помочь следующее. Здесь есть два момента: 1-й - нам не нужно использовать никакую другую команду вместе с awk для обработки. 2-й - нам нужно установить значения FS и OFS в секции BEGIN, которые вы делаете в каждой строке.

echo www.host.com | awk 'BEGIN{FS=OFS="."} {$1="";sub(/\./,"");print}'
4 голосов
/ 23 марта 2020

Чтобы получить домен, используйте:

$ echo www.host.com | awk 'BEGIN{FS=OFS="."}{print $(NF-1),$NF}'
host.com

Объяснено:

awk '
BEGIN {                 # before processing the data
    FS=OFS="."          # set input and output delimiters to .
}
{
    print $(NF-1),$NF   # then print the next-to-last and last fields
}'

Это также работает, если у вас произвольно длинные fqdns:

$ echo if.you.have.arbitrarily.long.fqdns.example.com |
awk 'BEGIN{FS=OFS="."}{print $(NF-1),$NF}'
example.com

И да, забавно, ваша версия действительно работает с 4.0.2. И awk версия 20121220.

Обновление:

Обновлено с некоторыми функциями проверки содержимого, см. Комментарии. Есть ли домены, которые go выше трех уровней?:

$ echo and.with.peculiar.fqdns.like.co.uk | 
awk '
BEGIN {
    FS=OFS="."
    pecs["co\034uk"]
}
{
    print (($(NF-1),$NF) in pecs?$(NF-2) OFS:"")$(NF-1),$NF
}'
like.co.uk
3 голосов
/ 23 марта 2020

Вы получили 2 очень хороших ответа на awk, но я считаю, что это должно быть обработано с cut из-за простоты, которую он предлагает для получения всех полей, начинающихся с известной позиции:

echo 'www.host.com' | cut -d. -f2-

host.com

Используются следующие параметры:

  • -d.: установить разделитель как .
  • -f2-: извлечь все поля, начиная с позиции 2
2 голосов
/ 23 марта 2020

То, что вы наблюдаете, было ошибкой в ​​GNU awk, которая была исправлена ​​в выпуске 4.2.1. В журнале изменений указано:

2014-08-12 Арнольд Д. Роббинс * Устанавливая OFS

следует перестроить $0 с использованием предыдущего OFS, если нужно перестроить $0. Спасибо Майку Бреннану за указание на это.

  • awk.h (rebuild_record): Объявить.
  • eval. c (set_OFS): Если не вызывается из var_init(), проверьте, нуждается ли $0 в восстановлении. Если это так, полностью проанализируйте запись и восстановите ее. Сделайте OFS указанием на отдельную копию нового OFS для следующего раза, так как OFS_node->var_value->stptr уже был обновлен на этом этапе.

  • поле. c (rebuild_record): Теперь внешний вместо stati c. Используйте OFS и OFSlen вместо значения OFS_node.

При чтении кода в OP указывается:

awk -F. '{$1="";OFS="." ; print $0}'

, который в соответствии с POSIX выполняет следующие действия:

  1. -F.: устанавливает разделитель поля FS для представления -характера
  2. прочитать запись
  3. Выполнить разбиение поля с помощью FS="."
  4. $1="": переопределить поле 1 и перестроить запись $0, используя OFS. В настоящее время OFS задается как один пробел. Если запись $0 была www.foo.com, то теперь она читается как _foo_com (подчеркивания обозначают пробелы). Пересчитайте количество полей, которые теперь являются только одним, поскольку больше нет FS.
  5. OFS=".": переопределите разделитель выходного поля OFS, чтобы он стал -персонаж. Это где ошибка происходит. Гну знал, что восстановление должно было произойти, но сделал это уже с новым OFS, а не со старым OFS.
  6. **print $0':** print the record $0 which is now _foo_com`.

Минимальное изменение в вашей программе будет:

awk -F. '{OFS="."; $1=""; print $0}'

Чистое изменение будет:

awk 'BEGIN{FS=OFS="."}{$1="";print $0}'

Идеальным изменением будет замена awk и sed cut решением Анубахува

Если у вас есть переменная с таким именем, вы можете использовать:

var=www.foo.com
echo ${var#*.}
...