使用' sed'或者' awk'用于数据转换任务

时间:2014-06-18 09:15:24

标签: linux awk sed

我有这种格式的数据(很多这样的行):

TASK : Task 1  
TASK : Task 2  
TASK : Task 3  
OWNER : Emp 1  
OWNER : Emp 2  
OWNER : Emp 3  
Deadline : Monday  
Deadline : Tuesday  
Deadline : Wednesday  

这个,我想转换为:

TASK          OWNER           Deadline
Task 1       Emp 1            Monday  
Task 2       Emp 2            Tuesday  
Task 3       Emp 3            Wednesday

即使我可以在没有列标题名称的情况下提取每个列,它也会很好。之后我可以手动添加列名。

有没有办法使用'awk'或'sed'?

3 个答案:

答案 0 :(得分:5)

使用awk的一种方式:

 awk -F': *' '{i=NR%3;i=i?i:3;a[i]=a[i]?a[i]"\t"$2:$2}
              END{for(x=1;x<=length(a);x++)print a[x]}' file

它保留了订单,省略了标题行:

kent$  cat f
TASK : Task 1  
TASK : Task 2  
TASK : Task 3  
OWNER : Emp 1  
OWNER : Emp 2  
OWNER : Emp 3  
Deadline : Monday  
Deadline : Tuesday  
Deadline : Wednesday 

kent$  awk -F': *' '{i=NR%3;i=i?i:3;a[i]=a[i]?a[i]"\t"$2:$2}END{for(x=1;x<=length(a);x++)print a[x]}' f
Task 1          Emp 1   Monday  
Task 2          Emp 2   Tuesday  
Task 3          Emp 3   Wednesday

解释

 awk -F': *'             #":any <space>" as FS
 '{i=NR%3;i=i?i:3;       #take NR%3 in i, if i=0, set i=3. because
                         #we want the i=0 case at the end of the output
 a[i]=a[i]?a[i]"\t"$2:$2}#concatenate the 2nd column to an array
 END{for and print}' file#print the content of the array at the end

标题

我们可以将标题保存在var h中并在通过a (array)之前将其打印出来:

awk -F': *' '{...h=i==1?(h?h"\t"$1:$1):h;a[i]=..} 
END{print h;for...}' file

答案 1 :(得分:2)

这是一个相对不错的awk版本:

BEGIN {FS=" : ";OFS="\t"}

/^TASK/     {task [tpos++] = $2}
/^OWNER/    {owner[opos++] = $2}
/^Deadline/ {due  [dpos++] = $2}

END {
  print "TASK", "OWNER", "DEADLINE"
  for (i in task) {
    print task[i],owner[i],due[i]
  }
}

:)

它为每个块保存一行,因为它不需要gsub()调用,因为它使用:作为分隔符。将其存储在test.awk中,然后按如下方式执行:

awk -f test.awk input.txt

<强>更新

上面的命令导致shell中的未对齐输出:

TASK    OWNER    DEADLINE
Task 1      Emp 1      Monday  
Task 2      Emp 2      Tuesday  
Task 3      Emp 3      Wednesday 

您可以使用column命令解决此问题:

awk -f test.awk input.txt | column -t -s $'\t'

现在输出看起来很干净:

TASK      OWNER    DEADLINE
Task 1    Emp 1    Monday  
Task 2    Emp 2    Tuesday  
Task 3    Emp 3    Wednesday 

答案 2 :(得分:2)

Perl解决方案:

perl -le 'while (<>) {
              chomp;
              ($h, $t) = split / : /;
              $i++, push @{$ar[0]}, $h if $h ne $ar[0][-1];
              push @{$ar[$i]}, $t;
          };
          $" = "\t";
          print "@{$ar[0]}";
          print join $", map shift @{$ar[$_]}, 1 .. $#ar while @{$ar[1]}'

如果标签没有很好地对齐文字,我会使用Text::Table