Повторення awk {n} не працює


18

Я намагаюся надрукувати рядки, використовуючи символ повторення {n}, але це не працює. Для. наприклад, я хочу надрукувати всі рядки, довжина яких становить 4 знаки

 awk '/^.{4}$/' test_data

Вищеописаний код - це не друк. Як виправити його, щоб я міг використовувати символ повторення? Я знаю таку альтернативу, як awk '/^....$/' test_dataіawk 'length ==3 ' test_data


3
Який дистрибутив ви використовуєте? Який буд?
terdon

1
$ awk --version GNU Awk 3.1.7 $ cat / etc / redhat-release Red Hat Enterprise Linux випуск сервера 6.7 (Сантьяго)
Forever Learner

2
Я б сказав, awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' щоб відповідати рівно 4 знакам. Також, як ви вже згадували, awk 'length($0) == 4' test_dataсумісний практично з усіма awkверсіями.
Валентин Байрамі

4
Робити awk --re-interval '/^.{4}$/' test_data чи awk --posix '/^.{4}$/' test_dataпрацювати?
steeldriver

Дякую, що ви керуєте. Це вирішило моє питання. Отримано. Ще раз дякую :)
Назавжди учень

Відповіді:


19

Відповідно до Посібника користувача GNU Awk: Історія функцій , версія версії 3.0 регулярної експресії була додана у версії 3.0, але спочатку потрібна явна опція командного рядка

Нові параметри командного рядка:

  • Нові параметри командного рядка:
    • Параметр --int-old попереджає про конструкції, недоступні в оригінальній версії Unik версії 7 (див. V7 / SVR3.1).
    • Варіант -m від BWK awk. (Брайан в той час ще був у лабораторіях Белла.) Це згодом було усунуто як з його дивовижних, так і з гаук-подій.
    • Параметр --re-interval для надання інтервальних виразів у регулярних виразах (див. Оператори Regexp).
    • - традиційний варіант був доданий як краща назва --compat (див. Параметри).

У gawk4.0,

Інтервальні вирази стали частиною регулярних виразів за замовчуванням

Оскільки ви використовуєте gawk3.x, вам потрібно буде скористатися

awk --re-interval '/^.{4}$/'

або

awk --posix '/^.{4}$/'

або (спасибі @ StéphaneChazelas), якщо ви хочете, щоб рішення було портативним, використовуйте

POSIXLY_CORRECT=anything awk '/^.{4}$/'

(Так --posixчи --re-intervalвикличе помилку в інших awkреалізаціях).


Дякуємо steeldriver, за ваш час та допомогу. Затверджено та прийнято як відповідь
Forever Learner

4
Краще використовувати, POSIXLY_CORRECT=anything awk '/^.{4}/'як це робить переносний код (a --posixабо --re-intervalспричинить помилку в інших awkреалізаціях).
Стефан Шазелас

Вітаю, Стефане Шазела, коли я видав команду, $ POSIXLY_CORRECT = нічого страшного / /. Тоді я зрозумів, що немає останніх доларів після повторень. Дякуємо за ваші вклади. Оголошення вашого коментаря та рішення. Вибачте, я неправильно зрозумів це в першу чергу через пропущення $ після повторення.
Forever Learner

20

ERE ( розширені регулярні вирази , що використовуються awkабо egrep) спочатку не мали {x,y}. Спочатку він був введений в BRE (як використовується grepабо sed), але з \{x,y\}синтаксисом, який не порушив зворотну портативність.

Але коли його додали до ERE з цим {x,y}синтаксисом, він порушив зворотну портативність як afoo{2} RE раніше відповідав чомусь іншому.

Тож деякі реалізації вирішили цього не робити. Ви знайдете це /bin/awk, /bin/nawkі /bin/egrepна Solaris все ще не шануєте це (потрібно використовувати /usr/xpg4/bin/awkабо /usr/xpg4/bin/grep -E). Те ж саме для awkі nawkна FreeBSD ( на основі підтримується Брайан Керниган (далі в )).awkkawk

Для GNUawk до недавнього часу (версія 4.0) вам доводилося закликати його, POSIXLY_CORRECT=anything awk '/^.{4}$/'щоб він його вшанував. mawkвсе ще не шанує цього .

Зауважте, що цим оператором є лише синтаксичний цукор. .{3,5}завжди можна писати, ....?.?наприклад (хоча, звичайно {3,5}, набагато більш розбірливим, а еквівалент (foo.{5,9}bar){123,456}був би набагато гіршим).


Ще раз дякую Стефану Шазеласу. Вибачте, мій поганий, я не зміг зрозуміти вашу відповідь спочатку. Велике спасибі і прихильне.
Forever Learner

6

Це працює, як очікувалося з GNU awk(gawk):

$ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/'
abcd

Але невдача, mawkяка ближче до POSIX awkі, AFAIK, є типовою для систем Ubuntu:

$ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/'
$ ## prints nothing

Отже, простим рішенням буде використовувати gawkзамість цього awk. {n}Позначення не є частиною синтаксису POSIX BRE (базове регулярний вираз). Ось чому grepтут також не вдається:

$ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$'
$

Однак він є частиною ERE (розширені регулярні вирази):

$ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$'
abcd

Я не знаю, який аромат регексу використовується mawkабо POSIXawk , але я б припустив, що це BRE. Вони використовують старішу версію ERE відповідно до відповіді Стефана . У будь-якому випадку, або ви, мабуть, використовуєте версію awk, яка не реалізує ERE, або на вашому введенні фактично немає рядків із точно 4 символами. Це може статися через пробіл, який ви не бачите, або скасовуєте, наприклад, гліфи.


Привіт тердоне, я хочу надрукувати рядки довжиною 4 символи. Не перші чотири символи рядка. Наприклад, $ grep -E '^. {4} $' test_data, буде працювати, але те ж саме не працює з awk
Forever Learner

@CppLearner так, саме тут я і роблю. Що ви маєте на увазі?
terdon

@CppLearner, рішення @ terdon виконує лише друковані лінії довжиною 4 символи. Але якщо вас дійсно цікавить лише довжина рядка, вам слід просто скористатись тим, length($0)який є більш ефективним, ніж регулярні вирази.
Стівен Кітт

Привіт тердон, рішення стильдера - це те, що я шукав. Дякую за ваш час. Привіт Стівен Кітт. Як я вже згадував у цій проблемі, я вже використовував довжину як альтернативу, мені було цікавіше знати, чому повторний повтор {n} не працює з коментаря steeldriver. Я дізнався, що мені потрібно використовувати параметр --re-інтервал або --posix. Дякую за ваш час.
Назавжди учень

1
mawkнасправді не ближче до POSIX awk, і не використовує BRE. Він використовує ERE, але без {x,y}оператора.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.