【问题标题】:Find a match followed by another match in a different line and sort the output在不同的行中找到一个匹配,然后是另一个匹配并对输出进行排序
【发布时间】:2014-06-22 10:32:30
【问题描述】:

我有一个格式如下的文件:

First Name : aa
#some noninteresting info
...
#some noninteresting info
Last Name : tt
First Name : cc
#some noninteresting info
...
#some noninteresting info
Last Name : ss

我需要生成另一个只有名字和姓氏并根据姓氏排序的文件:

First Name : cc
Last Name : ss
First Name : aa
Last Name : tt

我尝试了以下方法:

grep "Last Name :" | sort 

但这只是我想要的一半。如何将名字添加到与姓氏相对应的名称中,并根据姓氏对其进行排序?

【问题讨论】:

    标签: regex perl sed grep xargs


    【解决方案1】:

    如果您有 GNU sed,那么您可以通过管道将 grep 的输出传送给它。

    grep -E '(First|Last) Name' file | sed 'N;s/\n/ /' | sort -k8 | sed 's/Last/\nLast/'
    First Name : cc
    Last Name : ss
    First Name : aa
    Last Name : tt
    
    • grep -E '(First|Last) Name' file 将 grep 包含名字和姓氏的行
    • sed 'N;s/\n/ /' 会将姓氏添加到名字后
    • sort -k8 将排序第 8 个字段,即姓氏值
    • sed 's/Last/\nLast/' 会将它们放在不同的行中

    如果您没有 GNU sed,那么您的另一个选择是使用 xargs

    grep -E '(First|Last) Name' file | xargs -n8 | sort -k8 | xargs -n4
    First Name : cc
    Last Name : ss
    First Name : aa
    Last Name : tt
    

    注意:这假设您的数据对于每个条目都有名字和姓氏。 xargs 解决方案假定您的名字没有中间名

    【讨论】:

    • 完美运行。谢谢!
    • 如果我有三个字段(例如 First、Last、Age),我应该如何更改 sed 以连接三行?
    • @Ari 包括Age 你可以做grep -E '(First|Last|Age)' file | sed 'N;N;s/\n/ /g' | sort -k8 | sed 's/Last\|Age/\n&/g'
    • @jaypal 干得好。但是,鉴于人们倾向于使用明显的虚假数据(例如 Last 作为姓氏),我对使用 sed 的行的连接和拆分方法有点警惕。至少,我建议添加一个像~ 这样的随机分隔符,以帮助防止在拆分行时添加无关的返回。
    • @Miller 我认为First Name :Last Name : 是固定参数,它们旁边有值(例如ccssaatt)。话虽如此,我确实同意你的评论。第一个 sed 只是附加连续行,第二个根据 OP 在他的问题中使用的参数名称进行拆分。
    【解决方案2】:

    您可以轻松地使用正则表达式来完成过滤:

    grep -E "(Last|First) Name :"
    

    但要在显示名字的同时让它们按姓氏“顺序”排列,您需要在排序之前进行更多处理。也许您可以查看sedawk 来帮助解决这部分问题。

    您可以做到这一点的一种方法是通过更改正则表达式以使单个匹配包含名字和姓氏的行,将姓氏附加到匹配的开头,对其进行排序,然后删除姓氏... . 复杂,但可行的方法。

    【讨论】:

      【解决方案3】:

      使用 perl 单行代码

      perl -e 'print sort {@l = map /([^:]*)\Z/, $a, $b; $l[0] cmp $l[1]} split /(?=^First)/m, join q{}, grep /Name :/, <>' file.txt
      

      打破它。从下往上阅读。

      perl -e '
           print                                                   # Print results
           sort {@l = map /([^:]*)\Z/, $a, $b; $l[0] cmp $l[1]}    # Sort based off last phrase after a :
           split /(?=^First)/m,                                    # Split on lines beginning with First
           join q{},                                               # Join all lines together
           grep /Name :/,                                          # Filter all those not containing Name :
           <>                                                      # Slurp all the lines
         ' file.txt
      

      【讨论】:

        猜你喜欢
        • 2017-07-17
        • 1970-01-01
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-26
        • 1970-01-01
        • 2014-06-04
        相关资源
        最近更新 更多