Использование sed для идентификации шаблона в строках, а не в Столбцах
Можно ли использовать GNU sed для идентификации шаблона на основе строк? Или другими словами, как вы можете вставить разрыв строки в шаблон, который вы используете sed для идентификации?
Например, в следующем наборе данных (который на самом деле намного больше) у меня есть ошибка, которая должна была быть удалена, когда я искал дубликаты, но не была, потому что информация немного отличается в двух строках (что не имеет значения на данный момент).
В этом случае я хочу полностью удалить ошибку из оригинал file.In другими словами, если в моем файле две строки rs####
следуют друг за другом, я хотел бы стереть эти две копии, а также шесть строк, которые следуют за ними. Было бы неплохо переместить их в новый файл, но самое главное, что они удалены из оригинала.
rs1038864 16 73762557 A G
1 1633 0.5835 -0.0004 0.0035
1 1643 0.8902 0.004436 0.004354
0 0 0 0 0
rs1019567 16 83343715 G T
rs1019567 16 83343715 G T
1 1641 0.4692 0.0009 0.0035
1 559 0.4612 -0.0025 0.0060
1 1643 0.5178 -0.002244 0.002745
1 1643 0.5178 -0.002244 0.002745
1 1909 0.493842692 0.0008 0.0027
1 1950 0.493842692 0.0008 0.0027
rs1038556 16 55132072 C T
1 6388 0.7773 0.0020 0.0044
1 6843 0.1161 0.001379 0.004275
1 1509 0.978660942 0.0041 0.0096
rs1019797 16 87788686 C G
rs1019797 16 87788686 C G
1 1639 0.717 0.0022 0.0038
1 5557 0.7193 0.0020 0.0064
1 1643 0.6691 -0.001044 0.002888
1 6843 0.6691 -0.001044 0.002888
1 1959 0.315280799 -0.0041 0.0032
1 1909 0.315280799 -0.0041 0.0032
rs1038887 16 62660698 A G
1 1688 0.4947 -0.0028 0.0035
0 0 0 0 0
1 1909 0.464393658 0.0007 0.0028
Что-то вроде,
sed -i '/^rs.*d
^rs.*/,+6d' test.data
Или, возможно,
sed -i '/^rs.*;^rs.*/,+6d' test.data
? Любые мысли будут оценены!
2 ответа:
Если
infile
содержит перечисленные входные данные, что-то вроде этого должно сделать (GNU sed):<infile sed -r 'N; /([^\n]+)\n\1/ { N; N; N; N; N; N; d }; P; D'
Если вы хотите сохранить удаленные биты в
deleted.txt
, используйте следующее:Обратите внимание, что команда<infile sed -r 'N; /([^\n]+)\n\1/ { N; N; N; N; N; N; w deleted.txt d }; P; D'
w
должна завершаться новой строкой.объяснение
Это загружает вторую строку в пространство шаблонов (
N
) и проверяет, являются ли строки дубликатами (/([^\n]+)\n\1/
), если еще шесть строк загружены в пространство шаблонов и удалены (d
).
Я не думаю, что
sed
является правильным инструментом для работы (но я могу ошибаться; это отчасти зависит от того, всегда ли есть ровно 6 строк для удаления и, возможно, от того, всегда ли соседние строки ID имеют один и тот же ID). Вы, вероятно, можете сделать это сawk
, но я бы потянулся к Perl:#!/usr/bin/env perl use strict; use warnings; my $rejects = "reject.lines"; open my $fh, '>', $rejects or die "Failed to create $rejects"; my $old = ""; while (<>) { if ($_ =~ /^rs\d+ /) { if ($old =~ /^rs\d+ /) { print $fh $old; print $fh $_; while (<>) { last if /^rs\d+ /; print $fh $_; } $old = $_; next; } } print $old; $old = $_; } print $old if $old ne ""; close $fh;
Это будет обрабатывать произвольное количество строк после соседних строк маркера, и не зависит от того, что два маркера идентичны.
Вывод
rs1038864 16 73762557 A G 1 1633 0.5835 -0.0004 0.0035 1 1643 0.8902 0.004436 0.004354 0 0 0 0 0 rs1038556 16 55132072 C T 1 6388 0.7773 0.0020 0.0044 1 6843 0.1161 0.001379 0.004275 1 1509 0.978660942 0.0041 0.0096 rs1038887 16 62660698 A G 1 1688 0.4947 -0.0028 0.0035 0 0 0 0 0 1 1909 0.464393658 0.0007 0.0028
Отклонить строки
rs1019567 16 83343715 G T rs1019567 16 83343715 G T 1 1641 0.4692 0.0009 0.0035 1 559 0.4612 -0.0025 0.0060 1 1643 0.5178 -0.002244 0.002745 1 1643 0.5178 -0.002244 0.002745 1 1909 0.493842692 0.0008 0.0027 1 1950 0.493842692 0.0008 0.0027 rs1019797 16 87788686 C G rs1019797 16 87788686 C G 1 1639 0.717 0.0022 0.0038 1 5557 0.7193 0.0020 0.0064 1 1643 0.6691 -0.001044 0.002888 1 6843 0.6691 -0.001044 0.002888 1 1959 0.315280799 -0.0041 0.0032 1 1909 0.315280799 -0.0041 0.0032