使用 AWK 在没有几行的情况下将行转为列

使用 AWK 在没有几行的情况下将行转为列

我有一个文本文件,其中包含以下内容:

标题1 A1
标题3 A3
标题4 A4
标题5 A5

标题1 B1
标题2 B2
标题5 B5

标题1 C1
标题2 C2
标题4 C4
标题5 C5

标题1 D1
标题2 D2
标题3 D3

我想要如下的输出:

title1      title2       title3        title4      title5  
  A1                        A3           A4          A5  
  B1           B2                                    B5  
  C1           C2                        C4          C5  
  D1           D2           D3                        

您能告诉我如何使用 AWK 编写一段代码吗?

提前致谢!

答案1

如果您可以将数据更改为仅使用空格分隔(或仅使用“:”),则以下 awk 程序可以做到这一点。您可能需要调整它以完善您的布局。

BEGIN { i = 1; }
$1 != "" { C[$1] = $1; X[$1,i] = $2 ; next; }
{ i++; }
END {
    asort(C);
    for ( k in C ) printf "  %8s\t", C[k];
    printf "\n";
    for ( j = 1; j <= i; j++ ) {
        for ( k in C ) printf "%8s\t",X[C[k],j];
        printf "\n";
    }
}

答案2

awk -f  transpose_rows_to_cols.awk /tmp/1
title1  title2  title3  title4  title5
A1      A3  A4  A5
B1  B2          B5
C1  C2      C4  C5
D1  D2  D3      

附言。在终端上格式化就可以了。

脚本 -

#!/usr/bin/awk -f
BEGIN {
    printf("title1\ttitle2\ttitle3\ttitle4\ttitle5\n");
    a["title1"] = a["title2"]= a["title3"]= a["title4"]= a["title5"] = ""
}
{
    if ($0 !~ /^$/) {
        if ($0 ~ /:/)  {FS=":"; $0=$0} else {FS=" "; $0=$0}
        a[$1]=$2
    } else {
        printf("%s\t%s\t%s\t%s\t%s\n", a["title1"], a["title2"], a["title3"], a["title4"], a["title5"])
        a["title1"] = a["title2"]= a["title3"]= a["title4"]= a["title5"] = ""
    }
}
END{
        printf("%s\t%s\t%s\t%s\t%s\n", a["title1"], a["title2"], a["title3"], a["title4"], a["title5"])
}

答案3

这个答案建立在拉尔夫·伦奎斯特的回答, 但

  1. 假设列应按用户指定的顺序输出,而不是按标题的字母顺序输出,并且
  2. 允许数据值是多字。

就像拉尔夫的回答一样,这假设标题与数据之间用空格而不是冒号分隔。

为了实现目标#1,它要求输入以包含按所需顺序排列的所有标题(没有附带数据)的节开始。

BEGIN { i = 0; j= 0; }
$1 != "" { if (i==0) C[++j] = $1; else { label = $1; $1 = ""; X[label,i] = $0; } next; }
{ i++; }
END {
    for ( k in C ) printf "  %8s\t", C[k];
    printf "\n";
    for ( j = 1; j <= i; j++ ) {
        for ( k in C ) printf "%8s\t", X[C[k],j];
        printf "\n";
    }
}

请注意,i被初始化为0,并且该i==0情况经过特殊处理 - 仅捕获标题(因为这是唯一应该存在的东西),并且标题存储在C由递增整数 ( j) 索引的数组中,而不是由标题本身的价值。否则,我们会捕获数据。  $1 = "";删除行中的第一个字段并重建$0为所有其他字段的串联。 (这会在字段之间丢失多个空格;这可以通过一些工作来纠正。)我们将值保存$1label变量中,以便我们可以将其用作数据数组 的索引X

例如,这个输入:

name
address
phone
height
weight

name John Lennon
phone 123
height 6' 1"
weight 180

name Sir Paul M.
address Liverpool
weight 175

name George
address 42                 Main St.
height 71"
weight 185 lbs

name Ringo Starr
address Penny Lane
phone 456 789

产生这个输出:

      name         address           phone          height          weight
 John Lennon                         123           6' 1"             180
 Sir Paul M.     Liverpool                                           175
  George         42 Main St.                         71"         185 lbs
 Ringo Starr     Penny Lane      456 789

如果任何值的长度为 15 个字符或更长,则这些列将关闭。这一点还可以改进。

相关内容