Bash 在第一行中按字段排序两行,然后按第二行的长度排序

Bash 在第一行中按字段排序两行,然后按第二行的长度排序,bash,sorting,awk,Bash,Sorting,Awk,我想筛选具有以下格式的文件: Name1|Name2|Name3 ACGRTIDKEBDIVNRDIVFDOCDDIC Name4|Name5|Name6 AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP Name1|Name7|Name3 AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ 输出 Name1|Name7|Name3 AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJ

我想筛选具有以下格式的文件:

Name1|Name2|Name3  
ACGRTIDKEBDIVNRDIVFDOCDDIC  
Name4|Name5|Name6  
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP  
Name1|Name7|Name3 
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
输出

Name1|Name7|Name3  
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ  
Name1|Name2|Name3  
ACGRTIDKEBDIVNRDIVFDOCDDIC  
Name4|Name5|Name6  
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
我按文件名排序,并将第1行和第2行放在一起;但我也只想保留第二行最长的那一行(这里是第1行和第2行,去掉第3行和第4行)

我可以使用awk按名称排序:

awk '{if ((NR%1-2)==0) {line=sprintf("%-30s", $0)} else {print line ":" $0}}' file | sort -t '|' -k1 | tr ':' '\n' > newfile
我不知道如何根据第二行的长度进行排序(仅保留)(使用sort-n)

感谢

Perl解决方案:

#!/usr/bin/perl
use strict;
use warnings;

my %by_length;
my ($id, $l1);

while (<>) {
    ( sub { $by_length{$id} = {l1 => $l1, l2 => $_}
                if length > length($by_length{$id}{l2} // "")
      },
      sub { $id = (split /\|/)[0]; $l1 = $_ }
    )[$. % 2]->()
}
print @{ $by_length{$_} }{qw{ l1 l2 }} for sort keys %by_length;
awk 'NR % 2 == 0{ sub(/\|/, " ", r); print length, r, $0 }{ r = $0 }' file \
| sort -k2,2 -k1,1nr | awk '{ print $2"|"$3 ORS $NF }'
#/usr/bin/perl
严格使用;
使用警告;
我的长度百分比;
我的($id,$l1);
而(){
(sub{$by_length{$id}={l1=>$l1,l2=>$}
if length>length($by_length{$id}{l2}//“”)
},
sub{$id=(split/\\\|/)[0];$l1=$\}
)[$. % 2]->()
}
打印排序键的@{$by_length{${}{qw{l1 l2}}},打印长度为%by_length;
哈希
%by_length
在其
l2
子键中存储每个名称的最长行,以及
l1
下相应的第一行

#!/usr/bin/perl
use strict;
use warnings;

my %by_length;
my ($id, $l1);

while (<>) {
    ( sub { $by_length{$id} = {l1 => $l1, l2 => $_}
                if length > length($by_length{$id}{l2} // "")
      },
      sub { $id = (split /\|/)[0]; $l1 = $_ }
    )[$. % 2]->()
}
print @{ $by_length{$_} }{qw{ l1 l2 }} for sort keys %by_length;
awk 'NR % 2 == 0{ sub(/\|/, " ", r); print length, r, $0 }{ r = $0 }' file \
| sort -k2,2 -k1,1nr | awk '{ print $2"|"$3 ORS $NF }'
#/usr/bin/perl
严格使用;
使用警告;
我的长度百分比;
我的($id,$l1);
而(){
(sub{$by_length{$id}={l1=>$l1,l2=>$}
if length>length($by_length{$id}{l2}//“”)
},
sub{$id=(split/\\\|/)[0];$l1=$\}
)[$. % 2]->()
}
打印排序键的@{$by_length{${}{qw{l1 l2}}},打印长度为%by_length;

哈希
%by_length
在其
l2
子键中存储每个名称的最长行,以及
l1

复杂
awk
+
排序
解决方案:

#!/usr/bin/perl
use strict;
use warnings;

my %by_length;
my ($id, $l1);

while (<>) {
    ( sub { $by_length{$id} = {l1 => $l1, l2 => $_}
                if length > length($by_length{$id}{l2} // "")
      },
      sub { $id = (split /\|/)[0]; $l1 = $_ }
    )[$. % 2]->()
}
print @{ $by_length{$_} }{qw{ l1 l2 }} for sort keys %by_length;
awk 'NR % 2 == 0{ sub(/\|/, " ", r); print length, r, $0 }{ r = $0 }' file \
| sort -k2,2 -k1,1nr | awk '{ print $2"|"$3 ORS $NF }'
输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1|Name2|Name3
ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

奖金解决方案(针对附加要求):

输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1|Name2|Name3
ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

复杂的
awk
+
排序
解决方案:

#!/usr/bin/perl
use strict;
use warnings;

my %by_length;
my ($id, $l1);

while (<>) {
    ( sub { $by_length{$id} = {l1 => $l1, l2 => $_}
                if length > length($by_length{$id}{l2} // "")
      },
      sub { $id = (split /\|/)[0]; $l1 = $_ }
    )[$. % 2]->()
}
print @{ $by_length{$_} }{qw{ l1 l2 }} for sort keys %by_length;
awk 'NR % 2 == 0{ sub(/\|/, " ", r); print length, r, $0 }{ r = $0 }' file \
| sort -k2,2 -k1,1nr | awk '{ print $2"|"$3 ORS $NF }'
输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1|Name2|Name3
ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

奖金解决方案(针对附加要求):

输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1|Name2|Name3
ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

下面介绍了如何在不必将整个文件存储在内存中的情况下轻松、可移植地完成所需的操作:

1) 将每对行折叠为1,并在要排序的键前面加上前缀:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
2) 按您喜欢的顺序对上述输出进行排序:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
3) 仅保留每个主键值的第一个匹配项:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++'
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
4) 删除步骤1中添加的额外字段,重新拆分为两行PAR,并打印结果:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++{print $3 ORS $4}'
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

如果空白字符不能用作组合字段的分隔符,则只需选择一个不同的字符即可(例如,制表符或控制字符或…。

以下是如何轻松、可移植地执行所需操作,而无需将整个文件存储在内存中:

1) 将每对行折叠为1,并在要排序的键前面加上前缀:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
2) 按您喜欢的顺序对上述输出进行排序:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
3) 仅保留每个主键值的第一个匹配项:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++'
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
4) 删除步骤1中添加的额外字段,重新拆分为两行PAR,并打印结果:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++{print $3 ORS $4}'
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP


如果空白字符不能用作组合字段的分隔符,则只需选择其他字符即可(例如制表符或控制字符或…).

请通过编辑您的问题将您的样本包装在代码标签中,并在您的问题中更加清晰。此外,如果您是按第1列和第2列对文件进行排序,那么为什么Name7出现在第一行,请解释它。文件有多大?是的,我只想保留前面的最长一行(我的示例中的第1行和第2行)如果有多对同名的行(第一行在|之前)。该文件大约有200000行。请通过编辑您的问题将您的样本包装在代码标签中,并在您的问题中更加清晰。此外,如果您是按第1列和第2列对文件进行排序,那么Name7为什么排在第一行,请解释它。该文件有多大?是的,我只想保留最长的一行,并打开e before(在我的示例中是第1行和第2行),如果有多对同名的行(在|之前的第一行)。该文件大约有200000行。很多!我尝试过并且工作得很好(非常快)。非常感谢!我尝试过并且工作得很好(非常快)。也很好。是否可以使用awk在管道中添加“如果”以仅打印最长的行(与前一行一起)?@Nico64,我无法理解您的短语“如果”以仅打印最长的行(与前一行一起)如果因为第2行比第4行长,所以我只想在输出行1和第2行中添加一个关于长度的“If语句”并只打印第1行和第2行吗?@Nico64,也使用我的“奖金”解决方案nice。是否可以在管道中添加一个If以只打印最长的行(与前一行一起)同时使用awk?@Nico64,我无法理解您的短语“可能是如果只打印最长的行(与前一行一起)”如果我只想在输出行1和2中打印,因为第2行比第4行长,然后是第5行和第6行。我们是否可以添加一个关于长度的“if语句”并只打印第1行和第2行?@Nico64,使用我的“奖金”解决方案