При использовании 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] 

Breakout of Pattern {Действие} Заявления:

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

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

  • 1печатает все строки. Если для условия указано no {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.
Джайпал Сингх

1
Хотя это работает на отлично, это не идиоматично. Разумное использование nextявляется важным инструментом в программировании на awk.
dmckee

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

1
Это противоречивый и удивительный результат. Unadorned должен printтолько выводить, $0тогда как printfдолжен анализировать строку формата.
jw013

5

Крис Даун уже показал, как можно получить другое выражение для регулярных выражений, используя явный оператор if в блоке. Вы также можете получить тот же эффект в некоторых других отношениях, хотя его решение, вероятно, лучше.

Одним из них является написание третьего регулярного выражения, которое будет соответствовать только тексту, который не соответствует другим, в вашем случае это будет выглядеть примерно так:

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

Обратите внимание, что здесь используются привязанные регулярные выражения - символ ^ в начале регулярного выражения будет совпадать только в начале строки - ваши исходные шаблоны этого не делали, что немного замедляет сопоставление, так как будет проверять все символы в строке, а не пропуская до следующей строки. Третий случай («else») будет соответствовать строке, которая начинается с некоторого символа, который не является «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.