2013-08-23 3 views
16

Сегодня я искал команду онлайн для печати следующих двух строк после шаблона, и я наткнулся на команду awk, которую я не смог понять.Объясните команду awk

$ /usr/xpg4/bin/awk '_&&_--;/PATTERN/{_=2}' input 

Может кто-нибудь объяснить это?

ответ

2

Чудесно неясно. Будет обновляться, когда позволяет время.

_ используется как имя переменной. && является логическим оператором, который имеет 2 действительных действия, выполняемых вместе. После того, как значение _ сведено к нулю, вторая половина & & является ложной и никакой выход не генерируется.

print -- " 
xxxxx 
yyyy 
PATTERN 
zzz 
aa 
bbb 
ccc 
ddd" | awk '_&&_--;/PATTERN/{_=2}' 

выход

zzz 
aa 

отладки версия

print -- " 
xxxxx 
yyyy 
PATTERN 
zzz 
aa 
bbb 
ccc 
ddd" | awk '_&&_--;{print "_="_;print _&&_};/PATTERN/{_=2;print "_="_ }' 

выход

_= 
0 
_= 
0 
_= 
0 
_= 
0 
_=2 
zzz 
_=1 
1 
aa 
_=0 
0 
_=0 
0 
_=0 
0 
_=0 
0 
7

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

Число линий указано в блоке {_=2}, а для переменной _ установлено значение 2, если линия соответствует PATTERN. Каждая строка, прочитанная после соответствующей строки, приводит к уменьшению числа _. Вы можете читать _&&_--, как если бы _ больше нуля, а затем минус один из них, это происходит для каждой строки после матча, пока _ не достигнет нуля. Это довольно просто, когда вы заменяете переменную _ более разумным именем, например n.

Простой демо должны четко (печать 2 строки, которые следуют за любую линию, соответствующую foo):

$ cat file 
foo 
1 
2 
3 
foo 
a 
b 
c 

$ awk 'n && n--;/foo/{n=2}' file 
1 
2 
a 
b 

Так n верно только, когда он получает значение 2 после согласования линии с foo затем его уменьшается n и печатает текущую строку. Благодаря awk, имеющей оценку короткого замыкания n только декремент, когда n верно (п> 0) так что единственные возможные значения в этом случае для n являются 2,1 или 0.

Awk имеет следующую структуру и condition{block} когда условие оценивается True, тогда для текущей записи выполняется блок. Если вы не предоставляете блок awk, то используется блок {print $0} по умолчанию, поэтому n && n--; - это условие без блока, которое оценивает только True для n строк после соответствия регулярного выражения. Полуколона просто ограничивает условие n&&n-- для условий /foo/, чтобы было ясно, что условие не имеет блока.

Для печати две строки ниже матч, включая матч вы могли бы сделать:

$ awk '/foo/{n=3} n && n--' file 
foo 
1 
2 
foo 
a 
b 

Extra дополнительно: тот факт, что полный путь /usr/xpg4/bin/awk используется говорит мне этот код предназначен для Solaris поскольку /usr/bin/awk полностью сломан, и его следует избегать любой ценой.

+2

Очень хорошее объяснение – CBR

11

_ здесь используется как переменное здесь (действительное, но явно запутанное). Если вы перепишите его как:

awk 'x && x--; /PATTERN/ { x=2 }' input 

тогда немного легче разобрать. Всякий раз, когда сопоставляется /PATTERN/, переменная получает значение 2 (и эта строка не выводится) - это вторая половина. Первая часть срабатывает, когда x не равен нулю и уменьшает x, а также печатает текущую строку (действие по умолчанию, так как в этом предложении не указано действие).

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

2

Объяснение

awk выражения имеют следующий вид:

condition action; NEXT_EXPRESSION 

Если Conditon верно действие (s) будет выполняться. Обратите внимание, что если условие истинно, но действие было опущено, awk выполнит print (действие по умолчанию).

У вас есть два выражения в вашем коде, которые будут выполнены на каждой строке ввода:

_&&_--   ; 
/PATTERN/{_=2} 

Оба разделенных ;. Как я уже говорил, что действие по умолчанию print произойдет, если действие опущено это же, как:

_&&_-- {print}; 
/PATTERN/ {_=2} 

В вашем примере _ имя переменной, которая инициализируется с помощью 0 на первой строке ввода, до его первого использования - автоматически с помощью awk.

Первое условие будет (0) && (0) .. Что приводит к тому, что условие является ложным, так как 0 && 0 оценивает до false и awk не печатает.

Если шаблон найден, _ будет установлен в 2, что делает первое условие будучи (2) && (2) на следующей строке и (1) && (1) на следующей строке после того, как линия _ уменьшается после того, как условие оценивается. Оба оценивают до true, и awk напечатает эти строки.

Однако, хорошая головоломка;)

+0

Небольшая ошибка, пост-декремент имеет более высокий порядок или приоритет, чем логический И так явно '(0) && (0 -)' as '(0 && 0) -' оценивается -1. –

+0

приятно знать .. позвольте мне улучшить сообщение таким образом. – hek2mgl

+0

@sudo_O 'awk '_ &&_--; 1 {printf"% i \ n ", _};/Pattern/{_ = 2}' input.txt' Я не понимаю вывод строки выше. Если декремент имеет место до (то, что соответствует awk docs, вы правы), тогда правая сторона '&&' должна быть 1 в первом тесте и 0 во втором тесте после соответствия шаблона. Поэтому я ожидаю, что будет напечатана только одна строка. Что мне здесь не хватает? – hek2mgl

36

См https://stackoverflow.com/a/17914105/1745001 ответ, который был дублирован здесь.

+2

какая коллекция! +1 – iruvar

+2

ничего себе! Команда awk - действительно золотая жила. – CBR

+2

+1 Хорошо заслуженная щедрость! –

Смежные вопросы