在bash中基于多个列合并文件

在bash中基于多个列合并文件,bash,awk,Bash,Awk,我有一个包含多个列(用逗号分隔)的文件,其中的值重复。我要做的是基于这些列合并或“汇总”行 例如,假设我有以下内容: 输入文件: ID, Name , Eye Color, Hair Color, Marital Status 1 , John , Brown , Brown , Single 1 , Mary , Green , Brown , Married 2 , Joe , Blue , Blonde , Divorced 2 , Brian,

我有一个包含多个列(用逗号分隔)的文件,其中的值重复。我要做的是基于这些列合并或“汇总”行

例如,假设我有以下内容:

输入文件:

ID, Name , Eye Color, Hair Color, Marital Status
1 , John , Brown    , Brown     , Single
1 , Mary , Green    , Brown     , Married
2 , Joe  , Blue     , Blonde    , Divorced
2 , Brian, Green    , Brown     , Single
2 , Gary , Brown    , Blonde    , Married
我想要基于第一列和第四列的以下输出:

输出文件:

ID, Name , Eye Color, Hair Color, Marital Status, Name, Eye Color, Hair Color, Marital Status
1 , John , Brown    , Brown     , Single        , Mary, Green    , Brown     , Married
2 , Joe  , Blue     , Blonde    , Divorced      , Gary, Brown    , Blonde    , Married
2 , Brian, Green    , Brown     , Single
我可以使用以下awk为第一列执行此操作:

awk -F, '
    NR!=1 && p1!=$1 { print prev; prev="" }
    { p1=$1; prev=(prev"") ? prev FS substr($0,index($0,$2)) : $0 }
    END { if(prev"") print prev }
' input.txt > output.txt

我还需要找到一种方法来包括第四列。

这里是一般的想法,不假设记录是有序的(但也不保留顺序)

您可以像在逻辑中一样过滤不需要的重复列,并且需要努力使标题适合匹配记录的最大长度

可以使用扩展标题的格式化版本

$ awk 'BEGIN{FS=" *, *"; OFS=","}
       NR==1{$1=$1; header0=$0; split($0,header); next} 
            {$1=$1; c[$1,$4]++; 
             a[$1,$4]=(($1,$4) in a?a[$1,$4] OFS $2 OFS $3 OFS $5:$0)}
         END{for(k in c) if(max<c[k]) max=c[k]; 
             printf "%s",header0; 
             for(i=2;i<=max;i++) printf "%s", OFS header[2] OFS header[3] OFS header[5]; 
             print ""; 
             for(k in a) print a[k] | "sort -n" }' file | 
  column -ts,


ID  Name   Eye Color  Hair Color  Marital Status  Name  Eye Color  Marital Status
1   John   Brown      Brown       Single          Mary  Green      Married
2   Brian  Green      Brown       Single
2   Joe    Blue       Blonde      Divorced        Gary  Brown      Married
$awk'开始{FS=“*,*”OFS=“,”}
NR==1{$1=$1;header0=$0;拆分($0,header);下一个}
{$1=$1;c[$1,$4]+;
a[$1,$4]=(a中的($1,$4)OFS$2 OFS$3 OFS$5:$0)}

END{for(k in c)if(max这里是一般的想法,不假设记录是有序的(但也不保留顺序)

您可以像在逻辑中一样过滤不需要的重复列,并且需要努力使标题适合匹配记录的最大长度

可以使用扩展标题的格式化版本

$ awk 'BEGIN{FS=" *, *"; OFS=","}
       NR==1{$1=$1; header0=$0; split($0,header); next} 
            {$1=$1; c[$1,$4]++; 
             a[$1,$4]=(($1,$4) in a?a[$1,$4] OFS $2 OFS $3 OFS $5:$0)}
         END{for(k in c) if(max<c[k]) max=c[k]; 
             printf "%s",header0; 
             for(i=2;i<=max;i++) printf "%s", OFS header[2] OFS header[3] OFS header[5]; 
             print ""; 
             for(k in a) print a[k] | "sort -n" }' file | 
  column -ts,


ID  Name   Eye Color  Hair Color  Marital Status  Name  Eye Color  Marital Status
1   John   Brown      Brown       Single          Mary  Green      Married
2   Brian  Green      Brown       Single
2   Joe    Blue       Blonde      Divorced        Gary  Brown      Married
$awk'开始{FS=“*,*”OFS=“,”}
NR==1{$1=$1;header0=$0;拆分($0,header);下一个}
{$1=$1;c[$1,$4]+;
a[$1,$4]=(a中的($1,$4)OFS$2 OFS$3 OFS$5:$0)}

END{for(k in c)if(max以下使用三个关联数组跟踪所有内容

  • x
    数组是一个二维“交叉引用”--具有第1列和第4列值的索引,并且具有一个存储值作为行号,我们将在其中查找匹配行
  • g
    数组跟踪我们“增长”特定行的次数。(我们在需要时使用此数组来增长标题。)
  • o
    数组是我们的输出数组,用于聚合数据行
我们使用
sprintf
在添加到输出之前重新格式化最后一列输入,以根据问题的输出要求保留表格的间距

awk -F, -v OFS=, '
    ($1, $4) in x {
        # existent row -- append
        i = x[$1, $4]
        $1 = ""
        $5 = sprintf("%-15s", $5)
        o[i] = o[i] $0
        if(++g[i] > g[1]) {
            # grow the header row
            o[1] = o[1] h
            ++g[1]
        }
        next
    }
    {
        # new output row
        x[$1, $4] = ++n
        $5 = sprintf("%-15s", $5)
        o[n] = $0
    }
    NR==1 {
        # save header for append
        $1 = ""
        h = $0
    }
    END {
        for (i=1; i<=n; ++i)
            print o[i]
    }'
awk-F,-v OFS=,'
(1美元,4美元)x{
#现有行—追加
i=x[$1,$4]
$1 = ""
$5=sprintf(“%-15s”,5美元)
o[i]=o[i]$0
if(++g[i]>g[1]){
#增加标题行
o[1]=o[1]h
++g[1]
}
下一个
}
{
#新输出行
x[$1,$4]=++n
$5=sprintf(“%-15s”,5美元)
o[n]=$0
}
NR==1{
#保存要追加的标题
$1 = ""
h=$0
}
结束{

对于(i=1;i,以下使用三个关联数组跟踪所有内容

  • x
    数组是一个二维“交叉引用”--具有第1列和第4列值的索引,并且具有一个存储值作为行号,我们将在其中查找匹配行
  • g
    数组跟踪我们“增长”特定行的次数。(我们在需要时使用此数组来增长标题。)
  • o
    数组是我们的输出数组,用于聚合数据行
我们使用
sprintf
在添加到输出之前重新格式化最后一列输入,以根据问题的输出要求保留表格的间距

awk -F, -v OFS=, '
    ($1, $4) in x {
        # existent row -- append
        i = x[$1, $4]
        $1 = ""
        $5 = sprintf("%-15s", $5)
        o[i] = o[i] $0
        if(++g[i] > g[1]) {
            # grow the header row
            o[1] = o[1] h
            ++g[1]
        }
        next
    }
    {
        # new output row
        x[$1, $4] = ++n
        $5 = sprintf("%-15s", $5)
        o[n] = $0
    }
    NR==1 {
        # save header for append
        $1 = ""
        h = $0
    }
    END {
        for (i=1; i<=n; ++i)
            print o[i]
    }'
awk-F,-v OFS=,'
(1美元,4美元)x{
#现有行—追加
i=x[$1,$4]
$1 = ""
$5=sprintf(“%-15s”,5美元)
o[i]=o[i]$0
if(++g[i]>g[1]){
#增加标题行
o[1]=o[1]h
++g[1]
}
下一个
}
{
#新输出行
x[$1,$4]=++n
$5=sprintf(“%-15s”,5美元)
o[n]=$0
}
NR==1{
#保存要追加的标题
$1 = ""
h=$0
}
结束{

对于(i=1;唯一的问题是(我知道它不会出现在这个过于简单的数据中)我不确定需要“汇总”多少组记录到一行。但也许我可以在第一个awk命令后运行类似的操作。这种方法不受限制。您可以计算汇总行数并相应地打印标题,请参阅更新。唯一的问题是(我知道它不会显示在这个过于简化的数据中)我不确定需要“汇总”多少组记录到一行。但也许我可以在第一个awk命令后运行类似的操作。这种方法不受限制。您可以计算汇总行数并相应地打印标题,请参阅更新。