linux - 将带有模式的行转换为列

时间:2018-03-05 08:25:43

标签: linux bash awk sed

大家。

这种具有特定模式的转置事物从行到列一直困扰着我。

我想将下面的行更改为像

这样的列

20:20:10
abc_flow.out
sss_flow.out
20:20:11
bcd_flow.out
qcd_flow.out

20:20:10 abc_flow.out sss_flow.out
20:20:11 bcd_flow.out qcd_flow.out

谢谢!

7 个答案:

答案 0 :(得分:2)

当且仅当您的Input_file与所示示例相同(相同)时,才使用简单的xargs

xargs -n3 <  Input_file

来自man xargs

  

-n max-args          每个命令行最多使用max-args参数。如果使用的话,将使用少于max-args的参数          超出大小(请参阅-s选项),除非给出-x选项,在这种情况下xargs将          退出。

答案 1 :(得分:2)

以下是基于awksed的两种解决方案。这两个解决方案都是 泛型 ,这意味着我们不知道在使用正则表达式/..:..:../识别的两个时间字符串之间放置了多少条记录/行:

awk

awk 'BEGIN{ORS=OFS}/..:..:../&&(NR!=1){printf "\n"}1;END{printf "\n"}' <file>

这里我们将输出记录分隔符(ORS)设置为等于输出字段分隔符(OFS)。这意味着默认情况下,一切都将以一行结束。但是,每次我们找到表示时间字符串的记录时,我们都会打印换行符。

它基本上检查行是否是时间,如果是,则打印换行符。对于其余部分,它将所有记录打印在一行中(ORS=OFS ::输出记录分隔符是输出字段分隔符。)

备注: END{printf "\n"}只打印最终的换行符并不是必需的。这取决于您的要求。

sed

sed ':a;N;/..:..:..$/{P;D};s/\n/ /;ba' <file>

理解这只是纯sed wtf。理解这一点的方法最好一步一步完成:

  • :a创建标签a
  • N将新行添加到模式缓冲区
  • /..:..:..$/{P;D}如果模式缓冲区以时间字符串结尾,则将模式缓冲区打印到第一个换行符(P),然后删除相同的部分(D )。
  • s/\n/ /用空格替换模式缓冲区中的换行符。
  • ba转到标签a

由于sed在没有-n的情况下被调用,因此默认情况下会在退出时打印剩余的模式缓冲区。

答案 2 :(得分:1)

另外两个解决方案。结合echocatsed

echo $(cat file.txt) | sed 's/ \([0-9]\)/\n\1/g'                           

或使用paste命令:

paste -d " " - - - < file.txt

默认情况下,paste命令用选项卡 Tab 替换换行符\n。但是,在这种情况下,我们希望用空格替换\n,因此我们需要-d " "。要限制每次我们需要短划线占位符-时粘贴的行数。在这种情况下,由于输入数据的结构,我们需要三个破折号。

答案 3 :(得分:1)

另一个awk

$ awk '/[0-9:]/{if(line) print line; line=$0; next} 
               {line=line OFS $0} 
       END     {if(line) print line}' file

20:20:10 abc_flow.out sss_flow.out
20:20:11 bcd_flow.out qcd_flow.out

如果需要,您可以优化正则表达式匹配。

答案 4 :(得分:1)

使用此方法可能有助于您解决问题:

echo $(cat answer.txt) | sed 's/ ([0-9]\)/\n\1/g' 

答案 5 :(得分:0)

您可以使用以下sed命令:

$ (tr '\n' ' ' < file; echo '' ) | sed 's/ \([0-9]\{1,2\}:[0-9]\{1,2\}:\)/\n\1/g'                                                              

经过测试:

$ cat file
20:20:10
abc_flow.out
sss_flow.out
20:20:11
bcd_flow.out
qcd_flow.out
$ (tr '\n' ' ' < file; echo '' ) | sed 's/ \([0-9]\{1,2\}:[0-9]\{1,2\}:\)/\n\1/g'                                                              
20:20:10 abc_flow.out sss_flow.out
20:20:11 bcd_flow.out qcd_flow.out

<强>说明:

tr命令会将所有EOL转换为spaces,然后sed命令只会替换空格,后跟您的时间戳\n后跟对时间戳的反向引用,以便分隔不同行上的记录。

答案 6 :(得分:0)

rs命令用于重塑这样的数组。我们可以要求它将换行视为分隔符(-e),并重新整形为三列(0 3)中每一行的未知行数:

$ rs -e 0 3 <<END
20:20:10
abc_flow.out
sss_flow.out
20:20:11
bcd_flow.out
qcd_flow.out
END
20:20:10      abc_flow.out  sss_flow.out
20:20:11      bcd_flow.out  qcd_flow.out

我们可以添加-C' '-z以获得更紧凑的输出:

20:20:10 abc_flow.out sss_flow.out 
20:20:11 bcd_flow.out qcd_flow.out