如何根据每个部分第一行的第四个值对文件部分进行排序?

如何根据每个部分第一行的第四个值对文件部分进行排序?

我有一个由空行分隔的不同部分的文件,我想根据每个部分第一行的第四个值对所有部分进行升序排序,保持每个部分的主体不进行修改。

输入示例

PT2 energy =  7.135 eV ( -459.5928710 au) ( 57545.0 cm-1) (R=4)
22u22d00 3->6 : -0.535 (0.286)
22202200 4-->6 : -0.344 (0.119)
222u200d 4->8 :  0.256 (0.065)
222u2d00 4->6 : -0.254 (0.065)
R=4  TDM-form-state 1=   0.2702   -0.2855  -0.5610 TDM= 0.69  f: 0.082

PT2 energy =  7.018 eV ( -459.5971543 au) ( 56605.0 cm-1) (R=5)
22u220d0 3->7 : -0.396 (0.156)
222u2d00 4->6 :  0.352 (0.124)
22220ud0 5-->6,7 :  0.326 (0.106)
2222u0d0 5->7 :  0.303 (0.092)
2222u00d 5->8 :  0.271 (0.073)
222ud020 4,5-->7 :  0.267 (0.071)
22u22d00 3->6 : -0.229 (0.052)
R=5  TDM-form-state 1=   0.0860   -0.1785  -0.5446 TDM= 0.58  f: 0.058

PT2 energy =  6.552 eV ( -459.6143027 au) ( 52841.3 cm-1) (R=6)
222u20d0 4->7 : -0.612 (0.374)
2222ud00 5->6 : -0.499 (0.249)
222udud0 4,5-->6,7 : -0.271 (0.074)
R=6  TDM-form-state 1=  -0.2916   -0.0544  -2.1475 TDM= 2.17  f: 0.754

输出

PT2 energy =  6.552 eV ( -459.6143027 au) ( 52841.3 cm-1) (R=6)
222u20d0 4->7 : -0.612 (0.374)
2222ud00 5->6 : -0.499 (0.249)
222udud0 4,5-->6,7 : -0.271 (0.074)
R=6  TDM-form-state 1=  -0.2916   -0.0544  -2.1475 TDM= 2.17  f: 0.754

PT2 energy =  7.018 eV ( -459.5971543 au) ( 56605.0 cm-1) (R=5)
22u220d0 3->7 : -0.396 (0.156)
222u2d00 4->6 :  0.352 (0.124)
22220ud0 5-->6,7 :  0.326 (0.106)
2222u0d0 5->7 :  0.303 (0.092)
2222u00d 5->8 :  0.271 (0.073)
222ud020 4,5-->7 :  0.267 (0.071)
22u22d00 3->6 : -0.229 (0.052)
R=5  TDM-form-state 1=   0.0860   -0.1785  -0.5446 TDM= 0.58  f: 0.058

PT2 energy =  7.135 eV ( -459.5928710 au) ( 57545.0 cm-1) (R=4)
22u22d00 3->6 : -0.535 (0.286)
22202200 4-->6 : -0.344 (0.119)
222u200d 4->8 :  0.256 (0.065)
222u2d00 4->6 : -0.254 (0.065)
R=4  TDM-form-state 1=   0.2702   -0.2855  -0.5610 TDM= 0.69  f: 0.082

我尝试过

sort -n -k4 file

但这对所有文件进行操作并破坏这些部分

答案1

使用任何 awk、排序和剪切:

$ awk -v OFS='\t' '!pNF{val=$4} {print val, NR, $0; pNF=NF} END{if (pNF) print val, NR+1, ""}' file |
    sort -k1,1n -k2,2n |
    cut -f3-
PT2 energy =  6.552 eV ( -459.6143027 au) ( 52841.3 cm-1) (R=6)
222u20d0 4->7 : -0.612 (0.374)
2222ud00 5->6 : -0.499 (0.249)
222udud0 4,5-->6,7 : -0.271 (0.074)
R=6  TDM-form-state 1=  -0.2916   -0.0544  -2.1475 TDM= 2.17  f: 0.754

PT2 energy =  7.018 eV ( -459.5971543 au) ( 56605.0 cm-1) (R=5)
22u220d0 3->7 : -0.396 (0.156)
222u2d00 4->6 :  0.352 (0.124)
22220ud0 5-->6,7 :  0.326 (0.106)
2222u0d0 5->7 :  0.303 (0.092)
2222u00d 5->8 :  0.271 (0.073)
222ud020 4,5-->7 :  0.267 (0.071)
22u22d00 3->6 : -0.229 (0.052)
R=5  TDM-form-state 1=   0.0860   -0.1785  -0.5446 TDM= 0.58  f: 0.058

PT2 energy =  7.135 eV ( -459.5928710 au) ( 57545.0 cm-1) (R=4)
22u22d00 3->6 : -0.535 (0.286)
22202200 4-->6 : -0.344 (0.119)
222u200d 4->8 :  0.256 (0.065)
222u2d00 4->6 : -0.254 (0.065)
R=4  TDM-form-state 1=   0.2702   -0.2855  -0.5610 TDM= 0.69  f: 0.082

否则,只需使用 GNU awk 来处理数组的数组,并使用sorted_in:

awk '
    BEGIN { RS=""; ORS="\n\n" }
    { recs[$4][++cnt[$4]] = $0 }
    END {
        PROCINFO["sorted_in"] = "@ind_num_asc"
        for (val in recs) {
            for (i=1; i<=cnt[val]; i++) {
                print recs[val][i]
            }
        }
    }
' file

循环的目的cnt[]是,如果/当相同的值(例如7.135)在不同输入记录的第四个字段中多次出现时,输出将保留该键值的输入顺序。或者,在读取输入时,您可以通过字符串连接获得相同的结果,例如仍然使用 GNU awk 进行排序:

awk '
    BEGIN { RS=""; ORS="\n\n" }
    { recs[$4] = recs[$4] $0 ORS }
    END {
        PROCINFO["sorted_in"] = "@ind_num_asc"
        for (val in recs) {
            printf "%s", recs[val]
        }
    }
' file

仅使用 gawk 的方法的缺点是它们必须将整个文件存储在内存中,并且无法移植到没有 gawk 的系统。顶部的 awk+sort+cut 脚本具有高度可移植性,只有“sort”必须一次处理整个文件,并且它被设计为使用需求分页等来处理大文件,因此不太可能一个比 gawk 更大的文件的问题。

答案2

sort是面向线的。这里你需要阅读“段落”中的文件。

这可以通过一个非常短的 GNU awk 程序来完成:

gawk -v RS= -v ORS='\n\n' '
  {section[$4] = $0}
  END {
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (key in section) print section[key]
  }
' file

将 RS 变量(记录分隔符)设置为空字符串会读取包含空行分隔记录的文件。每条记录都存储在一个数组中,并通过排序键进行索引。

神奇的 PROCINFO 行告诉 gawk 在遍历数组时按索引对数组进行数字排序。

相关内容