Как удалить соответствующую строку, строку выше и одну ниже, используя sed?
У меня есть следующая последовательность, встречающаяся несколько раз в файле:
yyyy
xxxx
zzzz
У меня есть регулярное выражение, которое соответствует xxxx
. Всякий раз, когда есть совпадение, я хочу удалить эту строку, линию до (например, yyyy
) и строку после нее (например, zzzz
). Как я могу использовать sed для этого?
Ответы
Ответ 1
Трюк состоит в том, чтобы сохранить последнюю строку, видимую в "удержании".
sed -n '
/^xxxx/{n
n
x
d
}
x
1d
p
${x
p
}
' <input file>
Начиная с x
- свопинг текущей строки ввода с пространством удержания (x
), тогда для первой строки ничего не печатайте (1d
), последующие строки печатают строку, только что замененную (p
), в последней строке снова поменяйте место удержания и распечатайте то, что было в нем ($x{x p}
). Это оставляет то, что нужно делать, когда мы попадаем на целевую линию (начиная с /^xxxx/
) - читайте следующие две (n n
) и поменять пространство с пространством удержания (x
) - это оставляет пространство удержания со следующей строкой, которую мы хотим распечатать, и пространство с рисунком с линией перед матчем, которое мы не хочу, поэтому мы отключаем его (d
)
Ответ 2
Вы можете проверить этот документ. Он охватывает использование sed
для работы с несколькими строками.
Ответ 3
Вот как я сделал бы это в perl, может быть, он может помочь вам отправить вас на правильный путь... Удачи!
open(INFILE,"<in.txt");
my(@arrayOutBoundData, $skipNextLine)l
for (<INFILE>) {
if (not $skipNextLine) {
if (/^xxxx$/) {
pop(@arrayOutBoundData);
$skipNextLine = 1;
} else {
push(@arrayOutBoundData,$_);
}
}
$skipNextLine = 0
}
open(OUTFILE,">out.txt");
for (@arrayOutBoundData) {
print OUTFILE;
}
(Не проверено без perl на этой системе, пожалуйста, простите за любой сайт.)
Ответ 4
Это может сработать для вас (GNU sed):
echo -e "a\nyyyy\nxxxx\nzzzz\nb" | sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D'
a
b
Это сохраняет окно двух строк в пространстве шаблонов, и если требуемое регулярное выражение найдено в первой или второй строке, читает следующую строку и затем удаляет все три строки. Редкие случаи - если регулярное выражение найдено в первой или последней строках, когда нет линии до/после. В этих случаях можно удалить только две строки.
Кстати, это решение, возможно, выявило возможную ошибку в GNU sed. Флаг M
адреса позволяет использовать метасимволы ^
и $
в качестве маркеров нулевой длины в регулярном выражении для начала и конца строки в многострочных строках. Пустой адрес //
повторно использует ранее указанный адрес. Должен ли этот адрес быть одним, который включает многострочный флаг? В настоящее время он, как представляется, включает флаг, даже если он не указан i.e.
sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D' file
производит другой (правильный) результат:
sed 'N;/^xxxx/M{//d;$!N;d};P;D' file
если xxxx
появляется во второй строке файла.
Ответ 5
Вы можете использовать следующее:
sed -n '/xxxx/{N;s/.*//;x;d;};x;p;${x;p;}'
Это заменит 3 строки одной пустой строкой.
Ответ 6
Вы можете сначала отменить файл, использовать sed
, чтобы удалить согласованную строку и следующую строку (или строки, +Nd
в sed
) и, наконец, отменить результат:
tac old.file | sed -e '/xxxx/,+1d' | tac > new.file
Ответ 7
grep -v -f <(grep -1 "xxxx" file) file