【问题标题】:Sort a file in unix by the absolute value of a field按字段的绝对值对unix中的文件进行排序
【发布时间】:2017-07-08 10:41:09
【问题描述】:

我想按线性回归 (p) 列的 绝对 值降序对该文件进行排序。我这样做的尝试并没有奏效。我不确定它失败了什么。我从http://www.unix.com/shell-programming-and-scripting/168144-sort-absolute-value.html 找到了这段代码。

awk -F',' '{print ($2>=0)?$2:-$2, $0}' OFS=',' mycsv1.csv | sort -n -k8,8 | cut -d ',' -f2-



X var,Y var,MIC (strength),MIC-p^2 (nonlinearity),MAS (non-monotonicity),MEV (functionality),MCN (complexity),Linear regression (p)
AT1G01030,AT1G32310,0.67958,0.4832027,0.32644996,0.63247,4.0,-0.44314474
AT1G01030,AT3G06520,0.61732,0.17639545,0.23569,0.58557,4.0,0.6640215
AT1G01030,AT5G42580,0.61579,0.5019064,0.30105,0.58143,4.0,0.33746648
AT1G01030,AT1G55280,0.57287,0.20705527,0.19536,0.52857,4.0,0.6048262
AT1G01030,AT5G30490,0.56509,0.37536618,0.16172999,0.51847,4.0,-0.43557298
AT1G01030,AT1G80040,0.56268,0.22935495,0.18583998,0.52728,4.0,-0.5773431
...

请帮助我理解 awk 脚本对这个文件进行排序。

【问题讨论】:

  • 什么是“不太好用”?
  • 。它没有按第 8 列或任何其他列排序。所以我不确定它为什么会失败
  • 仔细看一下代码应该会有所帮助。我的意思是,当您对第 8 个字段感兴趣时,为什么要查看 awk 中的字段 $2

标签: sorting unix awk


【解决方案1】:

您可以为此使用sedsort,并遵循@hek2mgl 非常聪明的逻辑,即在末尾添加和删除字段以保留原始数字:

 sed -E 's/,([-]?)([0-9.]+)$/,\1\2,\2/' file | sort -t, -k9,9 -nr | cut -f1-8 -d,
  • sed -E 's/,([-]?)([0-9.]+)$/,\1\2,\2/' => 创建字段 9 作为字段 8 的绝对值
  • sort -t, -k9,9 -nr => 按新创建的字段、数字和降序排序
  • cut -f1-8 -d, => 删除第 9 个字段,将输出恢复为原始格式,并具有所需的排序顺序

这是输出:

AT1G01030,AT3G06520,0.61732,0.17639545,0.23569,0.58557,4.0,0.6640215
AT1G01030,AT1G55280,0.57287,0.20705527,0.19536,0.52857,4.0,0.6048262
AT1G01030,AT1G80040,0.56268,0.22935495,0.18583998,0.52728,4.0,-0.5773431
AT1G01030,AT1G32310,0.67958,0.4832027,0.32644996,0.63247,4.0,-0.44314474
AT1G01030,AT5G30490,0.56509,0.37536618,0.16172999,0.51847,4.0,-0.43557298
AT1G01030,AT5G42580,0.61579,0.5019064,0.30105,0.58143,4.0,0.33746648

【讨论】:

  • 如果您在第一个命令中输出排序和剪切的默认分隔符 (\t) 而不是 , 那么您不需要在后面的命令中指定这些分隔符。
【解决方案2】:

分三步:

(1) 临时创建第 9 个字段,其中包含字段 8 的绝对值:

LC_COLLATE=C awk -F, 'NR>1{v=$NF;sub(/-/,"",v);printf "%s%s%s%s",$0,FS,v,RS}' file
        ^ ------ make sure this is set since sorting, especially the decimal point
             depends on the local.

(2) 根据第 9 个字段对该输出进行排序:

command_1 | sort -t, -k9r

(3) 通过管道将其返回到 awk 以删除最后一个字段。 NF-- 减少将有效删除最后一个字段的字段数。 1 始终为真,这使得 awk 打印该行:

command_2 | cut -d, -f1-8

输出:

AT1G01030,AT3G06520,0.61732,0.17639545,0.23569,0.58557,4.0,0.6640215
AT1G01030,AT1G55280,0.57287,0.20705527,0.19536,0.52857,4.0,0.6048262
AT1G01030,AT1G80040,0.56268,0.22935495,0.18583998,0.52728,4.0,-0.5773431
AT1G01030,AT1G32310,0.67958,0.4832027,0.32644996,0.63247,4.0,-0.44314474
AT1G01030,AT5G30490,0.56509,0.37536618,0.16172999,0.51847,4.0,-0.43557298
AT1G01030,AT5G42580,0.61579,0.5019064,0.30105,0.58143,4.0,0.33746648

【讨论】:

  • 另外,您应该设置LC_COLLATE 而不是LANG 以避免更改语言环境可能产生的其他不良副作用。
  • 既然知道列数,那么cut 可能是awk 的更好替代方案。改变了,现在使用LC_COLLATE
【解决方案3】:

可以让 awk 完成所有工作:

awk -F, 'NR>1{n[substr($NF,1,1)=="-"?substr($NF,2):$NF]=$0}NR==1;END{asorti(n,out);for(i in out)print n[out[i]]}' file

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-13
    • 2011-09-14
    • 1970-01-01
    • 2017-11-13
    • 2012-06-20
    • 2019-02-13
    • 1970-01-01
    • 2020-09-02
    相关资源
    最近更新 更多