Під час використання awk / pattern / {print “text”} / patern / {print “”} чи існує ELSE-шаблон?


22

Скажімо, у мене є текстовий файл на зразок:

R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

Я хочу використовувати awkдля обробки цих рядків інакше, як

awk '/R1/ { print "=>" $0} /R2/ { print "*" $0} '

і я хочу також надрукувати всі інші рядки такими, якими вони є (без створення дублікатів рядків, які я вже обробив), в основному мені потрібен /ELSE/ { print $0}кінець awkрядка.

Чи є таке?

Відповіді:


27

Спрощений підхід с awk

awk '/R1/ {print "=>" $0;next} /R2/{print "*" $0;next} 1' text.file

[jaypal:~/Temp] cat text.file 
R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

[jaypal:~/Temp] awk '/R1/ { print "=>" $0;next} /R2/{print "*" $0;next}1' text.file
=>R1 12 324 3453 36 457 4 7 8
*R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242
[jaypal:~/Temp] 

Розрив зразка {Action} Заяви:

  • /R1/ { print "=>" $0;next}: Це означає, що лінії, що мають /R1/дію друку, =>будуть виконані. nextозначає, що решта заяв awk буде проігноровано, і наступний рядок буде розглянуто.

  • /R2/{print "*" $0;next}: Це означає, що лінії, що відповідають pattern /R2/дії друку, *будуть виконані. Під час awkзапуску обробки перше pattern {action}твердження буде ігноруватися, оскільки pattern /R1/для рядків, що мають рядки, значення не відповідає дійсності /R2/. Тож друге pattern {action}твердження буде зроблено на лінії. nextце ще раз означатиме, що ми не хочемо більше обробки і awkналежним чином перейдемо до наступного рядка.

  • 1друкує всі рядки. Якщо просто умова надається, немає {action}, awk за замовчуванням використовувати {print}. Тут умова така, 1що трактується як справжня, тому вона завжди вдається. Якщо ми підійдемо до цього пункту, це тому, що перший та другий pattern {action}висловлювання були проігноровані або пропущені (для рядків, що не містять /R1/та /R2/), тому дія друку за замовчуванням буде зроблена для решти рядків.


Здається, незначно вибігаєте найшвидше з усіх розміщених рішень.
Кріс Даун

1
Я не впевнений, що синтаксичний цукор тут є правильним терміном ... Це просто синтаксис.
Данило Гершкович

7

awkреалізує звичайних підозрюваних, коли мова йде про умовні умови. Це гарна ідея використовувати printfзамість printроботи, яку ви хочете виконувати на матчі.

awk '{ if (/^R1/) { printf("=> %s\n", $0) } else if (/^R2/) { printf("* %s\n", $0) } else { print $0 } }'

Вам це не дуже потрібно if-then-else.
jaypal singh

1
Хоча це працює чудово, але це не ідіоматично. Розумне використання next- важливий інструмент у програмі awk.
dmckee

2
Я не розумію сенсу використання printfтут. Єдиною його перевагою (якщо ви не займаєтесь форматним форматуванням, ніж конкатенацією), є те, що він не додає новий рядок, що тут не доречно.
Жил "ТАК - перестань бути злим"

1
Це контрінтуїтивний та дивовижний результат. Необхідно виводити printлише невстановлене, $0тоді як printfмає аналізувати рядок формату.
jw013

5

Кріс Даун вже показав, як можна отримати інше для регулярних виразів, скориставшись явним твердженням "якщо" в блоці. Можна отримати такий же ефект і іншими способами, хоча його рішення, мабуть, краще.

Одне полягає в тому, щоб написати третій регулярний вираз, який буде відповідати лише тексту, який не відповідає іншим; у вашому випадку це виглядатиме приблизно так:

awk '/^R1/ { print "=>" $0}
     /^R2/ { print "*" $0}
     /^[^R]/ || /^R[^12]/ { print $0 } '

Зауважте, для цього використовується прив’язаний регулярний вираз - ^ на початку регулярних виразів збігатиметься лише на початку рядка - ваші оригінальні шаблони цього не робили, що трохи сповільнює збіг, оскільки він перевірятиме всі символи в рядку, а не пропускаючи до наступного рядка. Третій (інший) випадок буде відповідати рядку, який починається з символу, який не є 'R' ([^ R]) або який починається з 'R', а потім символом, який не є '1' або ' 2 '(R [^ 12]). Два різних значення ^ дещо заплутані, але ця помилка була зроблена давно і не буде змінена найближчим часом.

Для використання додаткових регулярних виразів їх дійсно потрібно закріпити, оскільки в іншому випадку [^ R] відповідатиме, наприклад, 1, що йде за ним. Для таких простих регулярних виразів, як у вас, такий підхід може бути корисним, але, оскільки регулярні виразки стануть складнішими, такий підхід стане некерованим. Натомість ви можете використовувати змінні стану для кожного рядка, наприклад:

awk '{ handled = 0 }
     /^R1/ { print "=>" $0; handled = 1}
     /^R2/ { print "*" $0; handled = 1}
     { if (!handled) print $0 } '

Це встановлює обробку в нуль для кожного нового рядка, потім до 1, якщо він відповідає жодному з двох повторних виразів, і, нарешті, якщо він ще дорівнює нулю, виконує друк $ 0.


Слід зазначити, що для великих файлів обидва є менш ефективними, ніж використання умовних умов (як показано тут ). rfileце лише 10000 рядків набору даних запитувача, повторених.
Кріс Даун

4
if (!handled)Гидота! Використовуйте nextдля припинення розгляду інших дій.
dmckee

+1 для if (!handled). Загальні, гнучкі, багаторазові рішення - це добре. Що робити, якщо наступна особа, яка має це питання, захоче більше обробити після друку? Відповіді nextне підтримують цього.
Скотт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.