删除第二个和倒数第二个匹配项之间的所有内容

删除第二个和倒数第二个匹配项之间的所有内容

我有想要格式化的字符串。我想删除第二个;和倒数第二个之间的所有内容;

输入

cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;  

输出

cellular organisms;Eukaryota;Tribolium castaneum;

我尝试过使用sed

sed 's/;[^;]*//' <<<"cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;"

产生

cellular organisms;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;

答案1

您可以使用以下方法轻松完成此操作awk

awk -F\; '{print $1 ";" $2 ";" $(NF-1) ";" $NF}'

;这使用( )分割输入-F\;,并打印第一个 ( $1)、第二个 ( $2)、倒数第二个和最后一个字段($(NF-1)并且$NF;NF包含字段数)。

以下变体在输出中重新使用指定的字段分隔符:

awk -F\; '{print $1 FS $2 FS $(NF-1) FS $NF}'

贾尼斯也建议使用改进版本OFS

awk 'BEGIN{FS=OFS=";"} {print $1,$2,$(NF-1),$NF}'

或者,如果您想将分隔符保留为另一个参数:

awk -F\; 'BEGIN{OFS=FS} {print $1,$2,$(NF-1),$NF}'

答案2

一些 Perl 方法。在所有情况下,我都运行此命令来填充$string

string="cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;"

 

$ perl -F';' -lane '$"=";"; print "@F[0,1,$#F-1];"' file 
cellular organisms;Eukaryota;Tribolium castaneum;

或者

$ perl -F';' -lane 'print "$F[0];$F[1];$F[$#F];"' <<<"$string"
cellular organisms;Eukaryota;Tribolium castaneum;

或者

$ perl -F';' -lane 'print join(";", @F[0,1,$#F-1]) . ";"' <<<"$string"
cellular organisms;Eukaryota;Tribolium castaneum;

答案3

另一种sed方法:

sed 's/\(^[^;]*\;[^;]*\).*\(\;[^;]*\;$\)/\1\2/'

输出: cellular organisms;Eukaryota;Tribolium castaneum;

答案4

sed -n 's/\(;[^;]*;\).*\(;.*;\)/\1\2/p' <infile

...上面只会p打印匹配至少 4 个;字符的输入行的任何内容,并且对于这些输入行,只会打印之前和之后的内容,并分别包括第二个和倒数第二个出现的;字符。

不过,如果您首先验证您至少有四个,则可以更轻松地执行以下操作:

 sed -n '/\(;.*\)\{4\}/s/[^;]*//3p' <infile

首先确保该行至少匹配 4 ;,然后删除第三个出现的零个或多个非分号字符序列。该测试是必要的,因为s///替换可以应用于任何匹配至少 2 个分号的行 - 因此测试可以确保;在尝试剥离之前添加倒数第二个分号。

上述两个建议的解决方案仅打印替换成功的那些行。您可以通过删除-np命令来打印所有行 - 仍然会尝试替换,并且只打印它们匹配的行的结果,但无论如何都会打印其他所有行。

当然,如果您确定自己的输入,您所需要的只是:

sed 's/[^;]*//3' <infile

相关内容