【问题标题】:Unix how to sort whole row based on a particular matchUnix如何根据特定匹配对整行进行排序
【发布时间】:2016-09-29 07:08:48
【问题描述】:

我有一个这样的文件

$> cat testfile.txt
abc_xyz_2a      foo
dft_pqr_abc_5c  bar
pqr_ijk_1a      alpha
efg_5b          beta
ijk_pqr_5a      gamma
pqr_ijk_1b      alpha

我想根据第一列的最后一个值对行进行排序,在最后一个下划线 _ 之后,例如 1a,2a,5a,5b,5c

所以这是我的预期输出。

pqr_ijk_1a      alpha
pqr_ijk_1b      alpha
abc_xyz_2a      foo
ijk_pqr_5a      gamma
efg_5b          beta
dft_pqr_abc_5c  bar

有人可以建议一种实现预期输出的方法吗?

我尝试了什么

我尝试在第一列的最后一个下划线之后提取部分并排序,但这只会打印那些关键字,而不是整行。

$> awk '{print $1}' testfile.txt|rev|awk -F_ '{print $1}'|rev|sort
1a
2a
5a
5b
5c

我想可能有一种方法可以以某种方式保存/记下行号并基于此输出?我在 awk 中使用 NR 尝试了一些成功和尝试,但未成功。

编辑:在以1b 结尾的文件中添加了一行来处理另一种情况。根据它改变了预期的输出。

【问题讨论】:

    标签: bash sorting unix awk


    【解决方案1】:

    如果您有gnu-awk,那么您可以使用PROCINFO 对数组进行排序:

    awk 'BEGIN{PROCINFO["sorted_in"] = "@ind_num_asc"} {
       n=split($1, a, "_")
       data[a[n]]=$0
    }
    END {
       for (i in data)
          print data[i]
    }' file
    
    pqr_ijk_1a      alpha
    abc_xyz_2a      foo
    ijk_pqr_5a      gamma
    efg_5b          beta
    dft_pqr_abc_5c  bar
    

    否则你可以使用awk-sort-cut管道:

    awk '{n=split($1, a, "_"); print $0 "\0" a[n]}' file | sort -t '\0' -k2 | cut -d $'\0' -f1
    
    pqr_ijk_1a      alpha
    abc_xyz_2a      foo
    ijk_pqr_5a      gamma
    efg_5b          beta
    dft_pqr_abc_5c  bar
    

    【讨论】:

      【解决方案2】:

      只需删除所需的列,对其进行排序,然后再次将其删除。

      $ cat data
      abc_xyz_2a      foo
      dft_pqr_abc_5c  bar
      pqr_ijk_1a      alpha
      efg_5b          beta
      ijk_pqr_5a      gamma
      
      
      $ awk '{print substr($1, length($1)-1, 1), substr($1, length($1)), $1, $2}' data | sort -n -k1,2 | awk '{print $3,$4}'
      pqr_ijk_1a alpha
      abc_xyz_2a foo
      ijk_pqr_5a gamma
      efg_5b beta
      dft_pqr_abc_5c bar
      

      以下是管道的每个步骤发生的情况:

      $ awk '{print substr($1, length($1)-1, 1), substr($1, length($1)), $1, $2}' data
      2 a abc_xyz_2a foo
      5 c dft_pqr_abc_5c bar
      1 a pqr_ijk_1a alpha
      5 b efg_5b beta
      5 a ijk_pqr_5a gamma
      
      $ awk '{print substr($1, length($1)-1, 1), substr($1, length($1)), $1, $2}' data | sort -n -k1,2
      1 a pqr_ijk_1a alpha
      2 a abc_xyz_2a foo
      5 a ijk_pqr_5a gamma
      5 b efg_5b beta
      5 c dft_pqr_abc_5c bar
      

      【讨论】:

        【解决方案3】:

        您可以尝试下面的命令,它更简单直接。

         rev   test.txt | sort  -k2 | rev
        
        
        pqr_ijk_1a      alpha
        abc_xyz_2a      foo
        ijk_pqr_5a      gamma
        efg_5b          beta
        dft_pqr_abc_5c  bar
        

        【讨论】:

        • 这行不通,因为rev 会使a1 脱离1a,因此a5 脱离5a
        • @Ajinkya - 感谢您的回答。但是当我尝试在文件中添加1b 时,它没有按预期工作。但对不同的方法表示赞赏。干杯。
        • @Utsav 但根据您的要求,我得到的输出符合您的期望。排序后您是否替换任何单词。
        • 同意。不幸的是,我选择的示例适用于您的答案,但这并不是我想要的。对此感到抱歉。无论如何感谢您的回答。
        猜你喜欢
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-06
        相关资源
        最近更新 更多