在 shell 中输出由另一列组成的列组

在 shell 中输出由另一列组成的列组

提前致谢!

我有一个包含 3 列的文件,如下所示:

serv1   red     group1
serv1   black   group1
serv1   orange  group1
serv1   red     group2
serv1   orange  group2
serv1   red     group3
serv1   black   group3
serv1   orange  group3
serv2   orange  group1
serv2   red     group2
serv2   orange  group2
serv2   red     group3
serv2   black   group3
serv2   orange  group3
serv3   orange  group1
serv3   red     group1

我会这样展示:

serv1   group1  red black   orange
serv1   group2  red orange
serv1   group3  red black   orange
serv2   group1  orange
serv2   group2  red orange
serv2   group3  red black   orange
serv3   group1  orange  red

如果我尝试仅按第一个与下一个代码进行分组,我会表现得很好,但我无法对多个代码进行分组:

awk '{ V_GRUPO[$1]= (V_GRUPO[$1]==""?"":V_GRUPO[$1] OFS) $2 }END  { for(x in V_GRUPO) print x, V_GRUPO[x] }' file.txt
serv1   red black   orange red  orange  red black   orange
serv2   orange  red orange  red black   orange
serv3   orange  red

¿我怎么能做到呢???

谢谢!!

答案1

假设输入中的字段由多个空格分隔(一种“漂亮打印的表格”格式),并且您希望根据其他两个字段将第二个字段中的条目折叠到以空格分隔的列表中:

$ mlr --pprint -N nest --ivar ' ' -f 2 then reorder -f 1,3,2 file
serv1 group1 red black orange
serv1 group2 red orange
serv1 group3 red black orange
serv2 group1 orange
serv2 group2 red orange
serv2 group3 red black orange
serv3 group1 orange red

这会使用以下命令对原始字段进行折叠和重新排序磨坊主( mlr)。

如果数据是制表符分隔 (TSV),并且您想要制表符分隔输出,则更--pprint改为--tsv.您是否想要为折叠的数据列表使用不同的分隔符,然后更改--ivar ' '为例如--ivar ';'(以使用;)。

例如,对于制表符分隔的输入和输出,使用;作为列表分隔符:

$ mlr --tsv -N nest --ivar ';' -f 2 then reorder -f 1,3,2 file
serv1   group1  red;black;orange
serv1   group2  red;orange
serv1   group3  red;black;orange
serv2   group1  orange
serv2   group2  red;orange
serv2   group3  red;black;orange
serv3   group1  orange;red

另一个例子,读取 TSV 输入,向每个字段添加标签,使用这些标签而不是数字字段,并生成打印精美的表格输出:

$ mlr --itsv --implicit-csv-header --opprint --barred label Server,Colour,Group then nest --ivar ';' -f Colour then reorder -f Server,Group,Colour file
+--------+--------+------------------+
| Server | Group  | Colour           |
+--------+--------+------------------+
| serv1  | group1 | red;black;orange |
| serv1  | group2 | red;orange       |
| serv1  | group3 | red;black;orange |
| serv2  | group1 | orange           |
| serv2  | group2 | red;orange       |
| serv2  | group3 | red;black;orange |
| serv3  | group1 | orange;red       |
+--------+--------+------------------+

答案2

使用脚本,脚本文件.awk :

{
    k = $1 OFS $3
    a[k] = (k in a ? a[k] OFS : "" ) $2
}
END{
    for(key in a){
        print key, a[key]
    }
}

然后运行:

awk -f script-file.awk input
  • a[k]是一个使用键的数组k = $1 OFS $3
  • OFS是输出字段分隔符
  • ?是一个条件式 ( test ? true : false)
  • for(key in a)对于每个键

这可能不会被排序,所以如果你需要它排序管道它:

awk -f script-file.awk input | sort

答案3

由于您的输入已按 2 个键字段排序,因此使用任何 awk 时,一次只会在内存中保存 1 个键对的值:

$ awk '
    { key = $1 OFS $3 }
    key != prev { if (NR>1) print vals; prev=vals=key }
    { vals = vals OFS $2 }
    END { print vals }
' file
serv1 group1 red black orange
serv1 group2 red orange
serv1 group3 red black orange
serv2 group1 orange
serv2 group2 red orange
serv2 group3 red black orange
serv3 group1 orange red

如果您的实际输入尚未按照示例输入进行排序,则只需先对其进行排序:

sort -b -k1,1 -k3,3 file | awk '...'

答案4

datamash要折叠一个列组,可以使用另一个列(或其他列) 。

$ datamash -sW groupby 1,3 collapse 2 --collapse-delimiter ' ' <file

关于折叠分隔符的手册:

--collapse-delimiter=x
-c x
Use character X instead of comma to delimit items in a ‘collapse’ or ‘unique’ (aka ‘uniq’) list.

相关内容