sed / awk将成对的行合并为一行

时间:2016-01-14 01:26:46

标签: bash unix awk sed

我有一个数据列表,格式如下:

Joined       : a
Whatever     : b
Last visited : c
Useful       : y
NotUseful1   : f
Email        : z
RandomWat    : g
*** end *** 
Joined       : a
Whatever     : b
Last visited : c
Useful       : y
NotUseful1   : f
Email        : z
RandomWat    : g
*** end ***
Joined       : h
Whatever     : i
Last visited : j
Useful       : k
NotUseful1   : l
Email        : m
RandomWat    : n

我想要的是:

Useful, Email, Joined, Last Visited
y,z,a,c
y,z,a,c
k,m,h,j

我可能喝了太多啤酒,但我无法弄清楚如何在fiex-length列中获取各行的值。实际上是某些特定输出的CSV格式。

我真的在寻找sed / awk中的东西,尽管任何文本处理器都可以。

3 个答案:

答案 0 :(得分:3)

您可以将Awk的记录分隔符设置为**end**,并使用一些轻量分析来分隔字段;但如果格式是一个完全稳定的八行固定顺序系列,那么你真正需要的是

awk -F ' *: *' -v OFS=, '{i=NR%8; a[i]=$NF }
    i==7 { print a[4], a[7], a[1], a[3] }' file

如果您的值可能包含冒号,则需要进行调整 - 这个简单的代码只会在最后一个冒号之后删除它们。

将CSV标题添加为练习(或者只是不要)。

-F选项设置输入字段分隔符,因此Awk将分割冒号线,修剪任何相邻的空格。 OFS是输出字段分隔符;我们希望输出以逗号分隔。 NR是当前输入行号,% 8计算模数;所以i的值从1到7,然后换行为零,然后再次开始攀爬,在整个文件中重复。现在,我们使用i作为数组a的索引,并将每行的最后一个字段收集到此数组中。当我们到达索引7时,我们有所需的所有字段,因此我们打印它们。 (我最初将此值设为0,但之后会丢失最后一条记录,因为您的样本数据中没有终止**end**。)

NF是输入字段的数量,我们希望它基本上一直是2,所以我也可以在那里使用硬编码$2。如果您需要对此进行扩展,我会完全忘记-F ' *: *',只需手动sub("^[^:]*: *", ""),然后将整个值放在$0中。

答案 1 :(得分:2)

如果我理解正确,你想在一行上打印所有第1列,然后在第二行下面的第二列打印相应的信息。

使用awk非常简单。

awk '{ORS=" "} {print$1}' file.txt
awk '{ORS=" "} {print$NF}' file.txt

输出:

joined whatever last useful notuseful randomwat
a b c y f z g

ORS是输出记录分隔符。默认值是换行符。但在这种情况下,我们将它变成一个单独的空间。

因此,对于每一行,awk将打印由空格分隔的每行的第一个字段。

然后我们只执行相同的命令,但使用最后一个字段而不是第一个字段。然后,这将在下一行打印出相应的信息,每个记录再次被空格分隔。

如果你希望你的新列是固定宽度,我建议使用printf,但我相信还有其他方法可以做到(我听说Perl擅长这个)。

printf会抑制换行符,因此我们可以移除awk的ORS部分。 但是,由于不会创建换行符,因此我们必须在每个awk命令之后附加一个带有单独printf命令的结束语句,以使我们进入新行,即

awk '{printf "%10s",$1}END{printf"\n"}' file.txt
awk '{printf "%10s",$NF}END{printf"\n"}' file.txt

这将为使用awk语句找到的所有内容打印十个字符长的列。

输出:

joined  whatever       last    useful  notuseful     email randomwat
     a         b          c         y         f          z        g

注意:awk根据空格确定每列的内容。所以在你的例子中,"最后一次访问"将只打印出最后一个,因为那是第一列。如果要将多个单词分组到特定列中,请将单词集包装在引号""中。

答案 2 :(得分:0)

我不认为awk是这项工作的最佳工具,或者我只是不知道awk的某些方面会使这更容易。

awk 'BEGIN{split("4,6,1,3",x,",");i=1;FS=":"}
    function s(e){gsub(/( *$)|(^ *)/,"",e);return e}
    function p(a){for(j=1;j<length(x);++j)printf "%s,",a[x[j]];print a[x[j]]}
    function e(){if(!d){p(h);d=1}p(v);i=1}
    {if(NF==1)e();else{if(!d)h[i]=s($1);v[i++]=s($2)}}
    END{e()}' infile.txt

这不是太优雅,但这个眼睛完成了工作。您还可以修改"4,6,1,3"以选择以csv格式打印的字段 对于您的示例,这将输出以下内容:

Useful,Email,Joined,Last visited
y,z,a,c
y,z,a,c
k,m,h,j

此命令要求所有条目具有相同的字段,键和值由:分隔,条目由任何不包含冒号的行分隔。

我知道我迟到了,但我很想知道你是否想出更好的解决方案来解决这个问题。

相关问题