我有一个数据列表,格式如下:
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中的东西,尽管任何文本处理器都可以。
答案 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
此命令要求所有条目具有相同的字段,键和值由:
分隔,条目由任何不包含冒号的行分隔。
我知道我迟到了,但我很想知道你是否想出更好的解决方案来解决这个问题。