2014-11-06 3 views
0

У меня длинный список строк, и я хочу выборочно печатать START + 3 строки выше, пока не включится END. Проблема в том, что длина между START и END является переменной, но я всегда хочу, чтобы три строки были выше начала.
Я попытался AWK:awk для печати 3 строки выше совпадения до второго совпадения

awk '/START/,/END/' file.txt 

Однако я не могу найти способ, как включить три строки выше START. Подсказка действительно оценена спасибо!

Входной

EFA 
DAD 
ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 
CDA 

Результат

ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 
+1

Появляются ли СТАРТ и КОНЕЦ более одного раза? Или только один раз? –

+0

... и если это так, вы хотите распечатать с первого START до последнего END или сначала начать сначала END или каждый START до END или что-то еще? –

ответ

1
awk '/START/ { if (a) print a; if (b) print b; if (c) print c; }\ 
    { a=b; b=c; c=$0; }\ 
    /START/,/END/' file.txt 

Объяснение

/START/{if(a)print a;if(b)print b;if(c)print c} белый en встречается строка, соответствующая /START/, распечатывает записи буфера, пропуская все пустые.

{a=b;b=c;c=$0} записи сдвига буфера, если требуется много больше, чем массив.

/START/,/END/ печать все записи между /START/ и /END/

1
#!awk -f 
{ 
    foo[NR] = $0 
} 
/START/ { 
    bar = NR - 3 
} 
/END/ { 
    while (bar++ <= NR) 
    print foo[bar] 
} 
0

Если START и END появляются только один раз, вы можете использовать grep с контекстом, как это:

grep -B 3 -A 99999 START file | grep -B 99999 END 

т.е. 3 линии before START и вверх до 99999 строк после, затем до 99999 строк до END.

1
awk '/START/{print x3"\n"x2"\n"x;p=1} 
    /END/{print;p=0} 
    {x3=x2} 
    {x2=x} 
    {x=$0}p' your_file 

Испытано:

> cat temp 
EFA 
DAD 
ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 
CDA 
> awk '/START/{print x3"\n"x2"\n"x;p=1}/END/{print;p=0}{x3=x2}{x2=x}{x=$0}p' temp 
ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 
> 
+0

+1 для 'p'! Это просто и элегантно! – TrueY

1

Похожая, но может быть проще для понимания вариации на ту же тему:

awk '/START/{for(i=1;i<4;++i)if(NR-i in a)print a[NR-i]}{a[NR]=$0;delete a[NR-3]}/START/,/END/' inputfile 

В середине он просто хранит последние три строки и падает, если есть четвертый. Если строка START найдена, она печатает три предыдущих строки (только если они существуют) и что-то между START и END.

Если START и END должно быть точным, то образец должен быть /^START$/ и /^END$/ или вместо сопоставления с образцом прямого сравнения строк следует использовать как $0=="START" во всех случаях.

входного файла:

GEF 
START 
EDG 
EFG 
GAD 
END 
CDA 
EFA 
DAD 
ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 
CDA 

Выход:

GEF 
START 
EDG 
EFG 
GAD 
END 
GEF 
DEF 
ABC 
START 
EDG 
EFG 
GAD 
END 
0

Использование ТАС

Должен работать, если несколько END/НАЧИНАЕТСЯ в файле

tac file | awk '/END/{x=4}y&&x{x--}/START/{y=x}x' | tac 
+0

Почему это было опущено ха-ха? Можете ли вы оставить комментарий в будущем, чтобы объяснить, пожалуйста :) –

1

Одним из возможных решений один возможная интерпретация ваших требований:

$ awk '{a[NR]=$0} /START/{s=NR} /END/{for (i=(s-3);i<=NR;i++) print a[i]}' file 
ABC 
DEF 
GEF 
START 
EDG 
EFG 
GAD 
END 

будет работать, если есть 1 или более START/END блоки, и вы не хотите, первый старт к последней END.

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