2013-10-27 3 views
0

У меня есть данные в следующем формате:Выкрутите 2 последовательных линий

#@ <id_wxyz_1> 
A line written after this. 

#@ <id_123> 
A line written after this one also. 

#@ <id_wxyz_2> 
One more line. 

#@ <id_yex_9> 
Another line. 

Теперь я хочу, чтобы удалить 2 строки: строки, содержащие «WXYZ» в # @ < ...> и его следующую строку. Пример вывод, который я хочу это:

#@ <id_123> 
A line written after this one also. 

#@ <id_yex_9> 
Another line. 

Есть некоторые команды Linux, которая также может достигнуть того же или есть какой-то эффективный способ в Python, чтобы достичь того же. Я знаю, что я могу выборочно удалять одну строку с помощью grep, sed и т. Д. Но можно ли выборочно удалить две последовательные строки с помощью команды linux

EDIT: Ответы приведены отлично, но они не работают для ввода следующий вид:

#@ <id_wxyz_1> 
A line written after this. 

#@ <id_wxyz_2> 
A line written after this. 

#@ <id_wxyz_3> 
A line written after this. 

#@ <id_wxyz_4> 
A line written after this. 

#@ <id_wxyzadded5> 
A line written after this. 

Для приведенного выше ввода я не должен иметь выходных строк.

EDIT снова: еще один набор входов, которые у меня есть это:

#@ <id_wxyz0> 
Line 1. 
#@ <id_wxyz1> 
line 2. 
#@ <id_wxyz2> 
line 3. 
#@ <id_wxyz3> 
line 4. 
#@ <id_6> 
line 5. 

Для которого выход должен быть

#@ <id_6> 
line 5. 
+0

Рассмотрите также использование [GNU awk] (http://www.gnu.org/software/gawk/) ... –

+0

Вы можете написать скрипт Perl, который сканирует каждую строку для шаблона '_wxyz_', а затем удаляет линии и следующей строки. Не существует единой команды «unix», которая может делать такую ​​вещь. Я рекомендую Perl над утилитами, такими как sed или awk, когда дело касается нескольких строк. – zencv

ответ

4

Вы можете сделать это с использованием СЭД, например путем.

/^#@ <.*wxyz.*>/ { 
    N  #Add the next line to the pattern space 
    s/.*// #clear the line 
    N  #Read another line 
    /^\n$/ d #if line was blank, delete and start next cycle (reading again) 
    D  #Otherwise, delete up to newline, and start next cycle with that 

} 

Примечание: Во втором случае, он по-прежнему фактически выводит один пустую строку

+0

Ваш ответ потрясающий. +1 для этого. Но это не работает для определенных входов, как упоминалось в вопросе –

+0

@JannatArora: Исправлено (хотя теперь это не так просто, к сожалению). Кстати, если дело действительно было 2 последовательными линиями, и вы использовали GNU sed, вы могли бы сделать '/^# @<.*wxyz.*> /, + 1 d' вместо этого беспорядка. – Hasturkun

1

Использование awk вы могли бы сказать:

awk '/^#@ <.*wxyz.*>/{getline;getline}1' filename 

EDIT: В соответствии с измененным вопрос, можно сказать, :

sed '/^#@ <id_wxyz.*/,/^$/d' filename 
+0

Привет, это не работает для ввода формы: # @ Строка, написанная после этого. # @ A строка, написанная после этого. # @ A строка, написанная после этого. # @ A строка, написанная после этого. # @ A строка, написанная после этого. –

+0

@JannatArora Кажется, что ваш вход изменился. Комментарии не сохраняют новую строку; лучше, если бы вы обновили свой вопрос. – devnull

+0

Я обновил вопрос :) +1 за помощь –

1

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

awk '/^#@[[:blank:]]+<.*wxyz.*>/ { getline; getline; next } { print }' infile 

Это дает:

#@ <id_123> 
A line written after this one also. 

#@ <id_yex_9> 
Another line. 

UPDATE, чтобы обеспечить решение для нового редактирования в OP:

awk ' 
    BEGIN { RS = "#@" } 
    $1 ~ /[^[:space:]]/ && $1 !~ /<.*wxyz.*>/ { 
     sub(/\n[[:blank:]]*$/, "") 
     print RS, $0 
    } 
' infile 

И с вашим последним примером дает:

#@ <id_6> 
line 5. 
+0

Ваш ответ потрясающий. +1 для этого. Но это не работает для определенных входов, как указано в вопросе –

+0

@JannatArora: Я обновил ответ. – Birei

+0

слишком много 'getline'. Вам нужен только один (и '{print}' может быть '1'). – Kevin

2

Вы также можете просто использовать grep.

Пример: учитывая ваш вклад

$ cat t 
#@ <id_wxyz_1> 
A line written after this. 

#@ <id_123> 
A line written after this one also. 

#@ <id_wxyz_2> 
One more line. 

#@ <id_yex_9> 
Another line. 

#@ <id_wxyz_1> 
A line written after this. 

#@ <id_wxyz_2> 
A line written after this. 

#@ <id_wxyz_3> 
A line written after this. 

#@ <id_wxyz_4> 
A line written after this. 

#@ <id_wxyzadded5> 
A line written after this. 

#@ <id_wxyz0> 
Line 1. 
#@ <id_wxyz1> 
line 2. 
#@ <id_wxyz2> 
line 3. 
#@ <id_wxyz3> 
line 4. 
#@ <id_6> 
line 5. 

вы можете запустить

$ grep -A1 --group-separator="" -P '#[^_]*((?!wxyz).)*$' t 
#@ <id_123> 
A line written after this one also. 

#@ <id_yex_9> 
Another line. 

#@ <id_6> 
line 5. 

регулярное выражение соответствует линии, начиная с # и не содержащие wxyz с Perl-подобный синтаксис (отсюда -P аргумент) , -A1 добавляет одну строку после матча к выходу. Недокументированные опции --group-separator="" заменяют значение по умолчанию --, которое обычно разделяет группы строк при использовании параметра -A (или B310) или -C. Обратите внимание, что этот более поздний вариант недоступен для всех реализаций.

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