根据另一列中的值获取以逗号分隔的列值列表

  • 本文关键字:获取 列表 分隔 一列 bash awk
  • 更新时间 :
  • 英文 :


我想根据制表符分隔文件的第1列中的值获得某些列(2,4,5)中所有值的逗号分隔列表。

我正在调整下面的命令,但相反,它会给我列中所有值的列表,而不仅仅是每个人的值-我不确定如何做到这一点。

awk -F"t" '{print $2}' $i | sed -z 's/n/,/g;s/,$/n/'

这是我正在处理的

Bob     24      M       apples  red
Bob     12      M       apples  green
Linda   56      F       apples  red
Linda   102     F       bananas yellow

这就是我想要得到的(我想保留重复项和顺序)

Bob     24,12   M       apples,apples   red,green
Linda   56,102  F       apples,bananas  red,yellow

假设:

  • 对于重复的名称,性别将始终相同,否则保存'最后一次看到的'

Oneawkidea:

awk '
BEGIN { FS=OFS="t" }
{   nums[$1] = nums[$1]   sep[$1] $2
gender[$1] = $3
fruits[$1] = fruits[$1] sep[$1] $4
colors[$1] = colors[$1] sep[$1] $5
sep[$1] = ","
}
END   { # PROCINFO["sorted_in"]="@ind_str_asc"      # this line requires GNU awk
for (name in nums)
print name,nums[name],gender[name],fruits[name],colors[name]
}
' input.tsv   

由此产生:

Bob     24,12   M       apples,apples   red,green
Linda   56,102  F       apples,bananas  red,yellow

注意:这恰好按照名称顺序显示输出;如果需要保证排序(按名称),OP可以通过sort运行输出,或者如果使用GNU awk,则取消PROCINFO["sorted_in"]

的注释。

当您使用awk时,您永远不需要sed。

假设您的关键值(第一个字段)按示例中所示分组(如果不是,则先对文件进行排序),那么无需将整个文件读取到内存中,并且对于任何数量的输入字段(您只需确定哪些字段编号不累积值,即在这种情况下字段1和3),您可以这样做:

$ cat tst.awk
BEGIN { FS=OFS="t" }
$1 != vals[1] {
if ( NR>1 ) {
prt()
}
delete vals
}
{
for ( i=1; i<=NF; i++ ) {
pre = ( (i in vals) && (i !~ /^[13]$/) ? vals[i] "," : "" )
vals[i] = pre $i
}
}
END { prt() }
function prt(    i) {
for ( i=1; i<=NF; i++ ) {
printf "%s%s", vals[i], (i<NF ? OFS : ORS)
}
}

$ awk -f tst.awk file
Bob     24,12   M       apples,apples   red,green
Linda   56,102  F       apples,bananas  red,yellow