使用awk或sed将行转换为列

时间:2015-10-01 05:56:44

标签: awk sed

我有一个* .xvg格式的文件 它包含六列,每列有500个数字 除时间列(第一列)外,所有其他列都包含浮点数。

我想以相同的格式生成输出文件,其中这些列被转换为行,每个数字用空格分隔。

我用C编写了一个程序,对我来说很好用,但我正在寻找一种使用awk或sed的替代方法,这样我就可以做到这一点。

我对这些脚本语言完全陌生。在之前提出的问题中,我找不到任何相关的答案。所以,如果有人能帮助我完成这项任务,我将不胜感激。

输入文件如下所示: -

  # This file was created Thu Oct  1 17:18:10 2015
  # by the following command:
  # /home/durba/gmx455/bin/mdrun -np 1 -deffnm md0 -v 
  #
  @    title "dH/d\xl\f{}, \xD\f{}H"
  @    xaxis  label "Time (ps)"
  @    yaxis  label "(kJ/mol)"
  @TYPE xy
  @ subtitle "T = 200 (K), \xl\f{} = 0"
  @ view 0.15, 0.15, 0.75, 0.85
  @ legend on
  @ legend box on
  @ legend loctype view
  @ legend 0.78, 0.8
  @ legend length 2
  @ s0 legend "dH/d\xl\f{} \xl\f{} 0"
  @ s1 legend "\xD\f{}H \xl\f{} 0.05"
  0  19.3191 1.16531   1.8   -447.07  -47.07
  2 -447.072 -17.6454  1.5   -17.633  -1.33
  4 -17.633 -0.446508  1.3   -75.455  -5.45
  6 -75.4555 -2.83981  1.4   -28.724  -28.4
  8 -28.7246 -0.884639 1.5   -41.877  -14.87
  10 -41.8779 -1.45569  2.8   -43.685  -3.685
  12 -43.6851 -1.4797   -3.1  -91.651  -91.651
  14 -91.6515 -3.52492  -3.5  -61.135  -1.135
  16 -61.1356 -2.30129  -3.2  -48.847  -48.47

输出文件应如下所示: -

  # This file was created Thu Oct  1 17:18:10 2015
  # by the following command:
  # /home/durba/gmx455/bin/mdrun -np 1 -deffnm md0 -v 
  #
  @    title "dH/d\xl\f{}, \xD\f{}H"
  @    xaxis  label "Time (ps)"
  @    yaxis  label "(kJ/mol)"
  @TYPE xy
  @ subtitle "T = 200 (K), \xl\f{} = 0"
  @ view 0.15, 0.15, 0.75, 0.85
  @ legend on
  @ legend box on
  @ legend loctype view
  @ legend 0.78, 0.8
  @ legend length 2
  @ s0 legend "dH/d\xl\f{} \xl\f{} 0"
  @ s1 legend "\xD\f{}H \xl\f{} 0.05"
  0  2  4 6 8 10 12 
  19.3191 -447.072 -17.633 -17.633 -75.4555 -28.7246 -41.8779 -43.6851 -91.6515 -61.1356
  1.16531 -17.6454 -0.446508 -2.83981 -0.884639 -1.45569 -1.4797 -3.52492 -2.30129
  1.8 1.5 1.3 1.4 1.5 2.8 -3.1 -3.5 -3.2
  -447.07 -17.633 -75.455 -28.724 -41.877 -43.685 -91.651 -61.135 -48.847
  -47.07 -1.33 -5.45 -28.4 -14.87 -3.685 -91.651 -1.135 -48.47

请注意,以“#”和“@”开头的行在两个文件中应该相同。

2 个答案:

答案 0 :(得分:3)

回答原始问题

让我们考虑一下这个测试文件:

$ cat file
123 1.2 1.3 1.4 1.5
124 2.2 2.3 2.4 2.5
125 3.2 3.3 3.4 3.5

将列转换为行:

$ awk '{for (i=1;i<=NF;i++)a[i,NR]=$i} END{for (i=1;i<=NF;i++) for (j=1;j<=NR;j++) printf "%s%s",a[i,j],(j==NR?ORS:OFS)}' file
123 124 125
1.2 2.2 3.2
1.3 2.3 3.3
1.4 2.4 3.4
1.5 2.5 3.5

如何运作

  • for (i=1;i<=NF;i++)a[i,NR]=$i

    当我们遍历每一行时,我们将值保存在数组a中。

  • END{for (i=1;i<=NF;i++) for (j=1;j<=NR;j++) printf "%s%s",a[i,j],(j==NR?ORS:OFS)}

    在我们到达文件末尾之后,如果我们位于行中间或输出记录分隔符({{1}),则打印每个值后跟输出字段分隔符(OFS) })如果我们在行的末尾。

多行版本

如果你喜欢你的代码分布在几行:

ORS

回答修订后的问题

在修订后的问题中,文件开头的行以awk ' { for (i=1;i<=NF;i++) a[i,NR]=$i } END{ for (i=1;i<=NF;i++) for (j=1;j<=NR;j++) printf "%s%s",a[i,j],(j==NR?ORS:OFS) } ' file @开头,不会被更改。在这种情况下:

#

答案 1 :(得分:1)

这可能适合你(GNU sed):

sed -r 'H;$!d;x;:a;h;s/\n(\S+)[^\n]*/\1 /g;s/ $//p;g;s/\n\S+ ?/\n/g;ta;d' file

将文件拖入保留空间(HS),删除模式空间(PS),直到满足文件结束条件。在文件结束时交换PS用于PS。将PS复制到HS,然后删除除第一个字段后的所有字段,其中第一个字段后跟一个空格全局。删除最后一个空格并打印该行。然后从HS调用该行的副本并执行相反的操作。如果任何替换成功,则重复该过程,直到只有换行符存在。删除不需要的换行符。

自从第一次回答原始问题后发生了变化。下面的新解决方案使用基本相同的方法来迎合新问题:

sed -r '/^[0-9]/{s/ +/ /g;H};//!p;$!d;x;:a;h;s/\n(\S+)[^\n]*/\1 /g;s/ $//p;g;s/\n\S+ ?/\n/g;ta;d' file