2013-10-08 2 views
1

У меня есть файл, который выглядит следующим образом:BASH - Выборочное удаление

Guest-List 1 
All present 
Guest-list 2 
All present 
Guest-List 3 
Guest-list 4 
All present 
Guest-list 5 

Я хочу, чтобы удалить строку, содержащую «Все присутствующие» и его название (линия чуть выше «Все присутствующие»). Желательным результатом будет:

Guest-List 3 
Guest-list 5 

Я заинтересован в реализации этого с использованием sed. Потому что я новичок, другие возможные решения без sed также будут оценены (при ответе, пожалуйста, предоставьте подробное объяснение, чтобы я мог узнать):)

(Я знаю, что может удалить строку, соответствующую регулярному выражению, и может сохранить строку над ним, отправляя его в буфер удержания, что-то вроде этого: sed '/^.*present$/d; h' ... тогда команда «g» копирует буфер удержания обратно в пространство шаблона ... но как могу ли я сказать sed, чтобы удалить это?)

Заранее благодарен!

+0

Я попытался добавить верхнюю строку, сказав «Привет», но кажется, что ее удалили. Мои извинения. – DMS

+0

Каждый раз, когда вы общаетесь с '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' s ' Вся эта глупость была необходима, когда 'sed' был впервые изобретен как потоковая версия' ed', но устарел, когда 'awk' был изобретен несколько лет спустя, в середине 1970-х годов. Лучше всего я могу сказать, что люди все еще используют эти конструкторы sed сегодня просто для того, чтобы попытаться заставить его работать, например, решить сложную загадку. –

ответ

2
sed -n '/All present$/{s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d' 

Где file является вашим файлом.

Это адаптированный пример из here.

Это имеет большое объяснение:

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

Позвольте мне объяснить эту команду: x;p;; Это выполняется для каждой строки. x обменивает содержимое пространства с пространством удержания. p печатает узор пространства. В результате каждый раз текущая строка переходит в свободное место, а предыдущая строка попадает в пространство рисунка и печатается. Когда шаблон /All Present/ совпадает, мы пустым (s/.*//) занимаем пространство шаблонов и обмениваем (x) с пространством удержания (в результате которого пространство удержания становится пустым) и удаляем (d) пространство шаблона, которое содержит предыдущую строку. И, следовательно, текущая и предыдущая строка удаляются при столкновении с образцом Linux. ${x;p;} - это печать последней строки, которая останется в удержании, если она оставлена.

Вторая часть sed состоит в том, чтобы удалить пустые строки, созданные первой командой sed.

+0

Спасибо за ваш ответ Эван, я пойду через объяснение и протестирую код:) – DMS

+0

Протестировано, спасибо за команду и объяснение! – DMS

3

Вы можете использовать fgrep так:

fgrep -v -f <(fgrep 'All present' -B1 file) file 
Guest-List 3 
Guest-list 5 
+0

Спасибо anubhava, я также дам ваше предлагаемое решение. – DMS

+2

Довольно аккуратный, но он предполагает, что нет повторяющихся заголовков. – tripleee

+0

@tripleee: Не уверен, что мой тест был наиболее точным, но я фактически протестировал его с двойной записью заголовка, эта команда все еще работала. – anubhava

0

Если вы используете более чем с, г, р (с -n) команды в СЭД, то вы используете языковые конструкции, которые стали устаревшими в середине 1970-х годов, когда был изобретен awk.

СЭД является отличным инструментом для простых замен на одной линии, для чего-то просто использовать AWK:

$ cat file 
Guest-List 1 
All present 
Guest-list 2 
All present 
Guest-List 3 
Guest-list 4 
All present 
Guest-list 5 

$ awk 'NR==FNR{ if (/All present/) {skip[FNR-1]; skip[FNR]} next} !(FNR in skip)' file file 
Guest-List 3 
Guest-list 5 

выше только разбирает файл дважды - первый раз для создания массива с именем skip линии номера (FNR) вы не хотите выводить, а второй раз печатать строки, которые не находятся в этом массиве. Простой, ясный, ремонтируемый, расширяемый, ...

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