#perl #awk #sed
Вопрос:
Давайте рассмотрим этот простой файл:
{
bla bla
bla bla bla
}
{
bla bla
bla bla bla
}
bla bla
bla bla bla
Мне нужно удалить только эти последовательные строки:
}
{
Результат должен быть:
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Я попробовал следующее:
sed -e '/^}$/,/^{$/d' file
К сожалению, последняя закрывающая фигурная скобка и оставшиеся строки были удалены:
{
bla bla
bla bla bla
bla bla
bla bla bla
Есть какие-нибудь предложения?
Я открыт для любого простого решения, включающего другие инструменты, такие как awk/perl/… при необходимости.
Ответ №1:
Вы можете использовать это sed
:
sed '/^}$/ { N; /n{$/ d; }' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Чтобы сохранить изменения в строке:
sed -i.bak '/^}$/ { N; /n{$/ d; }' file
В качестве альтернативы это awk
также сработало бы:
awk '/^}$/ {p = $0; next} p != "" {if (/^{$/) {p=""; next} $0 = p ORS $0; p = ""} 1' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Комментарии:
1.Существуют угловые случаи, когда любая из этих команд может не выдавать желаемый результат (хотя в вопросе не было представлено никаких угловых случаев). Например, такая последовательность, как
}
}
{
.
Ответ №2:
Решение Perl:
perl -lne 'undef $prev, next if $prev eq "}" amp;amp; $_ eq "{";
print $prev if defined $prev;
$prev = $_;
END { print $prev if defined $prev}' -- file
-n
считывает входные данные строка за строкой и запускает код для каждой строки.-l
удаляет новые строки из входных данных и добавляет их вprint
.- Мы сохраняем предыдущую строку в
$prev
. Если предыдущая строка была}
, а текущая строка есть{
, мы забываем предыдущую строку и читаем следующую строку. В противном случае мы печатаем предыдущую строку, если она была (что означает, что мы не печатаем пустую строку после забытой строки). Затем мы сохраняем текущую строку в $prev и повторяем. - Эта
END
деталь необходима для печати последней запомнившейся строки, если таковая имеется.
Ответ №3:
С GNU sed для -z
:
$ sed -z 's/}n{n//' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
С GNU awk для многозначных RS:
$ awk -v RS='}n{n' -v ORS= '1' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Ответ №4:
$ sed '$!N;/^}n{$/d;P;D' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Этот двухстрочный буфер также будет работать для других входных данных, как в следующем тесте:
$ cat test
}
}
{
foo
}
$ sed '$!N;/^}n{$/d;P;D' test
}
foo
}
Ответ №5:
Также вы можете использовать это awk
:
awk 'BEGIN{RS="";FS=OFS="n"}{print $1,$2,$3,$6,$7,$8,$9,$10}' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla
Или с помощью for
цикла:
awk 'BEGIN{RS="";FS=OFS="n"}{
for(i=1;i<=NF;i ) {
if(i == 4 || i == 5) continue; print $i}
}' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla