如何根据键名而不是它在 unix 中的位置对文件进行排序?

How to sort a file based on key name instead of its position in unix?

我想在 Unix 中对文件进行排序,为此我正在使用命令

sort file --field-separator=' ' --key=7,7

但是这个字段的位置不固定,有时可以是第7个字段,有时是第6个或第8个字段。

我们知道是否可以根据字段名称对文件进行排序,例如

sort file --field-separator=' ' --keyname=<my_unique_id>

文件看起来像这样,我想根据 party_id

排序
status_date="2000-01-31" ref_date="2021-03-31" ead_percent="0.00365316" accounting_standard="IFRS" party_default_status_cd="NOTDFLT" party_id="36113477" v_src_system_id="ABC"
status_date="2002-12-31" ref_date="2021-03-31" ead_percent="1" accounting_standard="IFRS" orig_src_system_id="GRD" party_default_status_cd="UNLIKE" party_id="36053415" v_src_system_id="XYZ"

sort 没有命名键的概念,但是你可以执行一个 Schwartzian transform 临时将键作为前缀添加到行中,在第一个字段上排序,然后丢弃它。

sed 's/\(.*\)\(party_id="[^"]*"\)/    /' file |
sort -t '   ' -k1,1 |
cut -f2-

(两个第一个后向引用之间和 sort -t 参数中的空格是文字制表符,但是 Stack Overflow 将其呈现为空格序列)。

使用 Decorate/Sort/Undecorate 习语并假设,就像在您提供的示例中一样,您引用的字符串不包含空格、=":

装饰:

$ awk -F'[ ="]+' -v OFS='\t' -v keyname='party_id' '{for (i=1; i<NF; i+=2) if ($i == keyname) { print $(i+1), [=10=]; next} }' file
36113477        status_date="2000-01-31" ref_date="2021-03-31" ead_percent="0.00365316" accounting_standard="IFRS" party_default_status_cd="NOTDFLT" party_id="36113477" v_src_system_id="ABC"
36053415        status_date="2002-12-31" ref_date="2021-03-31" ead_percent="1" accounting_standard="IFRS" orig_src_system_id="GRD" party_default_status_cd="UNLIKE" party_id="36053415" v_src_system_id="XYZ"

装饰然后排序:

$ awk -F'[ ="]+' -v OFS='\t' -v keyname='party_id' '{for (i=1; i<NF; i+=2) if ($i == keyname) { print $(i+1), [=11=]; next} }' file |
    sort -k1,1n
36053415        status_date="2002-12-31" ref_date="2021-03-31" ead_percent="1" accounting_standard="IFRS" orig_src_system_id="GRD" party_default_status_cd="UNLIKE" party_id="36053415" v_src_system_id="XYZ"
36113477        status_date="2000-01-31" ref_date="2021-03-31" ead_percent="0.00365316" accounting_standard="IFRS" party_default_status_cd="NOTDFLT" party_id="36113477" v_src_system_id="ABC"

装饰然后排序然后取消装饰:

$ awk -F'[ ="]+' -v OFS='\t' -v keyname='party_id' '{for (i=1; i<NF; i+=2) if ($i == keyname) { print $(i+1), [=12=]; next} }' file |
    sort -k1,1n |
    cut -f2-
status_date="2002-12-31" ref_date="2021-03-31" ead_percent="1" accounting_standard="IFRS" orig_src_system_id="GRD" party_default_status_cd="UNLIKE" party_id="36053415" v_src_system_id="XYZ"
status_date="2000-01-31" ref_date="2021-03-31" ead_percent="0.00365316" accounting_standard="IFRS" party_default_status_cd="NOTDFLT" party_id="36113477" v_src_system_id="ABC"

使用GNU awk (gawk) 可以指定如何遍历数组。下面使用 party_id=XYZ 作为各自的索引将每一行保存在一个数组中,然后 returns 按所述索引排序的数组。对于非常大的文件,受 RAM 限制。

awk '{match([=10=],/party_id=[^ ]*/,[=10=],id) ; arr[id[0]]=[=10=]}
     END {PROCINFO["sorted_in"]="@ind_str_asc"
          for (i in arr) {print arr[i]}
     }' infile.txt